system.pp 31 KB

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