system.pp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  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. { allocate space for an exception frame }
  347. pushl $0
  348. pushl %fs:(0)
  349. { movl %esp,%fs:(0)
  350. but don't insert it as it doesn't
  351. point to anything yet
  352. this will be used in signals unit }
  353. movl %esp,%eax
  354. movl %eax,System_exception_frame
  355. pushl %ebp
  356. xorl %ebp,%ebp
  357. movl %esp,%eax
  358. movl %eax,Win32StackTop
  359. movw %ss,%bp
  360. movl %ebp,_SS
  361. call SysResetFPU
  362. xorl %ebp,%ebp
  363. call PASCALMAIN
  364. popl %ebp
  365. end;
  366. { if we pass here there was no error ! }
  367. system_exit;
  368. end;
  369. Const
  370. { DllEntryPoint }
  371. DLL_PROCESS_ATTACH = 1;
  372. DLL_THREAD_ATTACH = 2;
  373. DLL_PROCESS_DETACH = 0;
  374. DLL_THREAD_DETACH = 3;
  375. Var
  376. DLLBuf : Jmp_buf;
  377. Const
  378. DLLExitOK : boolean = true;
  379. function Dll_entry : longbool;[public, alias : '_FPC_DLL_Entry'];
  380. var
  381. res : longbool;
  382. begin
  383. IsLibrary:=true;
  384. Dll_entry:=false;
  385. case DLLreason of
  386. DLL_PROCESS_ATTACH :
  387. begin
  388. If SetJmp(DLLBuf) = 0 then
  389. begin
  390. if assigned(Dll_Process_Attach_Hook) then
  391. begin
  392. res:=Dll_Process_Attach_Hook(DllParam);
  393. if not res then
  394. exit(false);
  395. end;
  396. PASCALMAIN;
  397. Dll_entry:=true;
  398. end
  399. else
  400. Dll_entry:=DLLExitOK;
  401. end;
  402. DLL_THREAD_ATTACH :
  403. begin
  404. inc(Thread_count);
  405. {$warning Allocate Threadvars !}
  406. if assigned(Dll_Thread_Attach_Hook) then
  407. Dll_Thread_Attach_Hook(DllParam);
  408. Dll_entry:=true; { return value is ignored }
  409. end;
  410. DLL_THREAD_DETACH :
  411. begin
  412. dec(Thread_count);
  413. if assigned(Dll_Thread_Detach_Hook) then
  414. Dll_Thread_Detach_Hook(DllParam);
  415. {$warning Release Threadvars !}
  416. Dll_entry:=true; { return value is ignored }
  417. end;
  418. DLL_PROCESS_DETACH :
  419. begin
  420. Dll_entry:=true; { return value is ignored }
  421. If SetJmp(DLLBuf) = 0 then
  422. begin
  423. FPC_DO_EXIT;
  424. end;
  425. if assigned(Dll_Process_Detach_Hook) then
  426. Dll_Process_Detach_Hook(DllParam);
  427. end;
  428. end;
  429. end;
  430. Procedure ExitDLL(Exitcode : longint);
  431. begin
  432. DLLExitOK:=ExitCode=0;
  433. LongJmp(DLLBuf,1);
  434. end;
  435. function GetCurrentProcess : dword;
  436. stdcall;external 'kernel32' name 'GetCurrentProcess';
  437. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  438. stdcall;external 'kernel32' name 'ReadProcessMemory';
  439. function is_prefetch(p : pointer) : boolean;
  440. var
  441. a : array[0..15] of byte;
  442. doagain : boolean;
  443. instrlo,instrhi,opcode : byte;
  444. i : longint;
  445. begin
  446. result:=false;
  447. { read memory savely without causing another exeception }
  448. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  449. exit;
  450. i:=0;
  451. doagain:=true;
  452. while doagain and (i<15) do
  453. begin
  454. opcode:=a[i];
  455. instrlo:=opcode and $f;
  456. instrhi:=opcode and $f0;
  457. case instrhi of
  458. { prefix? }
  459. $20,$30:
  460. doagain:=(instrlo and 7)=6;
  461. $60:
  462. doagain:=(instrlo and $c)=4;
  463. $f0:
  464. doagain:=instrlo in [0,2,3];
  465. $0:
  466. begin
  467. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  468. exit;
  469. end;
  470. else
  471. doagain:=false;
  472. end;
  473. inc(i);
  474. end;
  475. end;
  476. //
  477. // Hardware exception handling
  478. //
  479. {$ifdef Set_i386_Exception_handler}
  480. {
  481. Error code definitions for the Win32 API functions
  482. Values are 32 bit values layed out as follows:
  483. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  484. 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
  485. +---+-+-+-----------------------+-------------------------------+
  486. |Sev|C|R| Facility | Code |
  487. +---+-+-+-----------------------+-------------------------------+
  488. where
  489. Sev - is the severity code
  490. 00 - Success
  491. 01 - Informational
  492. 10 - Warning
  493. 11 - Error
  494. C - is the Customer code flag
  495. R - is a reserved bit
  496. Facility - is the facility code
  497. Code - is the facility's status code
  498. }
  499. const
  500. SEVERITY_SUCCESS = $00000000;
  501. SEVERITY_INFORMATIONAL = $40000000;
  502. SEVERITY_WARNING = $80000000;
  503. SEVERITY_ERROR = $C0000000;
  504. const
  505. STATUS_SEGMENT_NOTIFICATION = $40000005;
  506. DBG_TERMINATE_THREAD = $40010003;
  507. DBG_TERMINATE_PROCESS = $40010004;
  508. DBG_CONTROL_C = $40010005;
  509. DBG_CONTROL_BREAK = $40010008;
  510. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  511. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  512. STATUS_BREAKPOINT = $80000003;
  513. STATUS_SINGLE_STEP = $80000004;
  514. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  515. STATUS_ACCESS_VIOLATION = $C0000005;
  516. STATUS_IN_PAGE_ERROR = $C0000006;
  517. STATUS_INVALID_HANDLE = $C0000008;
  518. STATUS_NO_MEMORY = $C0000017;
  519. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  520. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  521. STATUS_INVALID_DISPOSITION = $C0000026;
  522. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  523. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  524. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  525. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  526. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  527. STATUS_FLOAT_OVERFLOW = $C0000091;
  528. STATUS_FLOAT_STACK_CHECK = $C0000092;
  529. STATUS_FLOAT_UNDERFLOW = $C0000093;
  530. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  531. STATUS_INTEGER_OVERFLOW = $C0000095;
  532. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  533. STATUS_STACK_OVERFLOW = $C00000FD;
  534. STATUS_CONTROL_C_EXIT = $C000013A;
  535. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  536. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  537. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  538. EXCEPTION_EXECUTE_HANDLER = 1;
  539. EXCEPTION_CONTINUE_EXECUTION = -1;
  540. EXCEPTION_CONTINUE_SEARCH = 0;
  541. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  542. CONTEXT_X86 = $00010000;
  543. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  544. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  545. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  546. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  547. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  548. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  549. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  550. MAXIMUM_SUPPORTED_EXTENSION = 512;
  551. type
  552. PFloatingSaveArea = ^TFloatingSaveArea;
  553. TFloatingSaveArea = packed record
  554. ControlWord : Cardinal;
  555. StatusWord : Cardinal;
  556. TagWord : Cardinal;
  557. ErrorOffset : Cardinal;
  558. ErrorSelector : Cardinal;
  559. DataOffset : Cardinal;
  560. DataSelector : Cardinal;
  561. RegisterArea : array[0..79] of Byte;
  562. Cr0NpxState : Cardinal;
  563. end;
  564. PContext = ^TContext;
  565. TContext = packed record
  566. //
  567. // The flags values within this flag control the contents of
  568. // a CONTEXT record.
  569. //
  570. ContextFlags : Cardinal;
  571. //
  572. // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
  573. // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
  574. // included in CONTEXT_FULL.
  575. //
  576. Dr0, Dr1, Dr2,
  577. Dr3, Dr6, Dr7 : Cardinal;
  578. //
  579. // This section is specified/returned if the
  580. // ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
  581. //
  582. FloatSave : TFloatingSaveArea;
  583. //
  584. // This section is specified/returned if the
  585. // ContextFlags word contains the flag CONTEXT_SEGMENTS.
  586. //
  587. SegGs, SegFs,
  588. SegEs, SegDs : Cardinal;
  589. //
  590. // This section is specified/returned if the
  591. // ContextFlags word contains the flag CONTEXT_INTEGER.
  592. //
  593. Edi, Esi, Ebx,
  594. Edx, Ecx, Eax : Cardinal;
  595. //
  596. // This section is specified/returned if the
  597. // ContextFlags word contains the flag CONTEXT_CONTROL.
  598. //
  599. Ebp : Cardinal;
  600. Eip : Cardinal;
  601. SegCs : Cardinal;
  602. EFlags, Esp, SegSs : Cardinal;
  603. //
  604. // This section is specified/returned if the ContextFlags word
  605. // contains the flag CONTEXT_EXTENDED_REGISTERS.
  606. // The format and contexts are processor specific
  607. //
  608. ExtendedRegisters : array[0..MAXIMUM_SUPPORTED_EXTENSION-1] of Byte;
  609. end;
  610. type
  611. PExceptionRecord = ^TExceptionRecord;
  612. TExceptionRecord = packed record
  613. ExceptionCode : Longint;
  614. ExceptionFlags : Longint;
  615. ExceptionRecord : PExceptionRecord;
  616. ExceptionAddress : Pointer;
  617. NumberParameters : Longint;
  618. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
  619. end;
  620. PExceptionPointers = ^TExceptionPointers;
  621. TExceptionPointers = packed record
  622. ExceptionRecord : PExceptionRecord;
  623. ContextRecord : PContext;
  624. end;
  625. { type of functions that should be used for exception handling }
  626. TTopLevelExceptionFilter = function (excep : PExceptionPointers) : Longint;stdcall;
  627. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : TTopLevelExceptionFilter) : TTopLevelExceptionFilter;
  628. stdcall;external 'kernel32' name 'SetUnhandledExceptionFilter';
  629. const
  630. MaxExceptionLevel = 16;
  631. exceptLevel : Byte = 0;
  632. var
  633. exceptEip : array[0..MaxExceptionLevel-1] of Longint;
  634. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  635. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  636. {$ifdef SYSTEMEXCEPTIONDEBUG}
  637. procedure DebugHandleErrorAddrFrame(error, addr, frame : longint);
  638. begin
  639. if IsConsole then
  640. begin
  641. write(stderr,'HandleErrorAddrFrame(error=',error);
  642. write(stderr,',addr=',hexstr(addr,8));
  643. writeln(stderr,',frame=',hexstr(frame,8),')');
  644. end;
  645. HandleErrorAddrFrame(error,addr,frame);
  646. end;
  647. {$endif SYSTEMEXCEPTIONDEBUG}
  648. procedure JumpToHandleErrorFrame;
  649. var
  650. eip, ebp, error : Longint;
  651. begin
  652. // save ebp
  653. asm
  654. movl (%ebp),%eax
  655. movl %eax,ebp
  656. end;
  657. if (exceptLevel > 0) then
  658. dec(exceptLevel);
  659. eip:=exceptEip[exceptLevel];
  660. error:=exceptError[exceptLevel];
  661. {$ifdef SYSTEMEXCEPTIONDEBUG}
  662. if IsConsole then
  663. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  664. {$endif SYSTEMEXCEPTIONDEBUG}
  665. if resetFPU[exceptLevel] then asm
  666. fninit
  667. fldcw fpucw
  668. end;
  669. { build a fake stack }
  670. asm
  671. {$ifdef REGCALL}
  672. movl ebp,%ecx
  673. movl eip,%edx
  674. movl error,%eax
  675. pushl eip
  676. movl ebp,%ebp // Change frame pointer
  677. {$else}
  678. movl ebp,%eax
  679. pushl %eax
  680. movl eip,%eax
  681. pushl %eax
  682. movl error,%eax
  683. pushl %eax
  684. movl eip,%eax
  685. pushl %eax
  686. movl ebp,%ebp // Change frame pointer
  687. {$endif}
  688. {$ifdef SYSTEMEXCEPTIONDEBUG}
  689. jmpl DebugHandleErrorAddrFrame
  690. {$else not SYSTEMEXCEPTIONDEBUG}
  691. jmpl HandleErrorAddrFrame
  692. {$endif SYSTEMEXCEPTIONDEBUG}
  693. end;
  694. end;
  695. function syswin32_i386_exception_handler(excep : PExceptionPointers) : Longint;stdcall;
  696. var
  697. frame,
  698. res : longint;
  699. function SysHandleErrorFrame(error, frame : Longint; must_reset_fpu : Boolean) : Longint;
  700. begin
  701. if (frame = 0) then
  702. SysHandleErrorFrame:=EXCEPTION_CONTINUE_SEARCH
  703. else begin
  704. if (exceptLevel >= MaxExceptionLevel) then exit;
  705. exceptEip[exceptLevel] := excep^.ContextRecord^.Eip;
  706. exceptError[exceptLevel] := error;
  707. resetFPU[exceptLevel] := must_reset_fpu;
  708. inc(exceptLevel);
  709. excep^.ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
  710. excep^.ExceptionRecord^.ExceptionCode := 0;
  711. SysHandleErrorFrame := EXCEPTION_CONTINUE_EXECUTION;
  712. {$ifdef SYSTEMEXCEPTIONDEBUG}
  713. if IsConsole then begin
  714. writeln(stderr,'Exception Continue Exception set at ',
  715. hexstr(exceptEip[exceptLevel],8));
  716. writeln(stderr,'Eip changed to ',
  717. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  718. end;
  719. {$endif SYSTEMEXCEPTIONDEBUG}
  720. end;
  721. end;
  722. begin
  723. if excep^.ContextRecord^.SegSs=_SS then
  724. frame := excep^.ContextRecord^.Ebp
  725. else
  726. frame := 0;
  727. res := EXCEPTION_CONTINUE_SEARCH;
  728. {$ifdef SYSTEMEXCEPTIONDEBUG}
  729. if IsConsole then Writeln(stderr,'Exception ',
  730. hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
  731. {$endif SYSTEMEXCEPTIONDEBUG}
  732. case cardinal(excep^.ExceptionRecord^.ExceptionCode) of
  733. STATUS_INTEGER_DIVIDE_BY_ZERO,
  734. STATUS_FLOAT_DIVIDE_BY_ZERO :
  735. res := SysHandleErrorFrame(200, frame, true);
  736. STATUS_ARRAY_BOUNDS_EXCEEDED :
  737. res := SysHandleErrorFrame(201, frame, false);
  738. STATUS_STACK_OVERFLOW :
  739. res := SysHandleErrorFrame(202, frame, false);
  740. STATUS_FLOAT_OVERFLOW :
  741. res := SysHandleErrorFrame(205, frame, true);
  742. STATUS_FLOAT_DENORMAL_OPERAND,
  743. STATUS_FLOAT_UNDERFLOW :
  744. res := SysHandleErrorFrame(206, frame, true);
  745. {excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  746. STATUS_FLOAT_INEXACT_RESULT,
  747. STATUS_FLOAT_INVALID_OPERATION,
  748. STATUS_FLOAT_STACK_CHECK :
  749. res := SysHandleErrorFrame(207, frame, true);
  750. STATUS_INTEGER_OVERFLOW :
  751. res := SysHandleErrorFrame(215, frame, false);
  752. STATUS_ILLEGAL_INSTRUCTION:
  753. res := SysHandleErrorFrame(216, frame, true);
  754. STATUS_ACCESS_VIOLATION:
  755. { Athlon prefetch bug? }
  756. if is_prefetch(pointer(excep^.ContextRecord^.Eip)) then
  757. begin
  758. { if yes, then retry }
  759. excep^.ExceptionRecord^.ExceptionCode := 0;
  760. res:=EXCEPTION_CONTINUE_EXECUTION;
  761. end
  762. else
  763. res := SysHandleErrorFrame(216, frame, true);
  764. STATUS_CONTROL_C_EXIT:
  765. res := SysHandleErrorFrame(217, frame, true);
  766. STATUS_PRIVILEGED_INSTRUCTION:
  767. res := SysHandleErrorFrame(218, frame, false);
  768. else
  769. begin
  770. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  771. res := SysHandleErrorFrame(217, frame, true)
  772. else
  773. res := SysHandleErrorFrame(255, frame, true);
  774. end;
  775. end;
  776. syswin32_i386_exception_handler := res;
  777. end;
  778. procedure install_exception_handlers;
  779. {$ifdef SYSTEMEXCEPTIONDEBUG}
  780. var
  781. oldexceptaddr,
  782. newexceptaddr : Longint;
  783. {$endif SYSTEMEXCEPTIONDEBUG}
  784. begin
  785. {$ifdef SYSTEMEXCEPTIONDEBUG}
  786. asm
  787. movl $0,%eax
  788. movl %fs:(%eax),%eax
  789. movl %eax,oldexceptaddr
  790. end;
  791. {$endif SYSTEMEXCEPTIONDEBUG}
  792. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  793. {$ifdef SYSTEMEXCEPTIONDEBUG}
  794. asm
  795. movl $0,%eax
  796. movl %fs:(%eax),%eax
  797. movl %eax,newexceptaddr
  798. end;
  799. if IsConsole then
  800. writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
  801. ' new exception ',hexstr(newexceptaddr,8));
  802. {$endif SYSTEMEXCEPTIONDEBUG}
  803. end;
  804. procedure remove_exception_handlers;
  805. begin
  806. SetUnhandledExceptionFilter(nil);
  807. end;
  808. {$else not cpui386 (Processor specific !!)}
  809. procedure install_exception_handlers;
  810. begin
  811. end;
  812. procedure remove_exception_handlers;
  813. begin
  814. end;
  815. {$endif Set_i386_Exception_handler}
  816. {****************************************************************************
  817. OS dependend widestrings
  818. ****************************************************************************}
  819. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; stdcall; external 'user32' name 'CharUpperBuffW';
  820. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD; stdcall; external 'user32' name 'CharLowerBuffW';
  821. function Win32WideUpper(const s : WideString) : WideString;
  822. begin
  823. result:=s;
  824. UniqueString(result);
  825. if length(result)>0 then
  826. CharUpperBuff(LPWSTR(result),length(result));
  827. end;
  828. function Win32WideLower(const s : WideString) : WideString;
  829. begin
  830. result:=s;
  831. UniqueString(result);
  832. if length(result)>0 then
  833. CharLowerBuff(LPWSTR(result),length(result));
  834. end;
  835. { there is a similiar procedure in sysutils which inits the fields which
  836. are only relevant for the sysutils units }
  837. procedure InitWin32Widestrings;
  838. begin
  839. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  840. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  841. end;
  842. {****************************************************************************
  843. Error Message writing using messageboxes
  844. ****************************************************************************}
  845. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  846. stdcall;external 'user32' name 'MessageBoxA';
  847. const
  848. ErrorBufferLength = 1024;
  849. var
  850. ErrorBuf : array[0..ErrorBufferLength] of char;
  851. ErrorLen : longint;
  852. Function ErrorWrite(Var F: TextRec): Integer;
  853. {
  854. An error message should always end with #13#10#13#10
  855. }
  856. var
  857. p : pchar;
  858. i : longint;
  859. Begin
  860. if F.BufPos>0 then
  861. begin
  862. if F.BufPos+ErrorLen>ErrorBufferLength then
  863. i:=ErrorBufferLength-ErrorLen
  864. else
  865. i:=F.BufPos;
  866. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  867. inc(ErrorLen,i);
  868. ErrorBuf[ErrorLen]:=#0;
  869. end;
  870. if ErrorLen>3 then
  871. begin
  872. p:=@ErrorBuf[ErrorLen];
  873. for i:=1 to 4 do
  874. begin
  875. dec(p);
  876. if not(p^ in [#10,#13]) then
  877. break;
  878. end;
  879. end;
  880. if ErrorLen=ErrorBufferLength then
  881. i:=4;
  882. if (i=4) then
  883. begin
  884. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  885. ErrorLen:=0;
  886. end;
  887. F.BufPos:=0;
  888. ErrorWrite:=0;
  889. End;
  890. Function ErrorClose(Var F: TextRec): Integer;
  891. begin
  892. if ErrorLen>0 then
  893. begin
  894. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  895. ErrorLen:=0;
  896. end;
  897. ErrorLen:=0;
  898. ErrorClose:=0;
  899. end;
  900. Function ErrorOpen(Var F: TextRec): Integer;
  901. Begin
  902. TextRec(F).InOutFunc:=@ErrorWrite;
  903. TextRec(F).FlushFunc:=@ErrorWrite;
  904. TextRec(F).CloseFunc:=@ErrorClose;
  905. ErrorOpen:=0;
  906. End;
  907. procedure AssignError(Var T: Text);
  908. begin
  909. Assign(T,'');
  910. TextRec(T).OpenFunc:=@ErrorOpen;
  911. Rewrite(T);
  912. end;
  913. procedure SysInitStdIO;
  914. begin
  915. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  916. displayed in and messagebox }
  917. StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  918. StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  919. StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  920. if not IsConsole then
  921. begin
  922. AssignError(stderr);
  923. AssignError(stdout);
  924. Assign(Output,'');
  925. Assign(Input,'');
  926. Assign(ErrOutput,'');
  927. end
  928. else
  929. begin
  930. OpenStdIO(Input,fmInput,StdInputHandle);
  931. OpenStdIO(Output,fmOutput,StdOutputHandle);
  932. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  933. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  934. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  935. end;
  936. end;
  937. (* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
  938. var
  939. ProcessID: SizeUInt;
  940. function GetProcessID: SizeUInt;
  941. begin
  942. GetProcessID := ProcessID;
  943. end;
  944. const
  945. Exe_entry_code : pointer = @Exe_entry;
  946. Dll_entry_code : pointer = @Dll_entry;
  947. begin
  948. StackLength := InitialStkLen;
  949. StackBottom := Sptr - StackLength;
  950. { get some helpful informations }
  951. GetStartupInfo(@startupinfo);
  952. { some misc Win32 stuff }
  953. hprevinst:=0;
  954. if not IsLibrary then
  955. HInstance:=getmodulehandle(GetCommandFile);
  956. MainInstance:=HInstance;
  957. cmdshow:=startupinfo.wshowwindow;
  958. { Setup heap }
  959. InitHeap;
  960. SysInitExceptions;
  961. SysInitStdIO;
  962. { Arguments }
  963. setup_arguments;
  964. { Reset IO Error }
  965. InOutRes:=0;
  966. ProcessID := GetCurrentProcessID;
  967. { threading }
  968. InitSystemThreads;
  969. { Reset internal error variable }
  970. errno:=0;
  971. {$ifdef HASVARIANT}
  972. initvariantmanager;
  973. {$endif HASVARIANT}
  974. initwidestringmanager;
  975. InitWin32Widestrings
  976. end.