system.pp 30 KB

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