system.pp 31 KB

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