system.pp 33 KB

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