system.pp 31 KB

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