system.pp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133
  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. {$define DISABLE_NO_THREAD_MANAGER}
  21. { include system-independent routine headers }
  22. {$I systemh.inc}
  23. const
  24. LineEnding = #13#10;
  25. LFNSupport = true;
  26. DirectorySeparator = '\';
  27. DriveSeparator = ':';
  28. PathSeparator = ';';
  29. { FileNameCaseSensitive is defined separately below!!! }
  30. maxExitCode = 65535;
  31. MaxPathLen = 260;
  32. type
  33. PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
  34. TEXCEPTION_FRAME = record
  35. next : PEXCEPTION_FRAME;
  36. handler : pointer;
  37. end;
  38. const
  39. { Default filehandles }
  40. UnusedHandle : THandle = -1;
  41. StdInputHandle : THandle = 0;
  42. StdOutputHandle : THandle = 0;
  43. StdErrorHandle : THandle = 0;
  44. FileNameCaseSensitive : boolean = true;
  45. CtrlZMarksEOF: boolean = true; (* #26 not considered as end of file *)
  46. sLineBreak = LineEnding;
  47. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  48. { Thread count for DLL }
  49. Thread_count : longint = 0;
  50. System_exception_frame : PEXCEPTION_FRAME =nil;
  51. type
  52. TStartupInfo=packed record
  53. cb : longint;
  54. lpReserved : Pointer;
  55. lpDesktop : Pointer;
  56. lpTitle : Pointer;
  57. dwX : longint;
  58. dwY : longint;
  59. dwXSize : longint;
  60. dwYSize : longint;
  61. dwXCountChars : longint;
  62. dwYCountChars : longint;
  63. dwFillAttribute : longint;
  64. dwFlags : longint;
  65. wShowWindow : Word;
  66. cbReserved2 : Word;
  67. lpReserved2 : Pointer;
  68. hStdInput : longint;
  69. hStdOutput : longint;
  70. hStdError : longint;
  71. end;
  72. var
  73. { C compatible arguments }
  74. argc : longint;
  75. argv : ppchar;
  76. { Win32 Info }
  77. startupinfo : tstartupinfo;
  78. hprevinst,
  79. MainInstance,
  80. cmdshow : longint;
  81. DLLreason,DLLparam:longint;
  82. StartupConsoleMode : DWORD;
  83. type
  84. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  85. TDLL_Entry_Hook = procedure (dllparam : longint);
  86. const
  87. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  88. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  89. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  90. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  91. implementation
  92. var
  93. SysInstance : Longint;public name '_FPC_SysInstance';
  94. {$ifdef CPUI386}
  95. {$define HAS_RESOURCES}
  96. {$i winres.inc}
  97. {$endif}
  98. { used by wstrings.inc because wstrings.inc is included before sysos.inc
  99. this is put here (FK) }
  100. function SysAllocStringLen(psz:pointer;len:dword):pointer;stdcall;
  101. external 'oleaut32.dll' name 'SysAllocStringLen';
  102. procedure SysFreeString(bstr:pointer);stdcall;
  103. external 'oleaut32.dll' name 'SysFreeString';
  104. function SysReAllocStringLen(var bstr:pointer;psz: pointer;
  105. len:dword): Integer; stdcall;external 'oleaut32.dll' name 'SysReAllocStringLen';
  106. { include system independent routines }
  107. {$I system.inc}
  108. {*****************************************************************************
  109. Parameter Handling
  110. *****************************************************************************}
  111. var
  112. ModuleName : array[0..255] of char;
  113. function GetCommandFile:pchar;
  114. begin
  115. GetModuleFileName(0,@ModuleName,255);
  116. GetCommandFile:=@ModuleName;
  117. end;
  118. procedure setup_arguments;
  119. var
  120. arglen,
  121. count : longint;
  122. argstart,
  123. pc,arg : pchar;
  124. quote : char;
  125. argvlen : longint;
  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. pc:=getcommandfile;
  150. Arglen:=0;
  151. repeat
  152. Inc(Arglen);
  153. until (pc[Arglen]=#0);
  154. allocarg(count,arglen);
  155. move(pc^,argv[count]^,arglen+1);
  156. { Setup cmdline variable }
  157. cmdline:=GetCommandLine;
  158. { process arguments }
  159. pc:=cmdline;
  160. {$IfDef SYSTEM_DEBUG_STARTUP}
  161. Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
  162. {$EndIf }
  163. while pc^<>#0 do
  164. begin
  165. { skip leading spaces }
  166. while pc^ in [#1..#32] do
  167. inc(pc);
  168. if pc^=#0 then
  169. break;
  170. { calc argument length }
  171. quote:=' ';
  172. argstart:=pc;
  173. arglen:=0;
  174. while (pc^<>#0) do
  175. begin
  176. case pc^ of
  177. #1..#32 :
  178. begin
  179. if quote<>' ' then
  180. inc(arglen)
  181. else
  182. break;
  183. end;
  184. '"' :
  185. if pchar(pc+1)^<>'"' then
  186. begin
  187. if quote='"' then
  188. quote:=' '
  189. else
  190. quote:='"';
  191. end
  192. else
  193. inc(pc);
  194. else
  195. inc(arglen);
  196. end;
  197. inc(pc);
  198. end;
  199. { copy argument }
  200. { Don't copy the first one, it is already there.}
  201. If Count<>0 then
  202. begin
  203. allocarg(count,arglen);
  204. quote:=' ';
  205. pc:=argstart;
  206. arg:=argv[count];
  207. while (pc^<>#0) do
  208. begin
  209. case pc^ of
  210. #1..#32 :
  211. begin
  212. if quote<>' ' then
  213. begin
  214. arg^:=pc^;
  215. inc(arg);
  216. end
  217. else
  218. break;
  219. end;
  220. '"' :
  221. if pchar(pc+1)^<>'"' then
  222. begin
  223. if quote='"' then
  224. quote:=' '
  225. else
  226. quote:='"';
  227. end
  228. else
  229. inc(pc);
  230. else
  231. begin
  232. arg^:=pc^;
  233. inc(arg);
  234. end;
  235. end;
  236. inc(pc);
  237. end;
  238. arg^:=#0;
  239. end;
  240. {$IfDef SYSTEM_DEBUG_STARTUP}
  241. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  242. {$EndIf SYSTEM_DEBUG_STARTUP}
  243. inc(count);
  244. end;
  245. { get argc and create an nil entry }
  246. argc:=count;
  247. allocarg(argc,0);
  248. { free unused memory }
  249. sysreallocmem(argv,(argc+1)*sizeof(pointer));
  250. end;
  251. function paramcount : longint;
  252. begin
  253. paramcount := argc - 1;
  254. end;
  255. function paramstr(l : longint) : string;
  256. begin
  257. if (l>=0) and (l<argc) then
  258. paramstr:=strpas(argv[l])
  259. else
  260. paramstr:='';
  261. end;
  262. procedure randomize;
  263. begin
  264. randseed:=GetTickCount;
  265. end;
  266. {*****************************************************************************
  267. System Dependent Exit code
  268. *****************************************************************************}
  269. procedure install_exception_handlers;forward;
  270. procedure remove_exception_handlers;forward;
  271. procedure PascalMain;stdcall;external name 'PASCALMAIN';
  272. procedure fpc_do_exit;stdcall;external name 'FPC_DO_EXIT';
  273. Procedure ExitDLL(Exitcode : longint); forward;
  274. procedure asm_exit;stdcall;external name 'asm_exit';
  275. Procedure system_exit;
  276. begin
  277. { don't call ExitProcess inside
  278. the DLL exit code !!
  279. This crashes Win95 at least PM }
  280. if IsLibrary then
  281. ExitDLL(ExitCode);
  282. if not IsConsole then
  283. begin
  284. Close(stderr);
  285. Close(stdout);
  286. Close(erroutput);
  287. Close(Input);
  288. Close(Output);
  289. { what about Input and Output ?? PM }
  290. { now handled, FPK }
  291. end;
  292. remove_exception_handlers;
  293. { in 2.0 asm_exit does an exitprocess }
  294. {$ifndef ver2_0}
  295. { do cleanup required by the startup code }
  296. asm_exit;
  297. {$endif ver2_0}
  298. { call exitprocess, with cleanup as required }
  299. ExitProcess(exitcode);
  300. end;
  301. var
  302. { value of the stack segment
  303. to check if the call stack can be written on exceptions }
  304. _SS : Cardinal;
  305. procedure Exe_entry;[public,alias:'_FPC_EXE_Entry'];
  306. var
  307. ST : pointer;
  308. begin
  309. IsLibrary:=false;
  310. { install the handlers for exe only ?
  311. or should we install them for DLL also ? (PM) }
  312. install_exception_handlers;
  313. { This strange construction is needed to solve the _SS problem
  314. with a smartlinked syswin32 (PFV) }
  315. asm
  316. { allocate space for an exception frame }
  317. pushl $0
  318. pushl %fs:(0)
  319. { movl %esp,%fs:(0)
  320. but don't insert it as it doesn't
  321. point to anything yet
  322. this will be used in signals unit }
  323. movl %esp,%eax
  324. movl %eax,System_exception_frame
  325. pushl %ebp
  326. movl %esp,%eax
  327. movl %eax,st
  328. end;
  329. StackTop:=st;
  330. asm
  331. xorl %eax,%eax
  332. movw %ss,%ax
  333. movl %eax,_SS
  334. call SysResetFPU
  335. xorl %ebp,%ebp
  336. call PASCALMAIN
  337. popl %ebp
  338. end;
  339. { if we pass here there was no error ! }
  340. system_exit;
  341. end;
  342. Const
  343. { DllEntryPoint }
  344. DLL_PROCESS_ATTACH = 1;
  345. DLL_THREAD_ATTACH = 2;
  346. DLL_PROCESS_DETACH = 0;
  347. DLL_THREAD_DETACH = 3;
  348. Var
  349. DLLBuf : Jmp_buf;
  350. Const
  351. DLLExitOK : boolean = true;
  352. function Dll_entry : longbool; [public,alias:'_FPC_DLL_Entry'];
  353. var
  354. res : longbool;
  355. begin
  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. PASCALMAIN;
  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. {$warning 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. {$warning 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. {****************************************************************************
  803. OS dependend widestrings
  804. ****************************************************************************}
  805. const
  806. { MultiByteToWideChar }
  807. MB_PRECOMPOSED = 1;
  808. CP_ACP = 0;
  809. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  810. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  811. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  812. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  813. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  814. stdcall; external 'user32' name 'CharUpperBuffW';
  815. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  816. stdcall; external 'user32' name 'CharLowerBuffW';
  817. procedure Win32Wide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt);
  818. var
  819. destlen: SizeInt;
  820. begin
  821. // retrieve length including trailing #0
  822. destlen:=WideCharToMultiByte(CP_ACP, 0, source, len+1, nil, 0, nil, nil);
  823. setlength(dest, destlen-1);
  824. WideCharToMultiByte(CP_ACP, 0, source, len+1, @dest[1], destlen, nil, nil);
  825. end;
  826. procedure Win32Ansi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
  827. var
  828. destlen: SizeInt;
  829. begin
  830. // retrieve length including trailing #0
  831. destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len+1, nil, 0);
  832. setlength(dest, destlen-1);
  833. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len+1, @dest[1], destlen);
  834. end;
  835. function Win32WideUpper(const s : WideString) : WideString;
  836. begin
  837. result:=s;
  838. UniqueString(result);
  839. if length(result)>0 then
  840. CharUpperBuff(LPWSTR(result),length(result));
  841. end;
  842. function Win32WideLower(const s : WideString) : WideString;
  843. begin
  844. result:=s;
  845. UniqueString(result);
  846. if length(result)>0 then
  847. CharLowerBuff(LPWSTR(result),length(result));
  848. end;
  849. { there is a similiar procedure in sysutils which inits the fields which
  850. are only relevant for the sysutils units }
  851. procedure InitWin32Widestrings;
  852. begin
  853. widestringmanager.Wide2AnsiMoveProc:=@Win32Wide2AnsiMove;
  854. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  855. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  856. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  857. end;
  858. {****************************************************************************
  859. Error Message writing using messageboxes
  860. ****************************************************************************}
  861. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  862. stdcall;external 'user32' name 'MessageBoxA';
  863. const
  864. ErrorBufferLength = 1024;
  865. var
  866. ErrorBuf : array[0..ErrorBufferLength] of char;
  867. ErrorLen : longint;
  868. Function ErrorWrite(Var F: TextRec): Integer;
  869. {
  870. An error message should always end with #13#10#13#10
  871. }
  872. var
  873. p : pchar;
  874. i : longint;
  875. Begin
  876. if F.BufPos>0 then
  877. begin
  878. if F.BufPos+ErrorLen>ErrorBufferLength then
  879. i:=ErrorBufferLength-ErrorLen
  880. else
  881. i:=F.BufPos;
  882. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  883. inc(ErrorLen,i);
  884. ErrorBuf[ErrorLen]:=#0;
  885. end;
  886. if ErrorLen>3 then
  887. begin
  888. p:=@ErrorBuf[ErrorLen];
  889. for i:=1 to 4 do
  890. begin
  891. dec(p);
  892. if not(p^ in [#10,#13]) then
  893. break;
  894. end;
  895. end;
  896. if ErrorLen=ErrorBufferLength then
  897. i:=4;
  898. if (i=4) then
  899. begin
  900. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  901. ErrorLen:=0;
  902. end;
  903. F.BufPos:=0;
  904. ErrorWrite:=0;
  905. End;
  906. Function ErrorClose(Var F: TextRec): Integer;
  907. begin
  908. if ErrorLen>0 then
  909. begin
  910. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  911. ErrorLen:=0;
  912. end;
  913. ErrorLen:=0;
  914. ErrorClose:=0;
  915. end;
  916. Function ErrorOpen(Var F: TextRec): Integer;
  917. Begin
  918. TextRec(F).InOutFunc:=@ErrorWrite;
  919. TextRec(F).FlushFunc:=@ErrorWrite;
  920. TextRec(F).CloseFunc:=@ErrorClose;
  921. ErrorOpen:=0;
  922. End;
  923. procedure AssignError(Var T: Text);
  924. begin
  925. Assign(T,'');
  926. TextRec(T).OpenFunc:=@ErrorOpen;
  927. Rewrite(T);
  928. end;
  929. procedure SysInitStdIO;
  930. begin
  931. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  932. displayed in a messagebox }
  933. StdInputHandle:=longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  934. StdOutputHandle:=longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  935. StdErrorHandle:=longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  936. if not IsConsole then
  937. begin
  938. AssignError(stderr);
  939. AssignError(stdout);
  940. Assign(Output,'');
  941. Assign(Input,'');
  942. Assign(ErrOutput,'');
  943. end
  944. else
  945. begin
  946. OpenStdIO(Input,fmInput,StdInputHandle);
  947. OpenStdIO(Output,fmOutput,StdOutputHandle);
  948. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  949. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  950. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  951. end;
  952. end;
  953. (* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
  954. var
  955. ProcessID: SizeUInt;
  956. function GetProcessID: SizeUInt;
  957. begin
  958. GetProcessID := ProcessID;
  959. end;
  960. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  961. begin
  962. result := stklen;
  963. end;
  964. {
  965. const
  966. Exe_entry_code : pointer = @Exe_entry;
  967. Dll_entry_code : pointer = @Dll_entry;
  968. }
  969. begin
  970. StackLength := CheckInitialStkLen(InitialStkLen);
  971. StackBottom := StackTop - StackLength;
  972. { get some helpful informations }
  973. GetStartupInfo(@startupinfo);
  974. { some misc Win32 stuff }
  975. hprevinst:=0;
  976. if not IsLibrary then
  977. SysInstance:=getmodulehandle(GetCommandFile);
  978. MainInstance:=HInstance;
  979. cmdshow:=startupinfo.wshowwindow;
  980. { Setup heap }
  981. InitHeap;
  982. SysInitExceptions;
  983. { setup fastmove stuff }
  984. fpc_cpucodeinit;
  985. SysInitStdIO;
  986. { Arguments }
  987. setup_arguments;
  988. { Reset IO Error }
  989. InOutRes:=0;
  990. ProcessID := GetCurrentProcessID;
  991. { threading }
  992. InitSystemThreads;
  993. { Reset internal error variable }
  994. errno:=0;
  995. initvariantmanager;
  996. initwidestringmanager;
  997. InitWin32Widestrings;
  998. DispCallByIDProc:=@DoDispCallByIDError;
  999. end.