system.pp 30 KB

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