system.pp 31 KB

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