system.pp 31 KB

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