system.pp 30 KB

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