system.pp 31 KB

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