system.pp 31 KB

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