system.pp 28 KB

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