system.pp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2005 by Florian Klaempfl and Pavel Ozerski
  4. member of the Free Pascal development team.
  5. FPC Pascal system unit for the Win32 API.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit System;
  13. interface
  14. {$ifdef SYSTEMDEBUG}
  15. {$define SYSTEMEXCEPTIONDEBUG}
  16. {$endif SYSTEMDEBUG}
  17. {$ifdef cpui386}
  18. {$define Set_i386_Exception_handler}
  19. {$endif cpui386}
  20. {$define DISABLE_NO_THREAD_MANAGER}
  21. { include system-independent routine headers }
  22. {$I systemh.inc}
  23. const
  24. LineEnding = #13#10;
  25. LFNSupport = true;
  26. DirectorySeparator = '\';
  27. DriveSeparator = ':';
  28. PathSeparator = ';';
  29. { FileNameCaseSensitive is defined separately below!!! }
  30. maxExitCode = 65535;
  31. MaxPathLen = 260;
  32. AllFilesMask = '*';
  33. type
  34. PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
  35. TEXCEPTION_FRAME = record
  36. next : PEXCEPTION_FRAME;
  37. handler : pointer;
  38. end;
  39. const
  40. { Default filehandles }
  41. UnusedHandle : THandle = -1;
  42. StdInputHandle : THandle = 0;
  43. StdOutputHandle : THandle = 0;
  44. StdErrorHandle : THandle = 0;
  45. FileNameCaseSensitive : boolean = true;
  46. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  47. sLineBreak = LineEnding;
  48. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  49. { Thread count for DLL }
  50. Thread_count : longint = 0;
  51. System_exception_frame : PEXCEPTION_FRAME =nil;
  52. type
  53. TStartupInfo=packed record
  54. cb : longint;
  55. lpReserved : Pointer;
  56. lpDesktop : Pointer;
  57. lpTitle : Pointer;
  58. dwX : longint;
  59. dwY : longint;
  60. dwXSize : longint;
  61. dwYSize : longint;
  62. dwXCountChars : longint;
  63. dwYCountChars : longint;
  64. dwFillAttribute : longint;
  65. dwFlags : longint;
  66. wShowWindow : Word;
  67. cbReserved2 : Word;
  68. lpReserved2 : Pointer;
  69. hStdInput : longint;
  70. hStdOutput : longint;
  71. hStdError : longint;
  72. end;
  73. var
  74. { C compatible arguments }
  75. argc : longint;
  76. argv : ppchar;
  77. { Win32 Info }
  78. startupinfo : tstartupinfo;
  79. hprevinst,
  80. MainInstance,
  81. cmdshow : longint;
  82. DLLreason,DLLparam:longint;
  83. StartupConsoleMode : DWORD;
  84. type
  85. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  86. TDLL_Entry_Hook = procedure (dllparam : longint);
  87. const
  88. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  89. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  90. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  91. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  92. implementation
  93. var
  94. SysInstance : Longint;public name '_FPC_SysInstance';
  95. {$ifdef CPUI386}
  96. {$define HAS_RESOURCES}
  97. {$i winres.inc}
  98. {$endif}
  99. { used by wstrings.inc because wstrings.inc is included before sysos.inc
  100. this is put here (FK) }
  101. function SysAllocStringLen(psz:pointer;len:dword):pointer;stdcall;
  102. external 'oleaut32.dll' name 'SysAllocStringLen';
  103. procedure SysFreeString(bstr:pointer);stdcall;
  104. external 'oleaut32.dll' name 'SysFreeString';
  105. function SysReAllocStringLen(var bstr:pointer;psz: pointer;
  106. len:dword): Integer; stdcall;external 'oleaut32.dll' name 'SysReAllocStringLen';
  107. { include system independent routines }
  108. {$I system.inc}
  109. {*****************************************************************************
  110. Parameter Handling
  111. *****************************************************************************}
  112. var
  113. ModuleName : array[0..255] of char;
  114. function GetCommandFile:pchar;
  115. begin
  116. GetModuleFileName(0,@ModuleName,255);
  117. GetCommandFile:=@ModuleName;
  118. end;
  119. procedure setup_arguments;
  120. var
  121. arglen,
  122. count : longint;
  123. argstart,
  124. pc,arg : pchar;
  125. quote : char;
  126. argvlen : longint;
  127. procedure allocarg(idx,len:longint);
  128. var
  129. oldargvlen : longint;
  130. begin
  131. if idx>=argvlen then
  132. begin
  133. oldargvlen:=argvlen;
  134. argvlen:=(idx+8) and (not 7);
  135. sysreallocmem(argv,argvlen*sizeof(pointer));
  136. fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  137. end;
  138. { use realloc to reuse already existing memory }
  139. { always allocate, even if length is zero, since }
  140. { the arg. is still present! }
  141. sysreallocmem(argv[idx],len+1);
  142. end;
  143. begin
  144. SetupProcVars;
  145. { create commandline, it starts with the executed filename which is argv[0] }
  146. { Win32 passes the command NOT via the args, but via getmodulefilename}
  147. count:=0;
  148. argv:=nil;
  149. argvlen:=0;
  150. pc:=getcommandfile;
  151. Arglen:=0;
  152. repeat
  153. Inc(Arglen);
  154. until (pc[Arglen]=#0);
  155. allocarg(count,arglen);
  156. move(pc^,argv[count]^,arglen+1);
  157. { Setup cmdline variable }
  158. cmdline:=GetCommandLine;
  159. { process arguments }
  160. pc:=cmdline;
  161. {$IfDef SYSTEM_DEBUG_STARTUP}
  162. Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
  163. {$EndIf }
  164. while pc^<>#0 do
  165. begin
  166. { skip leading spaces }
  167. while pc^ in [#1..#32] do
  168. inc(pc);
  169. if pc^=#0 then
  170. break;
  171. { calc argument length }
  172. quote:=' ';
  173. argstart:=pc;
  174. arglen:=0;
  175. while (pc^<>#0) do
  176. begin
  177. case pc^ of
  178. #1..#32 :
  179. begin
  180. if quote<>' ' then
  181. inc(arglen)
  182. else
  183. break;
  184. end;
  185. '"' :
  186. if pchar(pc+1)^<>'"' then
  187. begin
  188. if quote='"' then
  189. quote:=' '
  190. else
  191. quote:='"';
  192. end
  193. else
  194. inc(pc);
  195. else
  196. inc(arglen);
  197. end;
  198. inc(pc);
  199. end;
  200. { copy argument }
  201. { Don't copy the first one, it is already there.}
  202. If Count<>0 then
  203. begin
  204. allocarg(count,arglen);
  205. quote:=' ';
  206. pc:=argstart;
  207. arg:=argv[count];
  208. while (pc^<>#0) do
  209. begin
  210. case pc^ of
  211. #1..#32 :
  212. begin
  213. if quote<>' ' then
  214. begin
  215. arg^:=pc^;
  216. inc(arg);
  217. end
  218. else
  219. break;
  220. end;
  221. '"' :
  222. if pchar(pc+1)^<>'"' then
  223. begin
  224. if quote='"' then
  225. quote:=' '
  226. else
  227. quote:='"';
  228. end
  229. else
  230. inc(pc);
  231. else
  232. begin
  233. arg^:=pc^;
  234. inc(arg);
  235. end;
  236. end;
  237. inc(pc);
  238. end;
  239. arg^:=#0;
  240. end;
  241. {$IfDef SYSTEM_DEBUG_STARTUP}
  242. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  243. {$EndIf SYSTEM_DEBUG_STARTUP}
  244. inc(count);
  245. end;
  246. { get argc and create an nil entry }
  247. argc:=count;
  248. allocarg(argc,0);
  249. { free unused memory }
  250. sysreallocmem(argv,(argc+1)*sizeof(pointer));
  251. end;
  252. function paramcount : longint;
  253. begin
  254. paramcount := argc - 1;
  255. end;
  256. function paramstr(l : longint) : string;
  257. begin
  258. if (l>=0) and (l<argc) then
  259. paramstr:=strpas(argv[l])
  260. else
  261. paramstr:='';
  262. end;
  263. procedure randomize;
  264. begin
  265. randseed:=GetTickCount;
  266. end;
  267. {*****************************************************************************
  268. System Dependent Exit code
  269. *****************************************************************************}
  270. procedure install_exception_handlers;forward;
  271. procedure remove_exception_handlers;forward;
  272. procedure PascalMain;stdcall;external name 'PASCALMAIN';
  273. procedure fpc_do_exit;stdcall;external name 'FPC_DO_EXIT';
  274. Procedure ExitDLL(Exitcode : longint); forward;
  275. procedure asm_exit;stdcall;external name 'asm_exit';
  276. Procedure system_exit;
  277. begin
  278. { don't call ExitProcess inside
  279. the DLL exit code !!
  280. This crashes Win95 at least PM }
  281. if IsLibrary then
  282. ExitDLL(ExitCode);
  283. if not IsConsole then
  284. begin
  285. Close(stderr);
  286. Close(stdout);
  287. Close(erroutput);
  288. Close(Input);
  289. Close(Output);
  290. { what about Input and Output ?? PM }
  291. { now handled, FPK }
  292. end;
  293. remove_exception_handlers;
  294. { in 2.0 asm_exit does an exitprocess }
  295. {$ifndef ver2_0}
  296. { do cleanup required by the startup code }
  297. asm_exit;
  298. {$endif ver2_0}
  299. { call exitprocess, with cleanup as required }
  300. ExitProcess(exitcode);
  301. end;
  302. var
  303. { value of the stack segment
  304. to check if the call stack can be written on exceptions }
  305. _SS : Cardinal;
  306. procedure Exe_entry;[public,alias:'_FPC_EXE_Entry'];
  307. var
  308. ST : pointer;
  309. begin
  310. IsLibrary:=false;
  311. { install the handlers for exe only ?
  312. or should we install them for DLL also ? (PM) }
  313. install_exception_handlers;
  314. { This strange construction is needed to solve the _SS problem
  315. with a smartlinked syswin32 (PFV) }
  316. asm
  317. { allocate space for an exception frame }
  318. pushl $0
  319. pushl %fs:(0)
  320. { movl %esp,%fs:(0)
  321. but don't insert it as it doesn't
  322. point to anything yet
  323. this will be used in signals unit }
  324. movl %esp,%eax
  325. movl %eax,System_exception_frame
  326. pushl %ebp
  327. movl %esp,%eax
  328. movl %eax,st
  329. end;
  330. StackTop:=st;
  331. asm
  332. xorl %eax,%eax
  333. movw %ss,%ax
  334. movl %eax,_SS
  335. call SysResetFPU
  336. xorl %ebp,%ebp
  337. call PASCALMAIN
  338. popl %ebp
  339. end;
  340. { if we pass here there was no error ! }
  341. system_exit;
  342. end;
  343. Const
  344. { DllEntryPoint }
  345. DLL_PROCESS_ATTACH = 1;
  346. DLL_THREAD_ATTACH = 2;
  347. DLL_PROCESS_DETACH = 0;
  348. DLL_THREAD_DETACH = 3;
  349. Var
  350. DLLBuf : Jmp_buf;
  351. Const
  352. DLLExitOK : boolean = true;
  353. function Dll_entry : longbool; [public,alias:'_FPC_DLL_Entry'];
  354. var
  355. res : longbool;
  356. begin
  357. IsLibrary:=true;
  358. Dll_entry:=false;
  359. case DLLreason of
  360. DLL_PROCESS_ATTACH :
  361. begin
  362. If SetJmp(DLLBuf) = 0 then
  363. begin
  364. if assigned(Dll_Process_Attach_Hook) then
  365. begin
  366. res:=Dll_Process_Attach_Hook(DllParam);
  367. if not res then
  368. exit(false);
  369. end;
  370. PASCALMAIN;
  371. Dll_entry:=true;
  372. end
  373. else
  374. Dll_entry:=DLLExitOK;
  375. end;
  376. DLL_THREAD_ATTACH :
  377. begin
  378. inclocked(Thread_count);
  379. {$warning Allocate Threadvars !}
  380. if assigned(Dll_Thread_Attach_Hook) then
  381. Dll_Thread_Attach_Hook(DllParam);
  382. Dll_entry:=true; { return value is ignored }
  383. end;
  384. DLL_THREAD_DETACH :
  385. begin
  386. declocked(Thread_count);
  387. if assigned(Dll_Thread_Detach_Hook) then
  388. Dll_Thread_Detach_Hook(DllParam);
  389. {$warning Release Threadvars !}
  390. Dll_entry:=true; { return value is ignored }
  391. end;
  392. DLL_PROCESS_DETACH :
  393. begin
  394. Dll_entry:=true; { return value is ignored }
  395. If SetJmp(DLLBuf) = 0 then
  396. FPC_Do_Exit;
  397. if assigned(Dll_Process_Detach_Hook) then
  398. Dll_Process_Detach_Hook(DllParam);
  399. end;
  400. end;
  401. end;
  402. Procedure ExitDLL(Exitcode : longint);
  403. begin
  404. DLLExitOK:=ExitCode=0;
  405. LongJmp(DLLBuf,1);
  406. end;
  407. function GetCurrentProcess : dword;
  408. stdcall;external 'kernel32' name 'GetCurrentProcess';
  409. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  410. stdcall;external 'kernel32' name 'ReadProcessMemory';
  411. function is_prefetch(p : pointer) : boolean;
  412. var
  413. a : array[0..15] of byte;
  414. doagain : boolean;
  415. instrlo,instrhi,opcode : byte;
  416. i : longint;
  417. begin
  418. result:=false;
  419. { read memory savely without causing another exeception }
  420. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  421. exit;
  422. i:=0;
  423. doagain:=true;
  424. while doagain and (i<15) do
  425. begin
  426. opcode:=a[i];
  427. instrlo:=opcode and $f;
  428. instrhi:=opcode and $f0;
  429. case instrhi of
  430. { prefix? }
  431. $20,$30:
  432. doagain:=(instrlo and 7)=6;
  433. $60:
  434. doagain:=(instrlo and $c)=4;
  435. $f0:
  436. doagain:=instrlo in [0,2,3];
  437. $0:
  438. begin
  439. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  440. exit;
  441. end;
  442. else
  443. doagain:=false;
  444. end;
  445. inc(i);
  446. end;
  447. end;
  448. //
  449. // Hardware exception handling
  450. //
  451. {$ifdef Set_i386_Exception_handler}
  452. {
  453. Error code definitions for the Win32 API functions
  454. Values are 32 bit values layed out as follows:
  455. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  456. 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
  457. +---+-+-+-----------------------+-------------------------------+
  458. |Sev|C|R| Facility | Code |
  459. +---+-+-+-----------------------+-------------------------------+
  460. where
  461. Sev - is the severity code
  462. 00 - Success
  463. 01 - Informational
  464. 10 - Warning
  465. 11 - Error
  466. C - is the Customer code flag
  467. R - is a reserved bit
  468. Facility - is the facility code
  469. Code - is the facility's status code
  470. }
  471. const
  472. SEVERITY_SUCCESS = $00000000;
  473. SEVERITY_INFORMATIONAL = $40000000;
  474. SEVERITY_WARNING = $80000000;
  475. SEVERITY_ERROR = $C0000000;
  476. const
  477. STATUS_SEGMENT_NOTIFICATION = $40000005;
  478. DBG_TERMINATE_THREAD = $40010003;
  479. DBG_TERMINATE_PROCESS = $40010004;
  480. DBG_CONTROL_C = $40010005;
  481. DBG_CONTROL_BREAK = $40010008;
  482. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  483. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  484. STATUS_BREAKPOINT = $80000003;
  485. STATUS_SINGLE_STEP = $80000004;
  486. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  487. STATUS_ACCESS_VIOLATION = $C0000005;
  488. STATUS_IN_PAGE_ERROR = $C0000006;
  489. STATUS_INVALID_HANDLE = $C0000008;
  490. STATUS_NO_MEMORY = $C0000017;
  491. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  492. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  493. STATUS_INVALID_DISPOSITION = $C0000026;
  494. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  495. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  496. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  497. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  498. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  499. STATUS_FLOAT_OVERFLOW = $C0000091;
  500. STATUS_FLOAT_STACK_CHECK = $C0000092;
  501. STATUS_FLOAT_UNDERFLOW = $C0000093;
  502. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  503. STATUS_INTEGER_OVERFLOW = $C0000095;
  504. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  505. STATUS_STACK_OVERFLOW = $C00000FD;
  506. STATUS_CONTROL_C_EXIT = $C000013A;
  507. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  508. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  509. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  510. EXCEPTION_EXECUTE_HANDLER = 1;
  511. EXCEPTION_CONTINUE_EXECUTION = -1;
  512. EXCEPTION_CONTINUE_SEARCH = 0;
  513. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  514. CONTEXT_X86 = $00010000;
  515. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  516. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  517. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  518. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  519. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  520. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  521. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  522. MAXIMUM_SUPPORTED_EXTENSION = 512;
  523. type
  524. PFloatingSaveArea = ^TFloatingSaveArea;
  525. TFloatingSaveArea = packed record
  526. ControlWord : Cardinal;
  527. StatusWord : Cardinal;
  528. TagWord : Cardinal;
  529. ErrorOffset : Cardinal;
  530. ErrorSelector : Cardinal;
  531. DataOffset : Cardinal;
  532. DataSelector : Cardinal;
  533. RegisterArea : array[0..79] of Byte;
  534. Cr0NpxState : Cardinal;
  535. end;
  536. PContext = ^TContext;
  537. TContext = packed record
  538. //
  539. // The flags values within this flag control the contents of
  540. // a CONTEXT record.
  541. //
  542. ContextFlags : Cardinal;
  543. //
  544. // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
  545. // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
  546. // included in CONTEXT_FULL.
  547. //
  548. Dr0, Dr1, Dr2,
  549. Dr3, Dr6, Dr7 : Cardinal;
  550. //
  551. // This section is specified/returned if the
  552. // ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
  553. //
  554. FloatSave : TFloatingSaveArea;
  555. //
  556. // This section is specified/returned if the
  557. // ContextFlags word contains the flag CONTEXT_SEGMENTS.
  558. //
  559. SegGs, SegFs,
  560. SegEs, SegDs : Cardinal;
  561. //
  562. // This section is specified/returned if the
  563. // ContextFlags word contains the flag CONTEXT_INTEGER.
  564. //
  565. Edi, Esi, Ebx,
  566. Edx, Ecx, Eax : Cardinal;
  567. //
  568. // This section is specified/returned if the
  569. // ContextFlags word contains the flag CONTEXT_CONTROL.
  570. //
  571. Ebp : Cardinal;
  572. Eip : Cardinal;
  573. SegCs : Cardinal;
  574. EFlags, Esp, SegSs : Cardinal;
  575. //
  576. // This section is specified/returned if the ContextFlags word
  577. // contains the flag CONTEXT_EXTENDED_REGISTERS.
  578. // The format and contexts are processor specific
  579. //
  580. ExtendedRegisters : array[0..MAXIMUM_SUPPORTED_EXTENSION-1] of Byte;
  581. end;
  582. type
  583. PExceptionRecord = ^TExceptionRecord;
  584. TExceptionRecord = packed record
  585. ExceptionCode : cardinal;
  586. ExceptionFlags : Longint;
  587. ExceptionRecord : PExceptionRecord;
  588. ExceptionAddress : Pointer;
  589. NumberParameters : Longint;
  590. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
  591. end;
  592. PExceptionPointers = ^TExceptionPointers;
  593. TExceptionPointers = packed record
  594. ExceptionRecord : PExceptionRecord;
  595. ContextRecord : PContext;
  596. end;
  597. { type of functions that should be used for exception handling }
  598. TTopLevelExceptionFilter = function (excep : PExceptionPointers) : Longint;stdcall;
  599. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : TTopLevelExceptionFilter) : TTopLevelExceptionFilter;
  600. stdcall;external 'kernel32' name 'SetUnhandledExceptionFilter';
  601. const
  602. MaxExceptionLevel = 16;
  603. exceptLevel : Byte = 0;
  604. var
  605. exceptEip : array[0..MaxExceptionLevel-1] of Longint;
  606. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  607. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  608. {$ifdef SYSTEMEXCEPTIONDEBUG}
  609. procedure DebugHandleErrorAddrFrame(error, addr, frame : longint);
  610. begin
  611. if IsConsole then
  612. begin
  613. write(stderr,'HandleErrorAddrFrame(error=',error);
  614. write(stderr,',addr=',hexstr(addr,8));
  615. writeln(stderr,',frame=',hexstr(frame,8),')');
  616. end;
  617. HandleErrorAddrFrame(error,addr,frame);
  618. end;
  619. {$endif SYSTEMEXCEPTIONDEBUG}
  620. procedure JumpToHandleErrorFrame;
  621. var
  622. eip, ebp, error : Longint;
  623. begin
  624. // save ebp
  625. asm
  626. movl (%ebp),%eax
  627. movl %eax,ebp
  628. end;
  629. if (exceptLevel > 0) then
  630. dec(exceptLevel);
  631. eip:=exceptEip[exceptLevel];
  632. error:=exceptError[exceptLevel];
  633. {$ifdef SYSTEMEXCEPTIONDEBUG}
  634. if IsConsole then
  635. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  636. {$endif SYSTEMEXCEPTIONDEBUG}
  637. if resetFPU[exceptLevel] then
  638. SysResetFPU;
  639. { build a fake stack }
  640. asm
  641. {$ifdef REGCALL}
  642. movl ebp,%ecx
  643. movl eip,%edx
  644. movl error,%eax
  645. pushl eip
  646. movl ebp,%ebp // Change frame pointer
  647. {$else}
  648. movl ebp,%eax
  649. pushl %eax
  650. movl eip,%eax
  651. pushl %eax
  652. movl error,%eax
  653. pushl %eax
  654. movl eip,%eax
  655. pushl %eax
  656. movl ebp,%ebp // Change frame pointer
  657. {$endif}
  658. {$ifdef SYSTEMEXCEPTIONDEBUG}
  659. jmpl DebugHandleErrorAddrFrame
  660. {$else not SYSTEMEXCEPTIONDEBUG}
  661. jmpl HandleErrorAddrFrame
  662. {$endif SYSTEMEXCEPTIONDEBUG}
  663. end;
  664. end;
  665. function syswin32_i386_exception_handler(excep : PExceptionPointers) : Longint;stdcall;
  666. var
  667. res: longint;
  668. err: byte;
  669. must_reset_fpu: boolean;
  670. begin
  671. res := EXCEPTION_CONTINUE_SEARCH;
  672. if excep^.ContextRecord^.SegSs=_SS then begin
  673. err := 0;
  674. must_reset_fpu := true;
  675. {$ifdef SYSTEMEXCEPTIONDEBUG}
  676. if IsConsole then Writeln(stderr,'Exception ',
  677. hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
  678. {$endif SYSTEMEXCEPTIONDEBUG}
  679. case excep^.ExceptionRecord^.ExceptionCode of
  680. STATUS_INTEGER_DIVIDE_BY_ZERO,
  681. STATUS_FLOAT_DIVIDE_BY_ZERO :
  682. err := 200;
  683. STATUS_ARRAY_BOUNDS_EXCEEDED :
  684. begin
  685. err := 201;
  686. must_reset_fpu := false;
  687. end;
  688. STATUS_STACK_OVERFLOW :
  689. begin
  690. err := 202;
  691. must_reset_fpu := false;
  692. end;
  693. STATUS_FLOAT_OVERFLOW :
  694. err := 205;
  695. STATUS_FLOAT_DENORMAL_OPERAND,
  696. STATUS_FLOAT_UNDERFLOW :
  697. err := 206;
  698. {excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  699. STATUS_FLOAT_INEXACT_RESULT,
  700. STATUS_FLOAT_INVALID_OPERATION,
  701. STATUS_FLOAT_STACK_CHECK :
  702. err := 207;
  703. STATUS_INTEGER_OVERFLOW :
  704. begin
  705. err := 215;
  706. must_reset_fpu := false;
  707. end;
  708. STATUS_ILLEGAL_INSTRUCTION:
  709. { if we're testing sse support, simply set the flag and continue }
  710. if sse_check then
  711. begin
  712. os_supports_sse:=false;
  713. { skip the offending movaps %xmm7, %xmm6 instruction }
  714. inc(excep^.ContextRecord^.Eip,3);
  715. excep^.ExceptionRecord^.ExceptionCode := 0;
  716. res:=EXCEPTION_CONTINUE_EXECUTION;
  717. end
  718. else
  719. err := 216;
  720. STATUS_ACCESS_VIOLATION:
  721. { Athlon prefetch bug? }
  722. if is_prefetch(pointer(excep^.ContextRecord^.Eip)) then
  723. begin
  724. { if yes, then retry }
  725. excep^.ExceptionRecord^.ExceptionCode := 0;
  726. res:=EXCEPTION_CONTINUE_EXECUTION;
  727. end
  728. else
  729. err := 216;
  730. STATUS_CONTROL_C_EXIT:
  731. err := 217;
  732. STATUS_PRIVILEGED_INSTRUCTION:
  733. begin
  734. err := 218;
  735. must_reset_fpu := false;
  736. end;
  737. else
  738. begin
  739. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  740. err := 217
  741. else
  742. err := 255;
  743. end;
  744. end;
  745. if (err <> 0) and (exceptLevel < MaxExceptionLevel) then begin
  746. exceptEip[exceptLevel] := excep^.ContextRecord^.Eip;
  747. exceptError[exceptLevel] := err;
  748. resetFPU[exceptLevel] := must_reset_fpu;
  749. inc(exceptLevel);
  750. excep^.ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
  751. excep^.ExceptionRecord^.ExceptionCode := 0;
  752. res := EXCEPTION_CONTINUE_EXECUTION;
  753. {$ifdef SYSTEMEXCEPTIONDEBUG}
  754. if IsConsole then begin
  755. writeln(stderr,'Exception Continue Exception set at ',
  756. hexstr(exceptEip[exceptLevel],8));
  757. writeln(stderr,'Eip changed to ',
  758. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  759. end;
  760. {$endif SYSTEMEXCEPTIONDEBUG}
  761. end;
  762. end;
  763. syswin32_i386_exception_handler := res;
  764. end;
  765. procedure install_exception_handlers;
  766. {$ifdef SYSTEMEXCEPTIONDEBUG}
  767. var
  768. oldexceptaddr,
  769. newexceptaddr : Longint;
  770. {$endif SYSTEMEXCEPTIONDEBUG}
  771. begin
  772. {$ifdef SYSTEMEXCEPTIONDEBUG}
  773. asm
  774. movl $0,%eax
  775. movl %fs:(%eax),%eax
  776. movl %eax,oldexceptaddr
  777. end;
  778. {$endif SYSTEMEXCEPTIONDEBUG}
  779. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  780. {$ifdef SYSTEMEXCEPTIONDEBUG}
  781. asm
  782. movl $0,%eax
  783. movl %fs:(%eax),%eax
  784. movl %eax,newexceptaddr
  785. end;
  786. if IsConsole then
  787. writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
  788. ' new exception ',hexstr(newexceptaddr,8));
  789. {$endif SYSTEMEXCEPTIONDEBUG}
  790. end;
  791. procedure remove_exception_handlers;
  792. begin
  793. SetUnhandledExceptionFilter(nil);
  794. end;
  795. {$else not cpui386 (Processor specific !!)}
  796. procedure install_exception_handlers;
  797. begin
  798. end;
  799. procedure remove_exception_handlers;
  800. begin
  801. end;
  802. {$endif Set_i386_Exception_handler}
  803. {****************************************************************************
  804. OS dependend widestrings
  805. ****************************************************************************}
  806. const
  807. { MultiByteToWideChar }
  808. MB_PRECOMPOSED = 1;
  809. CP_ACP = 0;
  810. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  811. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  812. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  813. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  814. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  815. stdcall; external 'user32' name 'CharUpperBuffW';
  816. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  817. stdcall; external 'user32' name 'CharLowerBuffW';
  818. procedure Win32Wide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt);
  819. var
  820. destlen: SizeInt;
  821. begin
  822. // retrieve length including trailing #0
  823. // not anymore, because this must also be usable for single characters
  824. destlen:=WideCharToMultiByte(CP_ACP, 0, source, len, nil, 0, nil, nil);
  825. // this will null-terminate
  826. setlength(dest, destlen);
  827. WideCharToMultiByte(CP_ACP, 0, source, len, @dest[1], destlen, nil, nil);
  828. end;
  829. procedure Win32Ansi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
  830. var
  831. destlen: SizeInt;
  832. begin
  833. // retrieve length including trailing #0
  834. // not anymore, because this must also be usable for single characters
  835. destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, nil, 0);
  836. // this will null-terminate
  837. setlength(dest, destlen);
  838. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, @dest[1], destlen);
  839. end;
  840. function Win32WideUpper(const s : WideString) : WideString;
  841. begin
  842. result:=s;
  843. UniqueString(result);
  844. if length(result)>0 then
  845. CharUpperBuff(LPWSTR(result),length(result));
  846. end;
  847. function Win32WideLower(const s : WideString) : WideString;
  848. begin
  849. result:=s;
  850. UniqueString(result);
  851. if length(result)>0 then
  852. CharLowerBuff(LPWSTR(result),length(result));
  853. end;
  854. { there is a similiar procedure in sysutils which inits the fields which
  855. are only relevant for the sysutils units }
  856. procedure InitWin32Widestrings;
  857. begin
  858. widestringmanager.Wide2AnsiMoveProc:=@Win32Wide2AnsiMove;
  859. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  860. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  861. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  862. end;
  863. {****************************************************************************
  864. Error Message writing using messageboxes
  865. ****************************************************************************}
  866. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  867. stdcall;external 'user32' name 'MessageBoxA';
  868. const
  869. ErrorBufferLength = 1024;
  870. var
  871. ErrorBuf : array[0..ErrorBufferLength] of char;
  872. ErrorLen : longint;
  873. Function ErrorWrite(Var F: TextRec): Integer;
  874. {
  875. An error message should always end with #13#10#13#10
  876. }
  877. var
  878. p : pchar;
  879. i : longint;
  880. Begin
  881. if F.BufPos>0 then
  882. begin
  883. if F.BufPos+ErrorLen>ErrorBufferLength then
  884. i:=ErrorBufferLength-ErrorLen
  885. else
  886. i:=F.BufPos;
  887. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  888. inc(ErrorLen,i);
  889. ErrorBuf[ErrorLen]:=#0;
  890. end;
  891. if ErrorLen>3 then
  892. begin
  893. p:=@ErrorBuf[ErrorLen];
  894. for i:=1 to 4 do
  895. begin
  896. dec(p);
  897. if not(p^ in [#10,#13]) then
  898. break;
  899. end;
  900. end;
  901. if ErrorLen=ErrorBufferLength then
  902. i:=4;
  903. if (i=4) then
  904. begin
  905. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  906. ErrorLen:=0;
  907. end;
  908. F.BufPos:=0;
  909. ErrorWrite:=0;
  910. End;
  911. Function ErrorClose(Var F: TextRec): Integer;
  912. begin
  913. if ErrorLen>0 then
  914. begin
  915. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  916. ErrorLen:=0;
  917. end;
  918. ErrorLen:=0;
  919. ErrorClose:=0;
  920. end;
  921. Function ErrorOpen(Var F: TextRec): Integer;
  922. Begin
  923. TextRec(F).InOutFunc:=@ErrorWrite;
  924. TextRec(F).FlushFunc:=@ErrorWrite;
  925. TextRec(F).CloseFunc:=@ErrorClose;
  926. ErrorOpen:=0;
  927. End;
  928. procedure AssignError(Var T: Text);
  929. begin
  930. Assign(T,'');
  931. TextRec(T).OpenFunc:=@ErrorOpen;
  932. Rewrite(T);
  933. end;
  934. procedure SysInitStdIO;
  935. begin
  936. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  937. displayed in a messagebox }
  938. StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  939. StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  940. StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  941. if not IsConsole then
  942. begin
  943. AssignError(stderr);
  944. AssignError(stdout);
  945. Assign(Output,'');
  946. Assign(Input,'');
  947. Assign(ErrOutput,'');
  948. end
  949. else
  950. begin
  951. OpenStdIO(Input,fmInput,StdInputHandle);
  952. OpenStdIO(Output,fmOutput,StdOutputHandle);
  953. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  954. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  955. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  956. end;
  957. end;
  958. (* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
  959. var
  960. ProcessID: SizeUInt;
  961. function GetProcessID: SizeUInt;
  962. begin
  963. GetProcessID := ProcessID;
  964. end;
  965. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  966. begin
  967. result := stklen;
  968. end;
  969. {
  970. const
  971. Exe_entry_code : pointer = @Exe_entry;
  972. Dll_entry_code : pointer = @Dll_entry;
  973. }
  974. begin
  975. StackLength := CheckInitialStkLen(InitialStkLen);
  976. StackBottom := StackTop - StackLength;
  977. { get some helpful informations }
  978. GetStartupInfo(@startupinfo);
  979. { some misc Win32 stuff }
  980. hprevinst:=0;
  981. if not IsLibrary then
  982. SysInstance:=getmodulehandle(GetCommandFile);
  983. MainInstance:=HInstance;
  984. cmdshow:=startupinfo.wshowwindow;
  985. { Setup heap }
  986. InitHeap;
  987. SysInitExceptions;
  988. { setup fastmove stuff }
  989. fpc_cpucodeinit;
  990. SysInitStdIO;
  991. { Arguments }
  992. setup_arguments;
  993. { Reset IO Error }
  994. InOutRes:=0;
  995. ProcessID := GetCurrentProcessID;
  996. { threading }
  997. InitSystemThreads;
  998. { Reset internal error variable }
  999. errno:=0;
  1000. initvariantmanager;
  1001. initwidestringmanager;
  1002. InitWin32Widestrings;
  1003. DispCallByIDProc:=@DoDispCallByIDError;
  1004. end.