system.pp 30 KB

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