system.pp 31 KB

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