system.pp 31 KB

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