system.pp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  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+1);
  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. res: longint;
  698. err: byte;
  699. must_reset_fpu: boolean;
  700. begin
  701. res := EXCEPTION_CONTINUE_SEARCH;
  702. if excep^.ContextRecord^.SegSs=_SS then begin
  703. err := 0;
  704. must_reset_fpu := true;
  705. {$ifdef SYSTEMEXCEPTIONDEBUG}
  706. if IsConsole then Writeln(stderr,'Exception ',
  707. hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
  708. {$endif SYSTEMEXCEPTIONDEBUG}
  709. case cardinal(excep^.ExceptionRecord^.ExceptionCode) of
  710. STATUS_INTEGER_DIVIDE_BY_ZERO,
  711. STATUS_FLOAT_DIVIDE_BY_ZERO :
  712. err := 200;
  713. STATUS_ARRAY_BOUNDS_EXCEEDED :
  714. begin
  715. err := 201;
  716. must_reset_fpu := false;
  717. end;
  718. STATUS_STACK_OVERFLOW :
  719. begin
  720. err := 202;
  721. must_reset_fpu := false;
  722. end;
  723. STATUS_FLOAT_OVERFLOW :
  724. err := 205;
  725. STATUS_FLOAT_DENORMAL_OPERAND,
  726. STATUS_FLOAT_UNDERFLOW :
  727. err := 206;
  728. {excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  729. STATUS_FLOAT_INEXACT_RESULT,
  730. STATUS_FLOAT_INVALID_OPERATION,
  731. STATUS_FLOAT_STACK_CHECK :
  732. err := 207;
  733. STATUS_INTEGER_OVERFLOW :
  734. begin
  735. err := 215;
  736. must_reset_fpu := false;
  737. end;
  738. STATUS_ILLEGAL_INSTRUCTION:
  739. err := 216;
  740. STATUS_ACCESS_VIOLATION:
  741. { Athlon prefetch bug? }
  742. if is_prefetch(pointer(excep^.ContextRecord^.Eip)) then
  743. begin
  744. { if yes, then retry }
  745. excep^.ExceptionRecord^.ExceptionCode := 0;
  746. res:=EXCEPTION_CONTINUE_EXECUTION;
  747. end
  748. else
  749. err := 216;
  750. STATUS_CONTROL_C_EXIT:
  751. err := 217;
  752. STATUS_PRIVILEGED_INSTRUCTION:
  753. begin
  754. err := 218;
  755. must_reset_fpu := false;
  756. end;
  757. else
  758. begin
  759. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  760. err := 217
  761. else
  762. err := 255;
  763. end;
  764. end;
  765. if (err <> 0) and (exceptLevel < MaxExceptionLevel) then begin
  766. exceptEip[exceptLevel] := excep^.ContextRecord^.Eip;
  767. exceptError[exceptLevel] := err;
  768. resetFPU[exceptLevel] := must_reset_fpu;
  769. inc(exceptLevel);
  770. excep^.ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
  771. excep^.ExceptionRecord^.ExceptionCode := 0;
  772. res := EXCEPTION_CONTINUE_EXECUTION;
  773. {$ifdef SYSTEMEXCEPTIONDEBUG}
  774. if IsConsole then begin
  775. writeln(stderr,'Exception Continue Exception set at ',
  776. hexstr(exceptEip[exceptLevel],8));
  777. writeln(stderr,'Eip changed to ',
  778. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  779. end;
  780. {$endif SYSTEMEXCEPTIONDEBUG}
  781. end;
  782. end;
  783. syswin32_i386_exception_handler := res;
  784. end;
  785. procedure install_exception_handlers;
  786. {$ifdef SYSTEMEXCEPTIONDEBUG}
  787. var
  788. oldexceptaddr,
  789. newexceptaddr : Longint;
  790. {$endif SYSTEMEXCEPTIONDEBUG}
  791. begin
  792. {$ifdef SYSTEMEXCEPTIONDEBUG}
  793. asm
  794. movl $0,%eax
  795. movl %fs:(%eax),%eax
  796. movl %eax,oldexceptaddr
  797. end;
  798. {$endif SYSTEMEXCEPTIONDEBUG}
  799. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  800. {$ifdef SYSTEMEXCEPTIONDEBUG}
  801. asm
  802. movl $0,%eax
  803. movl %fs:(%eax),%eax
  804. movl %eax,newexceptaddr
  805. end;
  806. if IsConsole then
  807. writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
  808. ' new exception ',hexstr(newexceptaddr,8));
  809. {$endif SYSTEMEXCEPTIONDEBUG}
  810. end;
  811. procedure remove_exception_handlers;
  812. begin
  813. SetUnhandledExceptionFilter(nil);
  814. end;
  815. {$else not cpui386 (Processor specific !!)}
  816. procedure install_exception_handlers;
  817. begin
  818. end;
  819. procedure remove_exception_handlers;
  820. begin
  821. end;
  822. {$endif Set_i386_Exception_handler}
  823. {****************************************************************************
  824. OS dependend widestrings
  825. ****************************************************************************}
  826. const
  827. { MultiByteToWideChar }
  828. MB_PRECOMPOSED = 1;
  829. CP_ACP = 0;
  830. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  831. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  832. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  833. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  834. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  835. stdcall; external 'user32' name 'CharUpperBuffW';
  836. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  837. stdcall; external 'user32' name 'CharLowerBuffW';
  838. procedure Win32Wide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt);
  839. var
  840. destlen: SizeInt;
  841. begin
  842. // retrieve length including trailing #0
  843. destlen:=WideCharToMultiByte(CP_ACP, 0, source, len+1, nil, 0, nil, nil);
  844. setlength(dest, destlen-1);
  845. WideCharToMultiByte(CP_ACP, 0, source, len+1, @dest[1], destlen, nil, nil);
  846. end;
  847. procedure Win32Ansi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
  848. var
  849. destlen: SizeInt;
  850. begin
  851. // retrieve length including trailing #0
  852. destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len+1, nil, 0);
  853. setlength(dest, destlen-1);
  854. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len+1, @dest[1], destlen);
  855. end;
  856. function Win32WideUpper(const s : WideString) : WideString;
  857. begin
  858. result:=s;
  859. UniqueString(result);
  860. if length(result)>0 then
  861. CharUpperBuff(LPWSTR(result),length(result));
  862. end;
  863. function Win32WideLower(const s : WideString) : WideString;
  864. begin
  865. result:=s;
  866. UniqueString(result);
  867. if length(result)>0 then
  868. CharLowerBuff(LPWSTR(result),length(result));
  869. end;
  870. { there is a similiar procedure in sysutils which inits the fields which
  871. are only relevant for the sysutils units }
  872. procedure InitWin32Widestrings;
  873. begin
  874. widestringmanager.Wide2AnsiMoveProc:=@Win32Wide2AnsiMove;
  875. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  876. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  877. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  878. end;
  879. {****************************************************************************
  880. Error Message writing using messageboxes
  881. ****************************************************************************}
  882. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  883. stdcall;external 'user32' name 'MessageBoxA';
  884. const
  885. ErrorBufferLength = 1024;
  886. var
  887. ErrorBuf : array[0..ErrorBufferLength] of char;
  888. ErrorLen : longint;
  889. Function ErrorWrite(Var F: TextRec): Integer;
  890. {
  891. An error message should always end with #13#10#13#10
  892. }
  893. var
  894. p : pchar;
  895. i : longint;
  896. Begin
  897. if F.BufPos>0 then
  898. begin
  899. if F.BufPos+ErrorLen>ErrorBufferLength then
  900. i:=ErrorBufferLength-ErrorLen
  901. else
  902. i:=F.BufPos;
  903. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  904. inc(ErrorLen,i);
  905. ErrorBuf[ErrorLen]:=#0;
  906. end;
  907. if ErrorLen>3 then
  908. begin
  909. p:=@ErrorBuf[ErrorLen];
  910. for i:=1 to 4 do
  911. begin
  912. dec(p);
  913. if not(p^ in [#10,#13]) then
  914. break;
  915. end;
  916. end;
  917. if ErrorLen=ErrorBufferLength then
  918. i:=4;
  919. if (i=4) then
  920. begin
  921. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  922. ErrorLen:=0;
  923. end;
  924. F.BufPos:=0;
  925. ErrorWrite:=0;
  926. End;
  927. Function ErrorClose(Var F: TextRec): Integer;
  928. begin
  929. if ErrorLen>0 then
  930. begin
  931. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  932. ErrorLen:=0;
  933. end;
  934. ErrorLen:=0;
  935. ErrorClose:=0;
  936. end;
  937. Function ErrorOpen(Var F: TextRec): Integer;
  938. Begin
  939. TextRec(F).InOutFunc:=@ErrorWrite;
  940. TextRec(F).FlushFunc:=@ErrorWrite;
  941. TextRec(F).CloseFunc:=@ErrorClose;
  942. ErrorOpen:=0;
  943. End;
  944. procedure AssignError(Var T: Text);
  945. begin
  946. Assign(T,'');
  947. TextRec(T).OpenFunc:=@ErrorOpen;
  948. Rewrite(T);
  949. end;
  950. procedure SysInitStdIO;
  951. begin
  952. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  953. displayed in and messagebox }
  954. StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  955. StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  956. StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  957. if not IsConsole then
  958. begin
  959. AssignError(stderr);
  960. AssignError(stdout);
  961. Assign(Output,'');
  962. Assign(Input,'');
  963. Assign(ErrOutput,'');
  964. end
  965. else
  966. begin
  967. OpenStdIO(Input,fmInput,StdInputHandle);
  968. OpenStdIO(Output,fmOutput,StdOutputHandle);
  969. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  970. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  971. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  972. end;
  973. end;
  974. (* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
  975. var
  976. ProcessID: SizeUInt;
  977. function GetProcessID: SizeUInt;
  978. begin
  979. GetProcessID := ProcessID;
  980. end;
  981. const
  982. Exe_entry_code : pointer = @Exe_entry;
  983. Dll_entry_code : pointer = @Dll_entry;
  984. begin
  985. StackLength := InitialStkLen;
  986. StackBottom := Sptr - StackLength;
  987. { get some helpful informations }
  988. GetStartupInfo(@startupinfo);
  989. { some misc Win32 stuff }
  990. hprevinst:=0;
  991. if not IsLibrary then
  992. HInstance:=getmodulehandle(GetCommandFile);
  993. MainInstance:=HInstance;
  994. cmdshow:=startupinfo.wshowwindow;
  995. { Setup heap }
  996. InitHeap;
  997. SysInitExceptions;
  998. SysInitStdIO;
  999. { Arguments }
  1000. setup_arguments;
  1001. { Reset IO Error }
  1002. InOutRes:=0;
  1003. ProcessID := GetCurrentProcessID;
  1004. { threading }
  1005. InitSystemThreads;
  1006. { Reset internal error variable }
  1007. errno:=0;
  1008. initvariantmanager;
  1009. initwidestringmanager;
  1010. InitWin32Widestrings
  1011. end.