system.pp 31 KB

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