system.pp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  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. {$define FPC_HAS_INDIRECT_MAIN_INFORMATION}
  18. {$ifdef cpui386}
  19. {$define Set_i386_Exception_handler}
  20. {$endif cpui386}
  21. {$define DISABLE_NO_THREAD_MANAGER}
  22. {$define HAS_WIDESTRINGMANAGER}
  23. { include system-independent routine headers }
  24. {$I systemh.inc}
  25. const
  26. LineEnding = #13#10;
  27. LFNSupport = true;
  28. DirectorySeparator = '\';
  29. DriveSeparator = ':';
  30. ExtensionSeparator = '.';
  31. PathSeparator = ';';
  32. AllowDirectorySeparators : set of char = ['\','/'];
  33. AllowDriveSeparators : set of char = [':'];
  34. { FileNameCaseSensitive is defined separately below!!! }
  35. maxExitCode = 65535;
  36. MaxPathLen = 260;
  37. AllFilesMask = '*';
  38. type
  39. PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
  40. TEXCEPTION_FRAME = record
  41. next : PEXCEPTION_FRAME;
  42. handler : pointer;
  43. end;
  44. const
  45. { Default filehandles }
  46. UnusedHandle : THandle = THandle(-1);
  47. StdInputHandle : THandle = 0;
  48. StdOutputHandle : THandle = 0;
  49. StdErrorHandle : THandle = 0;
  50. FileNameCaseSensitive : boolean = true;
  51. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  52. sLineBreak = LineEnding;
  53. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  54. System_exception_frame : PEXCEPTION_FRAME =nil;
  55. type
  56. TStartupInfo=packed record
  57. cb : longint;
  58. lpReserved : Pointer;
  59. lpDesktop : Pointer;
  60. lpTitle : Pointer;
  61. dwX : longint;
  62. dwY : longint;
  63. dwXSize : longint;
  64. dwYSize : longint;
  65. dwXCountChars : longint;
  66. dwYCountChars : longint;
  67. dwFillAttribute : longint;
  68. dwFlags : longint;
  69. wShowWindow : Word;
  70. cbReserved2 : Word;
  71. lpReserved2 : Pointer;
  72. hStdInput : longint;
  73. hStdOutput : longint;
  74. hStdError : longint;
  75. end;
  76. var
  77. { C compatible arguments }
  78. argc : longint;
  79. argv : ppchar;
  80. { Win32 Info }
  81. startupinfo : tstartupinfo;
  82. hprevinst,
  83. MainInstance,
  84. cmdshow : longint;
  85. DLLreason,DLLparam:longint;
  86. StartupConsoleMode : DWORD;
  87. type
  88. TDLL_Entry_Hook = procedure (dllparam : longint);
  89. const
  90. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  91. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  92. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  93. Const
  94. { it can be discussed whether fmShareDenyNone means read and write or read, write and delete, see
  95. also http://bugs.freepascal.org/view.php?id=8898, this allows users to configure the used
  96. value
  97. }
  98. fmShareDenyNoneFlags : DWord = 3;
  99. implementation
  100. var
  101. EntryInformation : TEntryInformation;
  102. SysInstance : Longint;public name '_FPC_SysInstance';
  103. { used by wstrings.inc because wstrings.inc is included before sysos.inc
  104. this is put here (FK) }
  105. function SysAllocStringLen(psz:pointer;len:dword):pointer;stdcall;
  106. external 'oleaut32.dll' name 'SysAllocStringLen';
  107. procedure SysFreeString(bstr:pointer);stdcall;
  108. external 'oleaut32.dll' name 'SysFreeString';
  109. function SysReAllocStringLen(var bstr:pointer;psz: pointer;
  110. len:dword): Integer; stdcall;external 'oleaut32.dll' name 'SysReAllocStringLen';
  111. { include system independent routines }
  112. {$I system.inc}
  113. {*****************************************************************************
  114. Parameter Handling
  115. *****************************************************************************}
  116. procedure setup_arguments;
  117. var
  118. arglen,
  119. count : longint;
  120. argstart,
  121. pc,arg : pchar;
  122. quote : Boolean;
  123. argvlen : longint;
  124. buf: array[0..259] of char; // need MAX_PATH bytes, not 256!
  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. ArgLen := GetModuleFileName(0, @buf[0], sizeof(buf));
  148. buf[ArgLen] := #0; // be safe
  149. allocarg(0,arglen);
  150. move(buf,argv[0]^,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:=False;
  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. if pc[1]<>'"' then
  181. quote := not quote
  182. else
  183. inc(pc);
  184. else
  185. inc(arglen);
  186. end;
  187. inc(pc);
  188. end;
  189. { copy argument }
  190. { Don't copy the first one, it is already there.}
  191. If Count<>0 then
  192. begin
  193. allocarg(count,arglen);
  194. quote:=False;
  195. pc:=argstart;
  196. arg:=argv[count];
  197. while (pc^<>#0) do
  198. begin
  199. case pc^ of
  200. #1..#32 :
  201. begin
  202. if quote then
  203. begin
  204. arg^:=pc^;
  205. inc(arg);
  206. end
  207. else
  208. break;
  209. end;
  210. '"' :
  211. if pc[1]<>'"' then
  212. quote := not quote
  213. else
  214. inc(pc);
  215. else
  216. begin
  217. arg^:=pc^;
  218. inc(arg);
  219. end;
  220. end;
  221. inc(pc);
  222. end;
  223. arg^:=#0;
  224. end;
  225. {$IfDef SYSTEM_DEBUG_STARTUP}
  226. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  227. {$EndIf SYSTEM_DEBUG_STARTUP}
  228. inc(count);
  229. end;
  230. { get argc }
  231. argc:=count;
  232. { free unused memory, leaving a nil entry at the end }
  233. sysreallocmem(argv,(count+1)*sizeof(pointer));
  234. argv[count] := nil;
  235. end;
  236. function paramcount : longint;
  237. begin
  238. paramcount := argc - 1;
  239. end;
  240. function paramstr(l : longint) : string;
  241. begin
  242. if (l>=0) and (l<argc) then
  243. paramstr:=strpas(argv[l])
  244. else
  245. paramstr:='';
  246. end;
  247. procedure randomize;
  248. begin
  249. randseed:=GetTickCount;
  250. end;
  251. {*****************************************************************************
  252. System Dependent Exit code
  253. *****************************************************************************}
  254. procedure install_exception_handlers;forward;
  255. procedure remove_exception_handlers;forward;
  256. {$ifndef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  257. procedure PascalMain;stdcall;external name 'PASCALMAIN';
  258. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  259. procedure fpc_do_exit;stdcall;external name 'FPC_DO_EXIT';
  260. Procedure ExitDLL(Exitcode : longint); forward;
  261. procedure asm_exit;stdcall;external name 'asm_exit';
  262. Procedure system_exit;
  263. begin
  264. { don't call ExitProcess inside
  265. the DLL exit code !!
  266. This crashes Win95 at least PM }
  267. if IsLibrary then
  268. ExitDLL(ExitCode);
  269. if not IsConsole then
  270. begin
  271. Close(stderr);
  272. Close(stdout);
  273. Close(erroutput);
  274. Close(Input);
  275. Close(Output);
  276. { what about Input and Output ?? PM }
  277. { now handled, FPK }
  278. end;
  279. remove_exception_handlers;
  280. { in 2.0 asm_exit does an exitprocess }
  281. {$ifndef ver2_0}
  282. { do cleanup required by the startup code }
  283. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  284. EntryInformation.asm_exit();
  285. {$else FPC_HAS_INDIRECT_MAIN_INFORMATION}
  286. asm_exit;
  287. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  288. {$endif ver2_0}
  289. { call exitprocess, with cleanup as required }
  290. ExitProcess(exitcode);
  291. end;
  292. var
  293. { value of the stack segment
  294. to check if the call stack can be written on exceptions }
  295. _SS : Cardinal;
  296. procedure Exe_entry(const info : TEntryInformation);[public,alias:'_FPC_EXE_Entry'];
  297. var
  298. ST : pointer;
  299. begin
  300. EntryInformation:=info;
  301. IsLibrary:=false;
  302. { install the handlers for exe only ?
  303. or should we install them for DLL also ? (PM) }
  304. install_exception_handlers;
  305. { This strange construction is needed to solve the _SS problem
  306. with a smartlinked syswin32 (PFV) }
  307. asm
  308. { allocate space for an exception frame }
  309. pushl $0
  310. pushl %fs:(0)
  311. { movl %esp,%fs:(0)
  312. but don't insert it as it doesn't
  313. point to anything yet
  314. this will be used in signals unit }
  315. movl %esp,%eax
  316. movl %eax,System_exception_frame
  317. pushl %ebp
  318. movl %esp,%eax
  319. movl %eax,st
  320. end;
  321. StackTop:=st;
  322. asm
  323. xorl %eax,%eax
  324. movw %ss,%ax
  325. movl %eax,_SS
  326. xorl %ebp,%ebp
  327. end;
  328. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  329. EntryInformation.PascalMain();
  330. {$else FPC_HAS_INDIRECT_MAIN_INFORMATION}
  331. PascalMain;
  332. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  333. asm
  334. popl %ebp
  335. end;
  336. { if we pass here there was no error ! }
  337. system_exit;
  338. end;
  339. function GetCurrentProcess : dword;
  340. stdcall;external 'kernel32' name 'GetCurrentProcess';
  341. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  342. stdcall;external 'kernel32' name 'ReadProcessMemory';
  343. function is_prefetch(p : pointer) : boolean;
  344. var
  345. a : array[0..15] of byte;
  346. doagain : boolean;
  347. instrlo,instrhi,opcode : byte;
  348. i : longint;
  349. begin
  350. result:=false;
  351. { read memory savely without causing another exeception }
  352. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  353. exit;
  354. i:=0;
  355. doagain:=true;
  356. while doagain and (i<15) do
  357. begin
  358. opcode:=a[i];
  359. instrlo:=opcode and $f;
  360. instrhi:=opcode and $f0;
  361. case instrhi of
  362. { prefix? }
  363. $20,$30:
  364. doagain:=(instrlo and 7)=6;
  365. $60:
  366. doagain:=(instrlo and $c)=4;
  367. $f0:
  368. doagain:=instrlo in [0,2,3];
  369. $0:
  370. begin
  371. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  372. exit;
  373. end;
  374. else
  375. doagain:=false;
  376. end;
  377. inc(i);
  378. end;
  379. end;
  380. //
  381. // Hardware exception handling
  382. //
  383. {$ifdef Set_i386_Exception_handler}
  384. {
  385. Error code definitions for the Win32 API functions
  386. Values are 32 bit values layed out as follows:
  387. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  388. 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
  389. +---+-+-+-----------------------+-------------------------------+
  390. |Sev|C|R| Facility | Code |
  391. +---+-+-+-----------------------+-------------------------------+
  392. where
  393. Sev - is the severity code
  394. 00 - Success
  395. 01 - Informational
  396. 10 - Warning
  397. 11 - Error
  398. C - is the Customer code flag
  399. R - is a reserved bit
  400. Facility - is the facility code
  401. Code - is the facility's status code
  402. }
  403. const
  404. SEVERITY_SUCCESS = $00000000;
  405. SEVERITY_INFORMATIONAL = $40000000;
  406. SEVERITY_WARNING = $80000000;
  407. SEVERITY_ERROR = $C0000000;
  408. const
  409. STATUS_SEGMENT_NOTIFICATION = $40000005;
  410. DBG_TERMINATE_THREAD = $40010003;
  411. DBG_TERMINATE_PROCESS = $40010004;
  412. DBG_CONTROL_C = $40010005;
  413. DBG_CONTROL_BREAK = $40010008;
  414. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  415. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  416. STATUS_BREAKPOINT = $80000003;
  417. STATUS_SINGLE_STEP = $80000004;
  418. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  419. STATUS_ACCESS_VIOLATION = $C0000005;
  420. STATUS_IN_PAGE_ERROR = $C0000006;
  421. STATUS_INVALID_HANDLE = $C0000008;
  422. STATUS_NO_MEMORY = $C0000017;
  423. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  424. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  425. STATUS_INVALID_DISPOSITION = $C0000026;
  426. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  427. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  428. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  429. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  430. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  431. STATUS_FLOAT_OVERFLOW = $C0000091;
  432. STATUS_FLOAT_STACK_CHECK = $C0000092;
  433. STATUS_FLOAT_UNDERFLOW = $C0000093;
  434. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  435. STATUS_INTEGER_OVERFLOW = $C0000095;
  436. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  437. STATUS_STACK_OVERFLOW = $C00000FD;
  438. STATUS_CONTROL_C_EXIT = $C000013A;
  439. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  440. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  441. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  442. EXCEPTION_EXECUTE_HANDLER = 1;
  443. EXCEPTION_CONTINUE_EXECUTION = -1;
  444. EXCEPTION_CONTINUE_SEARCH = 0;
  445. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  446. CONTEXT_X86 = $00010000;
  447. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  448. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  449. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  450. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  451. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  452. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  453. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  454. MAXIMUM_SUPPORTED_EXTENSION = 512;
  455. type
  456. PFloatingSaveArea = ^TFloatingSaveArea;
  457. TFloatingSaveArea = packed record
  458. ControlWord : Cardinal;
  459. StatusWord : Cardinal;
  460. TagWord : Cardinal;
  461. ErrorOffset : Cardinal;
  462. ErrorSelector : Cardinal;
  463. DataOffset : Cardinal;
  464. DataSelector : Cardinal;
  465. RegisterArea : array[0..79] of Byte;
  466. Cr0NpxState : Cardinal;
  467. end;
  468. PContext = ^TContext;
  469. TContext = packed record
  470. //
  471. // The flags values within this flag control the contents of
  472. // a CONTEXT record.
  473. //
  474. ContextFlags : Cardinal;
  475. //
  476. // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
  477. // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
  478. // included in CONTEXT_FULL.
  479. //
  480. Dr0, Dr1, Dr2,
  481. Dr3, Dr6, Dr7 : Cardinal;
  482. //
  483. // This section is specified/returned if the
  484. // ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
  485. //
  486. FloatSave : TFloatingSaveArea;
  487. //
  488. // This section is specified/returned if the
  489. // ContextFlags word contains the flag CONTEXT_SEGMENTS.
  490. //
  491. SegGs, SegFs,
  492. SegEs, SegDs : Cardinal;
  493. //
  494. // This section is specified/returned if the
  495. // ContextFlags word contains the flag CONTEXT_INTEGER.
  496. //
  497. Edi, Esi, Ebx,
  498. Edx, Ecx, Eax : Cardinal;
  499. //
  500. // This section is specified/returned if the
  501. // ContextFlags word contains the flag CONTEXT_CONTROL.
  502. //
  503. Ebp : Cardinal;
  504. Eip : Cardinal;
  505. SegCs : Cardinal;
  506. EFlags, Esp, SegSs : Cardinal;
  507. //
  508. // This section is specified/returned if the ContextFlags word
  509. // contains the flag CONTEXT_EXTENDED_REGISTERS.
  510. // The format and contexts are processor specific
  511. //
  512. ExtendedRegisters : array[0..MAXIMUM_SUPPORTED_EXTENSION-1] of Byte;
  513. end;
  514. type
  515. PExceptionRecord = ^TExceptionRecord;
  516. TExceptionRecord = packed record
  517. ExceptionCode : cardinal;
  518. ExceptionFlags : Longint;
  519. ExceptionRecord : PExceptionRecord;
  520. ExceptionAddress : Pointer;
  521. NumberParameters : Longint;
  522. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
  523. end;
  524. PExceptionPointers = ^TExceptionPointers;
  525. TExceptionPointers = packed record
  526. ExceptionRecord : PExceptionRecord;
  527. ContextRecord : PContext;
  528. end;
  529. { type of functions that should be used for exception handling }
  530. TTopLevelExceptionFilter = function (excep : PExceptionPointers) : Longint;stdcall;
  531. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : TTopLevelExceptionFilter) : TTopLevelExceptionFilter;
  532. stdcall;external 'kernel32' name 'SetUnhandledExceptionFilter';
  533. const
  534. MaxExceptionLevel = 16;
  535. exceptLevel : Byte = 0;
  536. var
  537. exceptEip : array[0..MaxExceptionLevel-1] of Longint;
  538. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  539. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  540. {$ifdef SYSTEMEXCEPTIONDEBUG}
  541. procedure DebugHandleErrorAddrFrame(error : longint; addr, frame : pointer);
  542. begin
  543. if IsConsole then
  544. begin
  545. write(stderr,'HandleErrorAddrFrame(error=',error);
  546. write(stderr,',addr=',hexstr(ptruint(addr),8));
  547. writeln(stderr,',frame=',hexstr(ptruint(frame),8),')');
  548. end;
  549. HandleErrorAddrFrame(error,addr,frame);
  550. end;
  551. {$endif SYSTEMEXCEPTIONDEBUG}
  552. procedure JumpToHandleErrorFrame;
  553. var
  554. eip, ebp, error : Longint;
  555. begin
  556. // save ebp
  557. asm
  558. movl (%ebp),%eax
  559. movl %eax,ebp
  560. end;
  561. if (exceptLevel > 0) then
  562. dec(exceptLevel);
  563. eip:=exceptEip[exceptLevel];
  564. error:=exceptError[exceptLevel];
  565. {$ifdef SYSTEMEXCEPTIONDEBUG}
  566. if IsConsole then
  567. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  568. {$endif SYSTEMEXCEPTIONDEBUG}
  569. if resetFPU[exceptLevel] then
  570. SysResetFPU;
  571. { build a fake stack }
  572. asm
  573. {$ifdef REGCALL}
  574. movl ebp,%ecx
  575. movl eip,%edx
  576. movl error,%eax
  577. pushl eip
  578. movl ebp,%ebp // Change frame pointer
  579. {$else}
  580. movl ebp,%eax
  581. pushl %eax
  582. movl eip,%eax
  583. pushl %eax
  584. movl error,%eax
  585. pushl %eax
  586. movl eip,%eax
  587. pushl %eax
  588. movl ebp,%ebp // Change frame pointer
  589. {$endif}
  590. {$ifdef SYSTEMEXCEPTIONDEBUG}
  591. jmpl DebugHandleErrorAddrFrame
  592. {$else not SYSTEMEXCEPTIONDEBUG}
  593. jmpl HandleErrorAddrFrame
  594. {$endif SYSTEMEXCEPTIONDEBUG}
  595. end;
  596. end;
  597. function syswin32_i386_exception_handler(excep : PExceptionPointers) : Longint;stdcall;
  598. var
  599. res: longint;
  600. err: byte;
  601. must_reset_fpu: boolean;
  602. begin
  603. res := EXCEPTION_CONTINUE_SEARCH;
  604. if excep^.ContextRecord^.SegSs=_SS then begin
  605. err := 0;
  606. must_reset_fpu := true;
  607. {$ifdef SYSTEMEXCEPTIONDEBUG}
  608. if IsConsole then Writeln(stderr,'Exception ',
  609. hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
  610. {$endif SYSTEMEXCEPTIONDEBUG}
  611. case excep^.ExceptionRecord^.ExceptionCode of
  612. STATUS_INTEGER_DIVIDE_BY_ZERO,
  613. STATUS_FLOAT_DIVIDE_BY_ZERO :
  614. err := 200;
  615. STATUS_ARRAY_BOUNDS_EXCEEDED :
  616. begin
  617. err := 201;
  618. must_reset_fpu := false;
  619. end;
  620. STATUS_STACK_OVERFLOW :
  621. begin
  622. err := 202;
  623. must_reset_fpu := false;
  624. end;
  625. STATUS_FLOAT_OVERFLOW :
  626. err := 205;
  627. STATUS_FLOAT_DENORMAL_OPERAND,
  628. STATUS_FLOAT_UNDERFLOW :
  629. err := 206;
  630. {excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  631. STATUS_FLOAT_INEXACT_RESULT,
  632. STATUS_FLOAT_INVALID_OPERATION,
  633. STATUS_FLOAT_STACK_CHECK :
  634. err := 207;
  635. STATUS_INTEGER_OVERFLOW :
  636. begin
  637. err := 215;
  638. must_reset_fpu := false;
  639. end;
  640. STATUS_ILLEGAL_INSTRUCTION:
  641. { if we're testing sse support, simply set the flag and continue }
  642. if sse_check then
  643. begin
  644. os_supports_sse:=false;
  645. { skip the offending movaps %xmm7, %xmm6 instruction }
  646. inc(excep^.ContextRecord^.Eip,3);
  647. excep^.ExceptionRecord^.ExceptionCode := 0;
  648. res:=EXCEPTION_CONTINUE_EXECUTION;
  649. end
  650. else
  651. err := 216;
  652. STATUS_ACCESS_VIOLATION:
  653. { Athlon prefetch bug? }
  654. if is_prefetch(pointer(excep^.ContextRecord^.Eip)) then
  655. begin
  656. { if yes, then retry }
  657. excep^.ExceptionRecord^.ExceptionCode := 0;
  658. res:=EXCEPTION_CONTINUE_EXECUTION;
  659. end
  660. else
  661. err := 216;
  662. STATUS_CONTROL_C_EXIT:
  663. err := 217;
  664. STATUS_PRIVILEGED_INSTRUCTION:
  665. begin
  666. err := 218;
  667. must_reset_fpu := false;
  668. end;
  669. else
  670. begin
  671. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  672. err := 217
  673. else
  674. err := 255;
  675. end;
  676. end;
  677. if (err <> 0) and (exceptLevel < MaxExceptionLevel) then begin
  678. exceptEip[exceptLevel] := excep^.ContextRecord^.Eip;
  679. exceptError[exceptLevel] := err;
  680. resetFPU[exceptLevel] := must_reset_fpu;
  681. inc(exceptLevel);
  682. excep^.ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
  683. excep^.ExceptionRecord^.ExceptionCode := 0;
  684. res := EXCEPTION_CONTINUE_EXECUTION;
  685. {$ifdef SYSTEMEXCEPTIONDEBUG}
  686. if IsConsole then begin
  687. writeln(stderr,'Exception Continue Exception set at ',
  688. hexstr(exceptEip[exceptLevel],8));
  689. writeln(stderr,'Eip changed to ',
  690. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', err);
  691. end;
  692. {$endif SYSTEMEXCEPTIONDEBUG}
  693. end;
  694. end;
  695. syswin32_i386_exception_handler := res;
  696. end;
  697. procedure install_exception_handlers;
  698. {$ifdef SYSTEMEXCEPTIONDEBUG}
  699. var
  700. oldexceptaddr,
  701. newexceptaddr : Longint;
  702. {$endif SYSTEMEXCEPTIONDEBUG}
  703. begin
  704. {$ifdef SYSTEMEXCEPTIONDEBUG}
  705. asm
  706. movl $0,%eax
  707. movl %fs:(%eax),%eax
  708. movl %eax,oldexceptaddr
  709. end;
  710. {$endif SYSTEMEXCEPTIONDEBUG}
  711. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  712. {$ifdef SYSTEMEXCEPTIONDEBUG}
  713. asm
  714. movl $0,%eax
  715. movl %fs:(%eax),%eax
  716. movl %eax,newexceptaddr
  717. end;
  718. if IsConsole then
  719. writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
  720. ' new exception ',hexstr(newexceptaddr,8));
  721. {$endif SYSTEMEXCEPTIONDEBUG}
  722. end;
  723. procedure remove_exception_handlers;
  724. begin
  725. SetUnhandledExceptionFilter(nil);
  726. end;
  727. {$else not cpui386 (Processor specific !!)}
  728. procedure install_exception_handlers;
  729. begin
  730. end;
  731. procedure remove_exception_handlers;
  732. begin
  733. end;
  734. {$endif Set_i386_Exception_handler}
  735. {******************************************************************************}
  736. { include code common with win64 }
  737. {$I syswin.inc}
  738. {******************************************************************************}
  739. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  740. type
  741. tdosheader = packed record
  742. e_magic : word;
  743. e_cblp : word;
  744. e_cp : word;
  745. e_crlc : word;
  746. e_cparhdr : word;
  747. e_minalloc : word;
  748. e_maxalloc : word;
  749. e_ss : word;
  750. e_sp : word;
  751. e_csum : word;
  752. e_ip : word;
  753. e_cs : word;
  754. e_lfarlc : word;
  755. e_ovno : word;
  756. e_res : array[0..3] of word;
  757. e_oemid : word;
  758. e_oeminfo : word;
  759. e_res2 : array[0..9] of word;
  760. e_lfanew : longint;
  761. end;
  762. tpeheader = packed record
  763. PEMagic : longint;
  764. Machine : word;
  765. NumberOfSections : word;
  766. TimeDateStamp : longint;
  767. PointerToSymbolTable : longint;
  768. NumberOfSymbols : longint;
  769. SizeOfOptionalHeader : word;
  770. Characteristics : word;
  771. Magic : word;
  772. MajorLinkerVersion : byte;
  773. MinorLinkerVersion : byte;
  774. SizeOfCode : longint;
  775. SizeOfInitializedData : longint;
  776. SizeOfUninitializedData : longint;
  777. AddressOfEntryPoint : longint;
  778. BaseOfCode : longint;
  779. BaseOfData : longint;
  780. ImageBase : longint;
  781. SectionAlignment : longint;
  782. FileAlignment : longint;
  783. MajorOperatingSystemVersion : word;
  784. MinorOperatingSystemVersion : word;
  785. MajorImageVersion : word;
  786. MinorImageVersion : word;
  787. MajorSubsystemVersion : word;
  788. MinorSubsystemVersion : word;
  789. Reserved1 : longint;
  790. SizeOfImage : longint;
  791. SizeOfHeaders : longint;
  792. CheckSum : longint;
  793. Subsystem : word;
  794. DllCharacteristics : word;
  795. SizeOfStackReserve : longint;
  796. SizeOfStackCommit : longint;
  797. SizeOfHeapReserve : longint;
  798. SizeOfHeapCommit : longint;
  799. LoaderFlags : longint;
  800. NumberOfRvaAndSizes : longint;
  801. DataDirectory : array[1..$80] of byte;
  802. end;
  803. begin
  804. result:=tpeheader((pointer(SysInstance)+(tdosheader(pointer(SysInstance)^).e_lfanew))^).SizeOfStackReserve;
  805. end;
  806. begin
  807. { get some helpful informations }
  808. GetStartupInfo(@startupinfo);
  809. SysResetFPU;
  810. if not(IsLibrary) then
  811. SysInitFPU;
  812. { some misc Win32 stuff }
  813. hprevinst:=0;
  814. if not IsLibrary then
  815. SysInstance:=getmodulehandle(nil);
  816. MainInstance:=SysInstance;
  817. { pass dummy value }
  818. StackLength := CheckInitialStkLen($1000000);
  819. StackBottom := StackTop - StackLength;
  820. cmdshow:=startupinfo.wshowwindow;
  821. { Setup heap }
  822. InitHeap;
  823. SysInitExceptions;
  824. { setup fastmove stuff }
  825. fpc_cpucodeinit;
  826. SysInitStdIO;
  827. { Arguments }
  828. setup_arguments;
  829. { Reset IO Error }
  830. InOutRes:=0;
  831. ProcessID := GetCurrentProcessID;
  832. { threading }
  833. InitSystemThreads;
  834. { Reset internal error variable }
  835. errno:=0;
  836. initvariantmanager;
  837. initwidestringmanager;
  838. {$ifndef VER2_2}
  839. initunicodestringmanager;
  840. {$endif VER2_2}
  841. InitWin32Widestrings;
  842. DispCallByIDProc:=@DoDispCallByIDError;
  843. end.