system.pp 32 KB

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