system.pp 33 KB

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