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. { 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. type
  30. PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
  31. TEXCEPTION_FRAME = record
  32. next : PEXCEPTION_FRAME;
  33. handler : pointer;
  34. end;
  35. const
  36. { Default filehandles }
  37. UnusedHandle : THandle = THandle(-1);
  38. StdInputHandle : THandle = 0;
  39. StdOutputHandle : THandle = 0;
  40. StdErrorHandle : THandle = 0;
  41. FileNameCaseSensitive : boolean = true;
  42. CtrlZMarksEOF: boolean = true; (* #26 not considered as end of file *)
  43. sLineBreak = LineEnding;
  44. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  45. { Thread count for DLL }
  46. Thread_count : longint = 0;
  47. type
  48. TStartupInfo = record
  49. cb : longint;
  50. lpReserved : Pointer;
  51. lpDesktop : Pointer;
  52. lpTitle : Pointer;
  53. dwX : longint;
  54. dwY : longint;
  55. dwXSize : longint;
  56. dwYSize : longint;
  57. dwXCountChars : longint;
  58. dwYCountChars : longint;
  59. dwFillAttribute : longint;
  60. dwFlags : longint;
  61. wShowWindow : Word;
  62. cbReserved2 : Word;
  63. lpReserved2 : Pointer;
  64. hStdInput : THandle;
  65. hStdOutput : THandle;
  66. hStdError : THandle;
  67. end;
  68. var
  69. { C compatible arguments }
  70. argc : longint;
  71. argv : ppchar;
  72. { Win32 Info }
  73. startupinfo : tstartupinfo;
  74. hprevinst,
  75. MainInstance,
  76. cmdshow : longint;
  77. DLLreason,DLLparam:longint;
  78. type
  79. TDLL_Process_Entry_Hook = function (dllparam : longint) : longbool;
  80. TDLL_Entry_Hook = procedure (dllparam : longint);
  81. const
  82. Dll_Process_Attach_Hook : TDLL_Process_Entry_Hook = nil;
  83. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  84. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  85. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  86. implementation
  87. var
  88. SysInstance : Longint;public;
  89. {$ifdef i386}
  90. {$define HAS_RESOURCES}
  91. {$i win32res.inc}
  92. {$endif}
  93. { used by wstrings.inc because wstrings.inc is included before sysos.inc
  94. this is put here (FK) }
  95. function SysAllocStringLen(psz:pointer;len:dword):pointer;stdcall;
  96. external 'oleaut32.dll' name 'SysAllocStringLen';
  97. procedure SysFreeString(bstr:pointer);stdcall;
  98. external 'oleaut32.dll' name 'SysFreeString';
  99. function SysReAllocStringLen(var bstr:pointer;psz: pointer;
  100. len:dword): Integer; stdcall;external 'oleaut32.dll' name 'SysReAllocStringLen';
  101. { include system independent routines }
  102. {$I system.inc}
  103. {*****************************************************************************
  104. Parameter Handling
  105. *****************************************************************************}
  106. var
  107. ModuleName : array[0..255] of char;
  108. function GetCommandFile:pchar;
  109. begin
  110. GetModuleFileName(0,@ModuleName,255);
  111. GetCommandFile:=@ModuleName;
  112. end;
  113. procedure setup_arguments;
  114. var
  115. arglen,
  116. count : longint;
  117. argstart,
  118. pc,arg : pchar;
  119. quote : char;
  120. argvlen : longint;
  121. procedure allocarg(idx,len:longint);
  122. var
  123. oldargvlen : longint;
  124. begin
  125. if idx>=argvlen then
  126. begin
  127. oldargvlen:=argvlen;
  128. argvlen:=(idx+8) and (not 7);
  129. sysreallocmem(argv,argvlen*sizeof(pointer));
  130. fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);
  131. end;
  132. { use realloc to reuse already existing memory }
  133. { always allocate, even if length is zero, since }
  134. { the arg. is still present! }
  135. sysreallocmem(argv[idx],len+1);
  136. end;
  137. begin
  138. SetupProcVars;
  139. { create commandline, it starts with the executed filename which is argv[0] }
  140. { Win32 passes the command NOT via the args, but via getmodulefilename}
  141. count:=0;
  142. argv:=nil;
  143. argvlen:=0;
  144. pc:=getcommandfile;
  145. Arglen:=0;
  146. repeat
  147. Inc(Arglen);
  148. until (pc[Arglen]=#0);
  149. allocarg(count,arglen);
  150. move(pc^,argv[count]^,arglen+1);
  151. { Setup cmdline variable }
  152. cmdline:=GetCommandLine;
  153. { process arguments }
  154. pc:=cmdline;
  155. {$IfDef SYSTEM_DEBUG_STARTUP}
  156. Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
  157. {$EndIf }
  158. while pc^<>#0 do
  159. begin
  160. { skip leading spaces }
  161. while pc^ in [#1..#32] do
  162. inc(pc);
  163. if pc^=#0 then
  164. break;
  165. { calc argument length }
  166. quote:=' ';
  167. argstart:=pc;
  168. arglen:=0;
  169. while (pc^<>#0) do
  170. begin
  171. case pc^ of
  172. #1..#32 :
  173. begin
  174. if quote<>' ' then
  175. inc(arglen)
  176. else
  177. break;
  178. end;
  179. '"' :
  180. begin
  181. if quote<>'''' then
  182. begin
  183. if pchar(pc+1)^<>'"' then
  184. begin
  185. if quote='"' then
  186. quote:=' '
  187. else
  188. quote:='"';
  189. end
  190. else
  191. inc(pc);
  192. end
  193. else
  194. inc(arglen);
  195. end;
  196. '''' :
  197. begin
  198. if quote<>'"' then
  199. begin
  200. if pchar(pc+1)^<>'''' then
  201. begin
  202. if quote='''' then
  203. quote:=' '
  204. else
  205. quote:='''';
  206. end
  207. else
  208. inc(pc);
  209. end
  210. else
  211. inc(arglen);
  212. end;
  213. else
  214. inc(arglen);
  215. end;
  216. inc(pc);
  217. end;
  218. { copy argument }
  219. { Don't copy the first one, it is already there.}
  220. If Count<>0 then
  221. begin
  222. allocarg(count,arglen);
  223. quote:=' ';
  224. pc:=argstart;
  225. arg:=argv[count];
  226. while (pc^<>#0) do
  227. begin
  228. case pc^ of
  229. #1..#32 :
  230. begin
  231. if quote<>' ' then
  232. begin
  233. arg^:=pc^;
  234. inc(arg);
  235. end
  236. else
  237. break;
  238. end;
  239. '"' :
  240. begin
  241. if quote<>'''' then
  242. begin
  243. if pchar(pc+1)^<>'"' then
  244. begin
  245. if quote='"' then
  246. quote:=' '
  247. else
  248. quote:='"';
  249. end
  250. else
  251. inc(pc);
  252. end
  253. else
  254. begin
  255. arg^:=pc^;
  256. inc(arg);
  257. end;
  258. end;
  259. '''' :
  260. begin
  261. if quote<>'"' then
  262. begin
  263. if pchar(pc+1)^<>'''' then
  264. begin
  265. if quote='''' then
  266. quote:=' '
  267. else
  268. quote:='''';
  269. end
  270. else
  271. inc(pc);
  272. end
  273. else
  274. begin
  275. arg^:=pc^;
  276. inc(arg);
  277. end;
  278. end;
  279. else
  280. begin
  281. arg^:=pc^;
  282. inc(arg);
  283. end;
  284. end;
  285. inc(pc);
  286. end;
  287. arg^:=#0;
  288. end;
  289. {$IfDef SYSTEM_DEBUG_STARTUP}
  290. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  291. {$EndIf SYSTEM_DEBUG_STARTUP}
  292. inc(count);
  293. end;
  294. { get argc and create an nil entry }
  295. argc:=count;
  296. allocarg(argc,0);
  297. { free unused memory }
  298. sysreallocmem(argv,(argc+1)*sizeof(pointer));
  299. end;
  300. function paramcount : longint;
  301. begin
  302. paramcount := argc - 1;
  303. end;
  304. function paramstr(l : longint) : string;
  305. begin
  306. if (l>=0) and (l<argc) then
  307. paramstr:=strpas(argv[l])
  308. else
  309. paramstr:='';
  310. end;
  311. procedure randomize;
  312. begin
  313. randseed:=GetTickCount;
  314. end;
  315. {*****************************************************************************
  316. System Dependent Exit code
  317. *****************************************************************************}
  318. procedure install_exception_handlers;forward;
  319. procedure remove_exception_handlers;forward;
  320. procedure PascalMain;stdcall;external name 'PASCALMAIN';
  321. procedure fpc_do_exit;stdcall;external name 'FPC_DO_EXIT';
  322. Procedure ExitDLL(Exitcode : longint); forward;
  323. Procedure system_exit;
  324. begin
  325. { don't call ExitProcess inside
  326. the DLL exit code !!
  327. This crashes Win95 at least PM }
  328. if IsLibrary then
  329. ExitDLL(ExitCode);
  330. if not IsConsole then
  331. begin
  332. Close(stderr);
  333. Close(stdout);
  334. Close(erroutput);
  335. Close(Input);
  336. Close(Output);
  337. { what about Input and Output ?? PM }
  338. { now handled, FPK }
  339. end;
  340. remove_exception_handlers;
  341. { call exitprocess, with cleanup as required }
  342. ExitProcess(exitcode);
  343. end;
  344. var
  345. { old compilers emitted a reference to _fltused if a module contains
  346. floating type code so the linker could leave away floating point
  347. libraries or not. VC does this as well so we need to define this
  348. symbol as well (FK)
  349. }
  350. _fltused : int64;cvar;public;
  351. { value of the stack segment
  352. to check if the call stack can be written on exceptions }
  353. _SS : Cardinal;
  354. procedure Exe_entry;[public,alias:'_FPC_EXE_Entry'];
  355. var
  356. ST : pointer;
  357. begin
  358. IsLibrary:=false;
  359. { install the handlers for exe only ?
  360. or should we install them for DLL also ? (PM) }
  361. install_exception_handlers;
  362. ExitCode:=0;
  363. asm
  364. { keep stack aligned }
  365. pushq $0
  366. pushq %rbp
  367. movq %rsp,%rax
  368. movq %rax,st
  369. end;
  370. StackTop:=st;
  371. asm
  372. xorl %rax,%rax
  373. movw %ss,%ax
  374. movl %eax,_SS
  375. call SysResetFPU
  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,_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,_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. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  853. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  854. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  855. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  856. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  857. stdcall; external 'user32' name 'CharUpperBuffW';
  858. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  859. stdcall; external 'user32' name 'CharLowerBuffW';
  860. procedure Win32Wide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt);
  861. var
  862. destlen: SizeInt;
  863. begin
  864. // retrieve length including trailing #0
  865. destlen:=WideCharToMultiByte(CP_ACP, 0, source, len+1, nil, 0, nil, nil);
  866. setlength(dest, destlen-1);
  867. WideCharToMultiByte(CP_ACP, 0, source, len+1, @dest[1], destlen, nil, nil);
  868. end;
  869. procedure Win32Ansi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
  870. var
  871. destlen: SizeInt;
  872. begin
  873. // retrieve length including trailing #0
  874. destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len+1, nil, 0);
  875. setlength(dest, destlen-1);
  876. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len+1, @dest[1], destlen);
  877. end;
  878. function Win32WideUpper(const s : WideString) : WideString;
  879. begin
  880. result:=s;
  881. UniqueString(result);
  882. if length(result)>0 then
  883. CharUpperBuff(LPWSTR(result),length(result));
  884. end;
  885. function Win32WideLower(const s : WideString) : WideString;
  886. begin
  887. result:=s;
  888. UniqueString(result);
  889. if length(result)>0 then
  890. CharLowerBuff(LPWSTR(result),length(result));
  891. end;
  892. { there is a similiar procedure in sysutils which inits the fields which
  893. are only relevant for the sysutils units }
  894. procedure InitWin32Widestrings;
  895. begin
  896. widestringmanager.Wide2AnsiMoveProc:=@Win32Wide2AnsiMove;
  897. widestringmanager.Ansi2WideMoveProc:=@Win32Ansi2WideMove;
  898. widestringmanager.UpperWideStringProc:=@Win32WideUpper;
  899. widestringmanager.LowerWideStringProc:=@Win32WideLower;
  900. end;
  901. {****************************************************************************
  902. Error Message writing using messageboxes
  903. ****************************************************************************}
  904. function MessageBox(w1:longint;l1,l2:pointer;w2:longint):longint;
  905. stdcall;external 'user32' name 'MessageBoxA';
  906. const
  907. ErrorBufferLength = 1024;
  908. var
  909. ErrorBuf : array[0..ErrorBufferLength] of char;
  910. ErrorLen : longint;
  911. Function ErrorWrite(Var F: TextRec): Integer;
  912. {
  913. An error message should always end with #13#10#13#10
  914. }
  915. var
  916. p : pchar;
  917. i : longint;
  918. Begin
  919. if F.BufPos>0 then
  920. begin
  921. if F.BufPos+ErrorLen>ErrorBufferLength then
  922. i:=ErrorBufferLength-ErrorLen
  923. else
  924. i:=F.BufPos;
  925. Move(F.BufPtr^,ErrorBuf[ErrorLen],i);
  926. inc(ErrorLen,i);
  927. ErrorBuf[ErrorLen]:=#0;
  928. end;
  929. if ErrorLen>3 then
  930. begin
  931. p:=@ErrorBuf[ErrorLen];
  932. for i:=1 to 4 do
  933. begin
  934. dec(p);
  935. if not(p^ in [#10,#13]) then
  936. break;
  937. end;
  938. end;
  939. if ErrorLen=ErrorBufferLength then
  940. i:=4;
  941. if (i=4) then
  942. begin
  943. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  944. ErrorLen:=0;
  945. end;
  946. F.BufPos:=0;
  947. ErrorWrite:=0;
  948. End;
  949. Function ErrorClose(Var F: TextRec): Integer;
  950. begin
  951. if ErrorLen>0 then
  952. begin
  953. MessageBox(0,@ErrorBuf,pchar('Error'),0);
  954. ErrorLen:=0;
  955. end;
  956. ErrorLen:=0;
  957. ErrorClose:=0;
  958. end;
  959. Function ErrorOpen(Var F: TextRec): Integer;
  960. Begin
  961. TextRec(F).InOutFunc:=@ErrorWrite;
  962. TextRec(F).FlushFunc:=@ErrorWrite;
  963. TextRec(F).CloseFunc:=@ErrorClose;
  964. ErrorOpen:=0;
  965. End;
  966. procedure AssignError(Var T: Text);
  967. begin
  968. Assign(T,'');
  969. TextRec(T).OpenFunc:=@ErrorOpen;
  970. Rewrite(T);
  971. end;
  972. procedure SysInitStdIO;
  973. begin
  974. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  975. displayed in a messagebox }
  976. StdInputHandle:=THandle(GetStdHandle(STD_INPUT_HANDLE));
  977. StdOutputHandle:=THandle(GetStdHandle(STD_OUTPUT_HANDLE));
  978. StdErrorHandle:=THandle(GetStdHandle(STD_ERROR_HANDLE));
  979. if not IsConsole then
  980. begin
  981. AssignError(stderr);
  982. AssignError(stdout);
  983. Assign(Output,'');
  984. Assign(Input,'');
  985. Assign(ErrOutput,'');
  986. end
  987. else
  988. begin
  989. OpenStdIO(Input,fmInput,StdInputHandle);
  990. OpenStdIO(Output,fmOutput,StdOutputHandle);
  991. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  992. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  993. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  994. end;
  995. end;
  996. (* ProcessID cached to avoid repeated calls to GetCurrentProcess. *)
  997. var
  998. ProcessID: SizeUInt;
  999. function GetProcessID: SizeUInt;
  1000. begin
  1001. GetProcessID := ProcessID;
  1002. end;
  1003. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  1004. begin
  1005. result := stklen;
  1006. end;
  1007. begin
  1008. SysResetFPU;
  1009. StackLength := CheckInitialStkLen(InitialStkLen);
  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:=HInstance;
  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.