system.pp 31 KB

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