system.pp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098
  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, pointer(dst) - pointer(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. { don't call ExitProcess inside
  267. the DLL exit code !!
  268. This crashes Win95 at least PM }
  269. if IsLibrary then
  270. ExitDLL(ExitCode);
  271. if not IsConsole then
  272. begin
  273. Close(stderr);
  274. Close(stdout);
  275. Close(erroutput);
  276. Close(Input);
  277. Close(Output);
  278. { what about Input and Output ?? PM }
  279. { now handled, FPK }
  280. end;
  281. remove_exception_handlers;
  282. { in 2.0 asm_exit does an exitprocess }
  283. {$ifndef ver2_0}
  284. { do cleanup required by the startup code }
  285. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  286. EntryInformation.asm_exit();
  287. {$else FPC_HAS_INDIRECT_MAIN_INFORMATION}
  288. asm_exit;
  289. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  290. {$endif ver2_0}
  291. { call exitprocess, with cleanup as required }
  292. ExitProcess(exitcode);
  293. end;
  294. var
  295. { value of the stack segment
  296. to check if the call stack can be written on exceptions }
  297. _SS : Cardinal;
  298. procedure Exe_entry(const info : TEntryInformation);[public,alias:'_FPC_EXE_Entry'];
  299. var
  300. ST : pointer;
  301. begin
  302. EntryInformation:=info;
  303. IsLibrary:=false;
  304. { install the handlers for exe only ?
  305. or should we install them for DLL also ? (PM) }
  306. install_exception_handlers;
  307. { This strange construction is needed to solve the _SS problem
  308. with a smartlinked syswin32 (PFV) }
  309. asm
  310. { allocate space for an exception frame }
  311. pushl $0
  312. pushl %fs:(0)
  313. { movl %esp,%fs:(0)
  314. but don't insert it as it doesn't
  315. point to anything yet
  316. this will be used in signals unit }
  317. movl %esp,%eax
  318. movl %eax,System_exception_frame
  319. pushl %ebp
  320. movl %esp,%eax
  321. movl %eax,st
  322. end;
  323. StackTop:=st;
  324. asm
  325. xorl %eax,%eax
  326. movw %ss,%ax
  327. movl %eax,_SS
  328. xorl %ebp,%ebp
  329. end;
  330. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  331. EntryInformation.PascalMain();
  332. {$else FPC_HAS_INDIRECT_MAIN_INFORMATION}
  333. PascalMain;
  334. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  335. asm
  336. popl %ebp
  337. end;
  338. { if we pass here there was no error ! }
  339. system_exit;
  340. end;
  341. Const
  342. { DllEntryPoint }
  343. DLL_PROCESS_ATTACH = 1;
  344. DLL_THREAD_ATTACH = 2;
  345. DLL_PROCESS_DETACH = 0;
  346. DLL_THREAD_DETACH = 3;
  347. Var
  348. DLLBuf : Jmp_buf;
  349. Const
  350. DLLExitOK : boolean = true;
  351. function Dll_entry(const info : TEntryInformation) : longbool; [public,alias:'_FPC_DLL_Entry'];
  352. var
  353. res : longbool;
  354. begin
  355. EntryInformation:=info;
  356. IsLibrary:=true;
  357. Dll_entry:=false;
  358. case DLLreason of
  359. DLL_PROCESS_ATTACH :
  360. begin
  361. If SetJmp(DLLBuf) = 0 then
  362. begin
  363. if assigned(Dll_Process_Attach_Hook) then
  364. begin
  365. res:=Dll_Process_Attach_Hook(DllParam);
  366. if not res then
  367. exit(false);
  368. end;
  369. {$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}
  370. EntryInformation.PascalMain();
  371. {$else FPC_HAS_INDIRECT_MAIN_INFORMATION}
  372. PascalMain;
  373. {$endif FPC_HAS_INDIRECT_MAIN_INFORMATION}
  374. Dll_entry:=true;
  375. end
  376. else
  377. Dll_entry:=DLLExitOK;
  378. end;
  379. DLL_THREAD_ATTACH :
  380. begin
  381. inclocked(Thread_count);
  382. { Allocate Threadvars ?!}
  383. if assigned(Dll_Thread_Attach_Hook) then
  384. Dll_Thread_Attach_Hook(DllParam);
  385. Dll_entry:=true; { return value is ignored }
  386. end;
  387. DLL_THREAD_DETACH :
  388. begin
  389. declocked(Thread_count);
  390. if assigned(Dll_Thread_Detach_Hook) then
  391. Dll_Thread_Detach_Hook(DllParam);
  392. { Release Threadvars ?!}
  393. Dll_entry:=true; { return value is ignored }
  394. end;
  395. DLL_PROCESS_DETACH :
  396. begin
  397. Dll_entry:=true; { return value is ignored }
  398. If SetJmp(DLLBuf) = 0 then
  399. FPC_Do_Exit;
  400. if assigned(Dll_Process_Detach_Hook) then
  401. Dll_Process_Detach_Hook(DllParam);
  402. end;
  403. end;
  404. end;
  405. Procedure ExitDLL(Exitcode : longint);
  406. begin
  407. DLLExitOK:=ExitCode=0;
  408. LongJmp(DLLBuf,1);
  409. end;
  410. function GetCurrentProcess : dword;
  411. stdcall;external 'kernel32' name 'GetCurrentProcess';
  412. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  413. stdcall;external 'kernel32' name 'ReadProcessMemory';
  414. function is_prefetch(p : pointer) : boolean;
  415. var
  416. a : array[0..15] of byte;
  417. doagain : boolean;
  418. instrlo,instrhi,opcode : byte;
  419. i : longint;
  420. begin
  421. result:=false;
  422. { read memory savely without causing another exeception }
  423. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  424. exit;
  425. i:=0;
  426. doagain:=true;
  427. while doagain and (i<15) do
  428. begin
  429. opcode:=a[i];
  430. instrlo:=opcode and $f;
  431. instrhi:=opcode and $f0;
  432. case instrhi of
  433. { prefix? }
  434. $20,$30:
  435. doagain:=(instrlo and 7)=6;
  436. $60:
  437. doagain:=(instrlo and $c)=4;
  438. $f0:
  439. doagain:=instrlo in [0,2,3];
  440. $0:
  441. begin
  442. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  443. exit;
  444. end;
  445. else
  446. doagain:=false;
  447. end;
  448. inc(i);
  449. end;
  450. end;
  451. //
  452. // Hardware exception handling
  453. //
  454. {$ifdef Set_i386_Exception_handler}
  455. {
  456. Error code definitions for the Win32 API functions
  457. Values are 32 bit values layed out as follows:
  458. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  459. 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
  460. +---+-+-+-----------------------+-------------------------------+
  461. |Sev|C|R| Facility | Code |
  462. +---+-+-+-----------------------+-------------------------------+
  463. where
  464. Sev - is the severity code
  465. 00 - Success
  466. 01 - Informational
  467. 10 - Warning
  468. 11 - Error
  469. C - is the Customer code flag
  470. R - is a reserved bit
  471. Facility - is the facility code
  472. Code - is the facility's status code
  473. }
  474. const
  475. SEVERITY_SUCCESS = $00000000;
  476. SEVERITY_INFORMATIONAL = $40000000;
  477. SEVERITY_WARNING = $80000000;
  478. SEVERITY_ERROR = $C0000000;
  479. const
  480. STATUS_SEGMENT_NOTIFICATION = $40000005;
  481. DBG_TERMINATE_THREAD = $40010003;
  482. DBG_TERMINATE_PROCESS = $40010004;
  483. DBG_CONTROL_C = $40010005;
  484. DBG_CONTROL_BREAK = $40010008;
  485. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  486. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  487. STATUS_BREAKPOINT = $80000003;
  488. STATUS_SINGLE_STEP = $80000004;
  489. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  490. STATUS_ACCESS_VIOLATION = $C0000005;
  491. STATUS_IN_PAGE_ERROR = $C0000006;
  492. STATUS_INVALID_HANDLE = $C0000008;
  493. STATUS_NO_MEMORY = $C0000017;
  494. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  495. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  496. STATUS_INVALID_DISPOSITION = $C0000026;
  497. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  498. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  499. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  500. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  501. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  502. STATUS_FLOAT_OVERFLOW = $C0000091;
  503. STATUS_FLOAT_STACK_CHECK = $C0000092;
  504. STATUS_FLOAT_UNDERFLOW = $C0000093;
  505. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  506. STATUS_INTEGER_OVERFLOW = $C0000095;
  507. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  508. STATUS_STACK_OVERFLOW = $C00000FD;
  509. STATUS_CONTROL_C_EXIT = $C000013A;
  510. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  511. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  512. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  513. EXCEPTION_EXECUTE_HANDLER = 1;
  514. EXCEPTION_CONTINUE_EXECUTION = -1;
  515. EXCEPTION_CONTINUE_SEARCH = 0;
  516. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  517. CONTEXT_X86 = $00010000;
  518. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  519. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  520. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  521. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  522. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  523. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  524. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  525. MAXIMUM_SUPPORTED_EXTENSION = 512;
  526. type
  527. PFloatingSaveArea = ^TFloatingSaveArea;
  528. TFloatingSaveArea = packed record
  529. ControlWord : Cardinal;
  530. StatusWord : Cardinal;
  531. TagWord : Cardinal;
  532. ErrorOffset : Cardinal;
  533. ErrorSelector : Cardinal;
  534. DataOffset : Cardinal;
  535. DataSelector : Cardinal;
  536. RegisterArea : array[0..79] of Byte;
  537. Cr0NpxState : Cardinal;
  538. end;
  539. PContext = ^TContext;
  540. TContext = packed record
  541. //
  542. // The flags values within this flag control the contents of
  543. // a CONTEXT record.
  544. //
  545. ContextFlags : Cardinal;
  546. //
  547. // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
  548. // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
  549. // included in CONTEXT_FULL.
  550. //
  551. Dr0, Dr1, Dr2,
  552. Dr3, Dr6, Dr7 : Cardinal;
  553. //
  554. // This section is specified/returned if the
  555. // ContextFlags word contains the flag CONTEXT_FLOATING_POINT.
  556. //
  557. FloatSave : TFloatingSaveArea;
  558. //
  559. // This section is specified/returned if the
  560. // ContextFlags word contains the flag CONTEXT_SEGMENTS.
  561. //
  562. SegGs, SegFs,
  563. SegEs, SegDs : Cardinal;
  564. //
  565. // This section is specified/returned if the
  566. // ContextFlags word contains the flag CONTEXT_INTEGER.
  567. //
  568. Edi, Esi, Ebx,
  569. Edx, Ecx, Eax : Cardinal;
  570. //
  571. // This section is specified/returned if the
  572. // ContextFlags word contains the flag CONTEXT_CONTROL.
  573. //
  574. Ebp : Cardinal;
  575. Eip : Cardinal;
  576. SegCs : Cardinal;
  577. EFlags, Esp, SegSs : Cardinal;
  578. //
  579. // This section is specified/returned if the ContextFlags word
  580. // contains the flag CONTEXT_EXTENDED_REGISTERS.
  581. // The format and contexts are processor specific
  582. //
  583. ExtendedRegisters : array[0..MAXIMUM_SUPPORTED_EXTENSION-1] of Byte;
  584. end;
  585. type
  586. PExceptionRecord = ^TExceptionRecord;
  587. TExceptionRecord = packed record
  588. ExceptionCode : cardinal;
  589. ExceptionFlags : Longint;
  590. ExceptionRecord : PExceptionRecord;
  591. ExceptionAddress : Pointer;
  592. NumberParameters : Longint;
  593. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
  594. end;
  595. PExceptionPointers = ^TExceptionPointers;
  596. TExceptionPointers = packed record
  597. ExceptionRecord : PExceptionRecord;
  598. ContextRecord : PContext;
  599. end;
  600. { type of functions that should be used for exception handling }
  601. TTopLevelExceptionFilter = function (excep : PExceptionPointers) : Longint;stdcall;
  602. function SetUnhandledExceptionFilter(lpTopLevelExceptionFilter : TTopLevelExceptionFilter) : TTopLevelExceptionFilter;
  603. stdcall;external 'kernel32' name 'SetUnhandledExceptionFilter';
  604. const
  605. MaxExceptionLevel = 16;
  606. exceptLevel : Byte = 0;
  607. var
  608. exceptEip : array[0..MaxExceptionLevel-1] of Longint;
  609. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  610. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  611. {$ifdef SYSTEMEXCEPTIONDEBUG}
  612. procedure DebugHandleErrorAddrFrame(error, addr, frame : longint);
  613. begin
  614. if IsConsole then
  615. begin
  616. write(stderr,'HandleErrorAddrFrame(error=',error);
  617. write(stderr,',addr=',hexstr(addr,8));
  618. writeln(stderr,',frame=',hexstr(frame,8),')');
  619. end;
  620. HandleErrorAddrFrame(error,addr,frame);
  621. end;
  622. {$endif SYSTEMEXCEPTIONDEBUG}
  623. procedure JumpToHandleErrorFrame;
  624. var
  625. eip, ebp, error : Longint;
  626. begin
  627. // save ebp
  628. asm
  629. movl (%ebp),%eax
  630. movl %eax,ebp
  631. end;
  632. if (exceptLevel > 0) then
  633. dec(exceptLevel);
  634. eip:=exceptEip[exceptLevel];
  635. error:=exceptError[exceptLevel];
  636. {$ifdef SYSTEMEXCEPTIONDEBUG}
  637. if IsConsole then
  638. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  639. {$endif SYSTEMEXCEPTIONDEBUG}
  640. if resetFPU[exceptLevel] then
  641. SysResetFPU;
  642. { build a fake stack }
  643. asm
  644. {$ifdef REGCALL}
  645. movl ebp,%ecx
  646. movl eip,%edx
  647. movl error,%eax
  648. pushl eip
  649. movl ebp,%ebp // Change frame pointer
  650. {$else}
  651. movl ebp,%eax
  652. pushl %eax
  653. movl eip,%eax
  654. pushl %eax
  655. movl error,%eax
  656. pushl %eax
  657. movl eip,%eax
  658. pushl %eax
  659. movl ebp,%ebp // Change frame pointer
  660. {$endif}
  661. {$ifdef SYSTEMEXCEPTIONDEBUG}
  662. jmpl DebugHandleErrorAddrFrame
  663. {$else not SYSTEMEXCEPTIONDEBUG}
  664. jmpl HandleErrorAddrFrame
  665. {$endif SYSTEMEXCEPTIONDEBUG}
  666. end;
  667. end;
  668. function syswin32_i386_exception_handler(excep : PExceptionPointers) : Longint;stdcall;
  669. var
  670. res: longint;
  671. err: byte;
  672. must_reset_fpu: boolean;
  673. begin
  674. res := EXCEPTION_CONTINUE_SEARCH;
  675. if excep^.ContextRecord^.SegSs=_SS then begin
  676. err := 0;
  677. must_reset_fpu := true;
  678. {$ifdef SYSTEMEXCEPTIONDEBUG}
  679. if IsConsole then Writeln(stderr,'Exception ',
  680. hexstr(excep^.ExceptionRecord^.ExceptionCode, 8));
  681. {$endif SYSTEMEXCEPTIONDEBUG}
  682. case excep^.ExceptionRecord^.ExceptionCode of
  683. STATUS_INTEGER_DIVIDE_BY_ZERO,
  684. STATUS_FLOAT_DIVIDE_BY_ZERO :
  685. err := 200;
  686. STATUS_ARRAY_BOUNDS_EXCEEDED :
  687. begin
  688. err := 201;
  689. must_reset_fpu := false;
  690. end;
  691. STATUS_STACK_OVERFLOW :
  692. begin
  693. err := 202;
  694. must_reset_fpu := false;
  695. end;
  696. STATUS_FLOAT_OVERFLOW :
  697. err := 205;
  698. STATUS_FLOAT_DENORMAL_OPERAND,
  699. STATUS_FLOAT_UNDERFLOW :
  700. err := 206;
  701. {excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  702. STATUS_FLOAT_INEXACT_RESULT,
  703. STATUS_FLOAT_INVALID_OPERATION,
  704. STATUS_FLOAT_STACK_CHECK :
  705. err := 207;
  706. STATUS_INTEGER_OVERFLOW :
  707. begin
  708. err := 215;
  709. must_reset_fpu := false;
  710. end;
  711. STATUS_ILLEGAL_INSTRUCTION:
  712. { if we're testing sse support, simply set the flag and continue }
  713. if sse_check then
  714. begin
  715. os_supports_sse:=false;
  716. { skip the offending movaps %xmm7, %xmm6 instruction }
  717. inc(excep^.ContextRecord^.Eip,3);
  718. excep^.ExceptionRecord^.ExceptionCode := 0;
  719. res:=EXCEPTION_CONTINUE_EXECUTION;
  720. end
  721. else
  722. err := 216;
  723. STATUS_ACCESS_VIOLATION:
  724. { Athlon prefetch bug? }
  725. if is_prefetch(pointer(excep^.ContextRecord^.Eip)) then
  726. begin
  727. { if yes, then retry }
  728. excep^.ExceptionRecord^.ExceptionCode := 0;
  729. res:=EXCEPTION_CONTINUE_EXECUTION;
  730. end
  731. else
  732. err := 216;
  733. STATUS_CONTROL_C_EXIT:
  734. err := 217;
  735. STATUS_PRIVILEGED_INSTRUCTION:
  736. begin
  737. err := 218;
  738. must_reset_fpu := false;
  739. end;
  740. else
  741. begin
  742. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  743. err := 217
  744. else
  745. err := 255;
  746. end;
  747. end;
  748. if (err <> 0) and (exceptLevel < MaxExceptionLevel) then begin
  749. exceptEip[exceptLevel] := excep^.ContextRecord^.Eip;
  750. exceptError[exceptLevel] := err;
  751. resetFPU[exceptLevel] := must_reset_fpu;
  752. inc(exceptLevel);
  753. excep^.ContextRecord^.Eip := Longint(@JumpToHandleErrorFrame);
  754. excep^.ExceptionRecord^.ExceptionCode := 0;
  755. res := EXCEPTION_CONTINUE_EXECUTION;
  756. {$ifdef SYSTEMEXCEPTIONDEBUG}
  757. if IsConsole then begin
  758. writeln(stderr,'Exception Continue Exception set at ',
  759. hexstr(exceptEip[exceptLevel],8));
  760. writeln(stderr,'Eip changed to ',
  761. hexstr(longint(@JumpToHandleErrorFrame),8), ' error=', error);
  762. end;
  763. {$endif SYSTEMEXCEPTIONDEBUG}
  764. end;
  765. end;
  766. syswin32_i386_exception_handler := res;
  767. end;
  768. procedure install_exception_handlers;
  769. {$ifdef SYSTEMEXCEPTIONDEBUG}
  770. var
  771. oldexceptaddr,
  772. newexceptaddr : Longint;
  773. {$endif SYSTEMEXCEPTIONDEBUG}
  774. begin
  775. {$ifdef SYSTEMEXCEPTIONDEBUG}
  776. asm
  777. movl $0,%eax
  778. movl %fs:(%eax),%eax
  779. movl %eax,oldexceptaddr
  780. end;
  781. {$endif SYSTEMEXCEPTIONDEBUG}
  782. SetUnhandledExceptionFilter(@syswin32_i386_exception_handler);
  783. {$ifdef SYSTEMEXCEPTIONDEBUG}
  784. asm
  785. movl $0,%eax
  786. movl %fs:(%eax),%eax
  787. movl %eax,newexceptaddr
  788. end;
  789. if IsConsole then
  790. writeln(stderr,'Old exception ',hexstr(oldexceptaddr,8),
  791. ' new exception ',hexstr(newexceptaddr,8));
  792. {$endif SYSTEMEXCEPTIONDEBUG}
  793. end;
  794. procedure remove_exception_handlers;
  795. begin
  796. SetUnhandledExceptionFilter(nil);
  797. end;
  798. {$else not cpui386 (Processor specific !!)}
  799. procedure install_exception_handlers;
  800. begin
  801. end;
  802. procedure remove_exception_handlers;
  803. begin
  804. end;
  805. {$endif Set_i386_Exception_handler}
  806. const
  807. { MultiByteToWideChar }
  808. MB_PRECOMPOSED = 1;
  809. CP_ACP = 0;
  810. WC_NO_BEST_FIT_CHARS = $400;
  811. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  812. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  813. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  814. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  815. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  816. stdcall; external 'user32' name 'CharUpperBuffW';
  817. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  818. stdcall; external 'user32' name 'CharLowerBuffW';
  819. {******************************************************************************
  820. Widestring
  821. ******************************************************************************}
  822. procedure Win32Wide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt);
  823. var
  824. destlen: SizeInt;
  825. begin
  826. // retrieve length including trailing #0
  827. // not anymore, because this must also be usable for single characters
  828. destlen:=WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, source, len, nil, 0, nil, nil);
  829. // this will null-terminate
  830. setlength(dest, destlen);
  831. WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, source, len, @dest[1], destlen, nil, nil);
  832. end;
  833. procedure Win32Ansi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
  834. var
  835. destlen: SizeInt;
  836. begin
  837. // retrieve length including trailing #0
  838. // not anymore, because this must also be usable for single characters
  839. destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, nil, 0);
  840. // this will null-terminate
  841. setlength(dest, destlen);
  842. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, @dest[1], destlen);
  843. end;
  844. function Win32WideUpper(const s : WideString) : WideString;
  845. begin
  846. result:=s;
  847. if length(result)>0 then
  848. CharUpperBuff(LPWSTR(result),length(result));
  849. end;
  850. function Win32WideLower(const s : WideString) : WideString;
  851. begin
  852. result:=s;
  853. if length(result)>0 then
  854. CharLowerBuff(LPWSTR(result),length(result));
  855. end;
  856. {******************************************************************************}
  857. { include code common with win64 }
  858. {$I syswin.inc}
  859. {******************************************************************************}
  860. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  861. type
  862. tdosheader = packed record
  863. e_magic : word;
  864. e_cblp : word;
  865. e_cp : word;
  866. e_crlc : word;
  867. e_cparhdr : word;
  868. e_minalloc : word;
  869. e_maxalloc : word;
  870. e_ss : word;
  871. e_sp : word;
  872. e_csum : word;
  873. e_ip : word;
  874. e_cs : word;
  875. e_lfarlc : word;
  876. e_ovno : word;
  877. e_res : array[0..3] of word;
  878. e_oemid : word;
  879. e_oeminfo : word;
  880. e_res2 : array[0..9] of word;
  881. e_lfanew : longint;
  882. end;
  883. tpeheader = packed record
  884. PEMagic : longint;
  885. Machine : word;
  886. NumberOfSections : word;
  887. TimeDateStamp : longint;
  888. PointerToSymbolTable : longint;
  889. NumberOfSymbols : longint;
  890. SizeOfOptionalHeader : word;
  891. Characteristics : word;
  892. Magic : word;
  893. MajorLinkerVersion : byte;
  894. MinorLinkerVersion : byte;
  895. SizeOfCode : longint;
  896. SizeOfInitializedData : longint;
  897. SizeOfUninitializedData : longint;
  898. AddressOfEntryPoint : longint;
  899. BaseOfCode : longint;
  900. BaseOfData : longint;
  901. ImageBase : longint;
  902. SectionAlignment : longint;
  903. FileAlignment : longint;
  904. MajorOperatingSystemVersion : word;
  905. MinorOperatingSystemVersion : word;
  906. MajorImageVersion : word;
  907. MinorImageVersion : word;
  908. MajorSubsystemVersion : word;
  909. MinorSubsystemVersion : word;
  910. Reserved1 : longint;
  911. SizeOfImage : longint;
  912. SizeOfHeaders : longint;
  913. CheckSum : longint;
  914. Subsystem : word;
  915. DllCharacteristics : word;
  916. SizeOfStackReserve : longint;
  917. SizeOfStackCommit : longint;
  918. SizeOfHeapReserve : longint;
  919. SizeOfHeapCommit : longint;
  920. LoaderFlags : longint;
  921. NumberOfRvaAndSizes : longint;
  922. DataDirectory : array[1..$80] of byte;
  923. end;
  924. begin
  925. result:=tpeheader((pointer(SysInstance)+(tdosheader(pointer(SysInstance)^).e_lfanew))^).SizeOfStackReserve;
  926. end;
  927. initialization
  928. { get some helpful informations }
  929. GetStartupInfo(@startupinfo);
  930. SysResetFPU;
  931. if not(IsLibrary) then
  932. SysInitFPU;
  933. { some misc Win32 stuff }
  934. hprevinst:=0;
  935. if not IsLibrary then
  936. SysInstance:=getmodulehandle(nil);
  937. MainInstance:=SysInstance;
  938. { pass dummy value }
  939. StackLength := CheckInitialStkLen($1000000);
  940. StackBottom := StackTop - StackLength;
  941. cmdshow:=startupinfo.wshowwindow;
  942. { Setup heap }
  943. InitHeap;
  944. SysInitExceptions;
  945. { setup fastmove stuff }
  946. fpc_cpucodeinit;
  947. SetupProcVars;
  948. { Reset IO Error }
  949. InOutRes:=0;
  950. ProcessID := GetCurrentProcessID;
  951. { threading }
  952. InitSystemThreads;
  953. { Reset internal error variable }
  954. errno:=0;
  955. initvariantmanager;
  956. initwidestringmanager;
  957. {$ifndef VER2_2}
  958. initunicodestringmanager;
  959. {$endif VER2_2}
  960. InitWin32Widestrings;
  961. DispCallByIDProc:=@DoDispCallByIDError;
  962. SysInitStdIO;
  963. finalization
  964. SysFreeMem(FArgs);
  965. SysFreeMem(FArgv);
  966. end.