system.pp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950
  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. {$define HAS_WIDESTRINGMANAGER}
  20. { include system-independent routine headers }
  21. {$I systemh.inc}
  22. const
  23. LineEnding = #13#10;
  24. LFNSupport = true;
  25. DirectorySeparator = '\';
  26. DriveSeparator = ':';
  27. ExtensionSeparator = '.';
  28. PathSeparator = ';';
  29. AllowDirectorySeparators : set of char = ['\','/'];
  30. AllowDriveSeparators : set of char = [':'];
  31. { FileNameCaseSensitive is defined separately below!!! }
  32. maxExitCode = 65535;
  33. MaxPathLen = 260;
  34. AllFilesMask = '*';
  35. type
  36. PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
  37. TEXCEPTION_FRAME = record
  38. next : PEXCEPTION_FRAME;
  39. handler : pointer;
  40. end;
  41. const
  42. { Default filehandles }
  43. UnusedHandle : THandle = THandle(-1);
  44. StdInputHandle : THandle = 0;
  45. StdOutputHandle : THandle = 0;
  46. StdErrorHandle : THandle = 0;
  47. System_exception_frame : PEXCEPTION_FRAME =nil;
  48. FileNameCaseSensitive : boolean = true;
  49. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  50. sLineBreak = LineEnding;
  51. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  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. StartupConsoleMode : dword;
  80. hprevinst,
  81. MainInstance : qword;
  82. cmdshow : longint;
  83. DLLreason,DLLparam:longint;
  84. type
  85. TDLL_Entry_Hook = procedure (dllparam : longint);
  86. const
  87. Dll_Process_Detach_Hook : TDLL_Entry_Hook = nil;
  88. Dll_Thread_Attach_Hook : TDLL_Entry_Hook = nil;
  89. Dll_Thread_Detach_Hook : TDLL_Entry_Hook = nil;
  90. Const
  91. { it can be discussed whether fmShareDenyNone means read and write or read, write and delete, see
  92. also http://bugs.freepascal.org/view.php?id=8898, this allows users to configure the used
  93. value
  94. }
  95. fmShareDenyNoneFlags : DWord = 3;
  96. implementation
  97. var
  98. SysInstance : qword;public;
  99. { used by wstrings.inc because wstrings.inc is included before sysos.inc
  100. this is put here (FK) }
  101. function SysAllocStringLen(psz:pointer;len:dword):pointer;stdcall;
  102. external 'oleaut32.dll' name 'SysAllocStringLen';
  103. procedure SysFreeString(bstr:pointer);stdcall;
  104. external 'oleaut32.dll' name 'SysFreeString';
  105. function SysReAllocStringLen(var bstr:pointer;psz: pointer;
  106. len:dword): Integer; stdcall;external 'oleaut32.dll' name 'SysReAllocStringLen';
  107. { include system independent routines }
  108. {$I system.inc}
  109. {*****************************************************************************
  110. Parameter Handling
  111. *****************************************************************************}
  112. procedure setup_arguments;
  113. var
  114. arglen,
  115. count : longint;
  116. argstart,
  117. pc,arg : pchar;
  118. quote : char;
  119. argvlen : longint;
  120. buf: array[0..259] of char; // need MAX_PATH bytes, not 256!
  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. { 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. ArgLen := GetModuleFileName(0, @buf[0], sizeof(buf));
  144. buf[ArgLen] := #0; // be safe
  145. allocarg(0,arglen);
  146. move(buf,argv[0]^,arglen+1);
  147. { Setup cmdline variable }
  148. cmdline:=GetCommandLine;
  149. { process arguments }
  150. pc:=cmdline;
  151. {$IfDef SYSTEM_DEBUG_STARTUP}
  152. Writeln(stderr,'Win32 GetCommandLine is #',pc,'#');
  153. {$EndIf }
  154. while pc^<>#0 do
  155. begin
  156. { skip leading spaces }
  157. while pc^ in [#1..#32] do
  158. inc(pc);
  159. if pc^=#0 then
  160. break;
  161. { calc argument length }
  162. quote:=' ';
  163. argstart:=pc;
  164. arglen:=0;
  165. while (pc^<>#0) do
  166. begin
  167. case pc^ of
  168. #1..#32 :
  169. begin
  170. if quote<>' ' then
  171. inc(arglen)
  172. else
  173. break;
  174. end;
  175. '"' :
  176. begin
  177. if quote<>'''' then
  178. begin
  179. if pchar(pc+1)^<>'"' then
  180. begin
  181. if quote='"' then
  182. quote:=' '
  183. else
  184. quote:='"';
  185. end
  186. else
  187. inc(pc);
  188. end
  189. else
  190. inc(arglen);
  191. end;
  192. '''' :
  193. begin
  194. if quote<>'"' then
  195. begin
  196. if pchar(pc+1)^<>'''' then
  197. begin
  198. if quote='''' then
  199. quote:=' '
  200. else
  201. quote:='''';
  202. end
  203. else
  204. inc(pc);
  205. end
  206. else
  207. inc(arglen);
  208. end;
  209. else
  210. inc(arglen);
  211. end;
  212. inc(pc);
  213. end;
  214. { copy argument }
  215. { Don't copy the first one, it is already there.}
  216. If Count<>0 then
  217. begin
  218. allocarg(count,arglen);
  219. quote:=' ';
  220. pc:=argstart;
  221. arg:=argv[count];
  222. while (pc^<>#0) do
  223. begin
  224. case pc^ of
  225. #1..#32 :
  226. begin
  227. if quote<>' ' then
  228. begin
  229. arg^:=pc^;
  230. inc(arg);
  231. end
  232. else
  233. break;
  234. end;
  235. '"' :
  236. begin
  237. if quote<>'''' then
  238. begin
  239. if pchar(pc+1)^<>'"' then
  240. begin
  241. if quote='"' then
  242. quote:=' '
  243. else
  244. quote:='"';
  245. end
  246. else
  247. inc(pc);
  248. end
  249. else
  250. begin
  251. arg^:=pc^;
  252. inc(arg);
  253. end;
  254. end;
  255. '''' :
  256. begin
  257. if quote<>'"' then
  258. begin
  259. if pchar(pc+1)^<>'''' then
  260. begin
  261. if quote='''' then
  262. quote:=' '
  263. else
  264. quote:='''';
  265. end
  266. else
  267. inc(pc);
  268. end
  269. else
  270. begin
  271. arg^:=pc^;
  272. inc(arg);
  273. end;
  274. end;
  275. else
  276. begin
  277. arg^:=pc^;
  278. inc(arg);
  279. end;
  280. end;
  281. inc(pc);
  282. end;
  283. arg^:=#0;
  284. end;
  285. {$IfDef SYSTEM_DEBUG_STARTUP}
  286. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  287. {$EndIf SYSTEM_DEBUG_STARTUP}
  288. inc(count);
  289. end;
  290. { get argc }
  291. argc:=count;
  292. { free unused memory, leaving a nil entry at the end }
  293. sysreallocmem(argv,(count+1)*sizeof(pointer));
  294. argv[count] := nil;
  295. end;
  296. function paramcount : longint;
  297. begin
  298. paramcount := argc - 1;
  299. end;
  300. function paramstr(l : longint) : string;
  301. begin
  302. if (l>=0) and (l<argc) then
  303. paramstr:=strpas(argv[l])
  304. else
  305. paramstr:='';
  306. end;
  307. procedure randomize;
  308. begin
  309. randseed:=GetTickCount;
  310. end;
  311. {*****************************************************************************
  312. System Dependent Exit code
  313. *****************************************************************************}
  314. procedure install_exception_handlers;forward;
  315. procedure remove_exception_handlers;forward;
  316. procedure PascalMain;stdcall;external name 'PASCALMAIN';
  317. procedure fpc_do_exit;stdcall;external name 'FPC_DO_EXIT';
  318. Procedure ExitDLL(Exitcode : longint); forward;
  319. Procedure system_exit;
  320. begin
  321. { don't call ExitProcess inside
  322. the DLL exit code !!
  323. This crashes Win95 at least PM }
  324. if IsLibrary then
  325. ExitDLL(ExitCode);
  326. if not IsConsole then
  327. begin
  328. Close(stderr);
  329. Close(stdout);
  330. Close(erroutput);
  331. Close(Input);
  332. Close(Output);
  333. { what about Input and Output ?? PM }
  334. { now handled, FPK }
  335. end;
  336. remove_exception_handlers;
  337. { call exitprocess, with cleanup as required }
  338. ExitProcess(exitcode);
  339. end;
  340. var
  341. { old compilers emitted a reference to _fltused if a module contains
  342. floating type code so the linker could leave away floating point
  343. libraries or not. VC does this as well so we need to define this
  344. symbol as well (FK)
  345. }
  346. _fltused : int64;cvar;public;
  347. { value of the stack segment
  348. to check if the call stack can be written on exceptions }
  349. _SS : Cardinal;
  350. procedure Exe_entry;[public,alias:'_FPC_EXE_Entry'];
  351. var
  352. ST : pointer;
  353. begin
  354. IsLibrary:=false;
  355. { install the handlers for exe only ?
  356. or should we install them for DLL also ? (PM) }
  357. install_exception_handlers;
  358. ExitCode:=0;
  359. asm
  360. { allocate space for an exception frame }
  361. pushq $0
  362. pushq %gs:(0)
  363. { movl %rsp,%gs:(0)
  364. but don't insert it as it doesn't
  365. point to anything yet
  366. this will be used in signals unit }
  367. movq %rsp,%rax
  368. {$ifdef FPC_HAS_RIP_RELATIVE}
  369. movq %rax,System_exception_frame(%rip)
  370. {$else}
  371. movq %rax,System_exception_frame
  372. {$endif}
  373. { keep stack aligned }
  374. pushq $0
  375. pushq %rbp
  376. movq %rsp,%rax
  377. movq %rax,st
  378. end;
  379. StackTop:=st;
  380. asm
  381. xorq %rax,%rax
  382. movw %ss,%ax
  383. {$ifdef FPC_HAS_RIP_RELATIVE}
  384. movl %eax,_SS(%rip)
  385. {$else}
  386. movl %eax,_SS
  387. {$endif}
  388. xorq %rbp,%rbp
  389. call PASCALMAIN
  390. popq %rbp
  391. popq %rax
  392. end;
  393. { if we pass here there was no error ! }
  394. system_exit;
  395. end;
  396. function GetConsoleMode(hConsoleHandle: THandle; var lpMode: DWORD): Boolean; stdcall; external 'kernel32' name 'GetConsoleMode';
  397. function Dll_entry{$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}(const info : TEntryInformation){$endif FPC_HAS_INDIRECT_MAIN_INFORMATION} : longbool;forward;
  398. procedure _FPC_DLLMainCRTStartup(_hinstance : qword;_dllreason,_dllparam:longint);stdcall;public name '_DLLMainCRTStartup';
  399. begin
  400. IsConsole:=true;
  401. sysinstance:=_hinstance;
  402. dllreason:=_dllreason;
  403. dllparam:=_dllparam;
  404. DLL_Entry;
  405. end;
  406. procedure _FPC_DLLWinMainCRTStartup(_hinstance : qword;_dllreason,_dllparam:longint);stdcall;public name '_DLLWinMainCRTStartup';
  407. begin
  408. IsConsole:=false;
  409. sysinstance:=_hinstance;
  410. dllreason:=_dllreason;
  411. dllparam:=_dllparam;
  412. DLL_Entry;
  413. end;
  414. function GetCurrentProcess : dword;
  415. stdcall;external 'kernel32' name 'GetCurrentProcess';
  416. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  417. stdcall;external 'kernel32' name 'ReadProcessMemory';
  418. function is_prefetch(p : pointer) : boolean;
  419. var
  420. a : array[0..15] of byte;
  421. doagain : boolean;
  422. instrlo,instrhi,opcode : byte;
  423. i : longint;
  424. begin
  425. result:=false;
  426. { read memory savely without causing another exeception }
  427. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  428. exit;
  429. i:=0;
  430. doagain:=true;
  431. while doagain and (i<15) do
  432. begin
  433. opcode:=a[i];
  434. instrlo:=opcode and $f;
  435. instrhi:=opcode and $f0;
  436. case instrhi of
  437. { prefix? }
  438. $20,$30:
  439. doagain:=(instrlo and 7)=6;
  440. $60:
  441. doagain:=(instrlo and $c)=4;
  442. $f0:
  443. doagain:=instrlo in [0,2,3];
  444. $0:
  445. begin
  446. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  447. exit;
  448. end;
  449. else
  450. doagain:=false;
  451. end;
  452. inc(i);
  453. end;
  454. end;
  455. //
  456. // Hardware exception handling
  457. //
  458. {
  459. Error code definitions for the Win32 API functions
  460. Values are 32 bit values layed out as follows:
  461. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  462. 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
  463. +---+-+-+-----------------------+-------------------------------+
  464. |Sev|C|R| Facility | Code |
  465. +---+-+-+-----------------------+-------------------------------+
  466. where
  467. Sev - is the severity code
  468. 00 - Success
  469. 01 - Informational
  470. 10 - Warning
  471. 11 - Error
  472. C - is the Customer code flag
  473. R - is a reserved bit
  474. Facility - is the facility code
  475. Code - is the facility's status code
  476. }
  477. const
  478. SEVERITY_SUCCESS = $00000000;
  479. SEVERITY_INFORMATIONAL = $40000000;
  480. SEVERITY_WARNING = $80000000;
  481. SEVERITY_ERROR = $C0000000;
  482. const
  483. STATUS_SEGMENT_NOTIFICATION = $40000005;
  484. DBG_TERMINATE_THREAD = $40010003;
  485. DBG_TERMINATE_PROCESS = $40010004;
  486. DBG_CONTROL_C = $40010005;
  487. DBG_CONTROL_BREAK = $40010008;
  488. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  489. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  490. STATUS_BREAKPOINT = $80000003;
  491. STATUS_SINGLE_STEP = $80000004;
  492. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  493. STATUS_ACCESS_VIOLATION = $C0000005;
  494. STATUS_IN_PAGE_ERROR = $C0000006;
  495. STATUS_INVALID_HANDLE = $C0000008;
  496. STATUS_NO_MEMORY = $C0000017;
  497. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  498. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  499. STATUS_INVALID_DISPOSITION = $C0000026;
  500. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  501. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  502. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  503. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  504. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  505. STATUS_FLOAT_OVERFLOW = $C0000091;
  506. STATUS_FLOAT_STACK_CHECK = $C0000092;
  507. STATUS_FLOAT_UNDERFLOW = $C0000093;
  508. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  509. STATUS_INTEGER_OVERFLOW = $C0000095;
  510. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  511. STATUS_STACK_OVERFLOW = $C00000FD;
  512. STATUS_CONTROL_C_EXIT = $C000013A;
  513. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  514. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  515. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  516. EXCEPTION_EXECUTE_HANDLER = 1;
  517. EXCEPTION_CONTINUE_EXECUTION = -1;
  518. EXCEPTION_CONTINUE_SEARCH = 0;
  519. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  520. CONTEXT_X86 = $00010000;
  521. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  522. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  523. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  524. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  525. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  526. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  527. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  528. MAXIMUM_SUPPORTED_EXTENSION = 512;
  529. type
  530. M128A = record
  531. Low : QWord;
  532. High : Int64;
  533. end;
  534. PContext = ^TContext;
  535. TContext = record
  536. P1Home : QWord;
  537. P2Home : QWord;
  538. P3Home : QWord;
  539. P4Home : QWord;
  540. P5Home : QWord;
  541. P6Home : QWord;
  542. ContextFlags : DWord;
  543. MxCsr : DWord;
  544. SegCs : word;
  545. SegDs : word;
  546. SegEs : word;
  547. SegFs : word;
  548. SegGs : word;
  549. SegSs : word;
  550. EFlags : DWord;
  551. Dr0 : QWord;
  552. Dr1 : QWord;
  553. Dr2 : QWord;
  554. Dr3 : QWord;
  555. Dr6 : QWord;
  556. Dr7 : QWord;
  557. Rax : QWord;
  558. Rcx : QWord;
  559. Rdx : QWord;
  560. Rbx : QWord;
  561. Rsp : QWord;
  562. Rbp : QWord;
  563. Rsi : QWord;
  564. Rdi : QWord;
  565. R8 : QWord;
  566. R9 : QWord;
  567. R10 : QWord;
  568. R11 : QWord;
  569. R12 : QWord;
  570. R13 : QWord;
  571. R14 : QWord;
  572. R15 : QWord;
  573. Rip : QWord;
  574. Header : array[0..1] of M128A;
  575. Legacy : array[0..7] of M128A;
  576. Xmm0 : M128A;
  577. Xmm1 : M128A;
  578. Xmm2 : M128A;
  579. Xmm3 : M128A;
  580. Xmm4 : M128A;
  581. Xmm5 : M128A;
  582. Xmm6 : M128A;
  583. Xmm7 : M128A;
  584. Xmm8 : M128A;
  585. Xmm9 : M128A;
  586. Xmm10 : M128A;
  587. Xmm11 : M128A;
  588. Xmm12 : M128A;
  589. Xmm13 : M128A;
  590. Xmm14 : M128A;
  591. Xmm15 : M128A;
  592. VectorRegister : array[0..25] of M128A;
  593. VectorControl : QWord;
  594. DebugControl : QWord;
  595. LastBranchToRip : QWord;
  596. LastBranchFromRip : QWord;
  597. LastExceptionToRip : QWord;
  598. LastExceptionFromRip : QWord;
  599. end;
  600. type
  601. PExceptionRecord = ^TExceptionRecord;
  602. TExceptionRecord = record
  603. ExceptionCode : DWord;
  604. ExceptionFlags : DWord;
  605. ExceptionRecord : PExceptionRecord;
  606. ExceptionAddress : Pointer;
  607. NumberParameters : DWord;
  608. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
  609. end;
  610. PExceptionPointers = ^TExceptionPointers;
  611. TExceptionPointers = packed record
  612. ExceptionRecord : PExceptionRecord;
  613. ContextRecord : PContext;
  614. end;
  615. TVectoredExceptionHandler = function (excep : PExceptionPointers) : Longint;
  616. function AddVectoredExceptionHandler(FirstHandler : DWORD;VectoredHandler : TVectoredExceptionHandler) : longint;
  617. external 'kernel32' name 'AddVectoredExceptionHandler';
  618. const
  619. MaxExceptionLevel = 16;
  620. exceptLevel : Byte = 0;
  621. var
  622. exceptRip : array[0..MaxExceptionLevel-1] of Int64;
  623. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  624. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  625. {$ifdef SYSTEMEXCEPTIONDEBUG}
  626. procedure DebugHandleErrorAddrFrame(error : longint; addr, frame : pointer);
  627. begin
  628. if IsConsole then
  629. begin
  630. write(stderr,'HandleErrorAddrFrame(error=',error);
  631. write(stderr,',addr=',hexstr(int64(addr),16));
  632. writeln(stderr,',frame=',hexstr(int64(frame),16),')');
  633. end;
  634. HandleErrorAddrFrame(error,addr,frame);
  635. end;
  636. {$endif SYSTEMEXCEPTIONDEBUG}
  637. procedure JumpToHandleErrorFrame;
  638. var
  639. rip, rbp : int64;
  640. error : longint;
  641. begin
  642. // save ebp
  643. asm
  644. movq (%rbp),%rax
  645. movq %rax,rbp
  646. end;
  647. if exceptLevel>0 then
  648. dec(exceptLevel);
  649. rip:=exceptRip[exceptLevel];
  650. error:=exceptError[exceptLevel];
  651. {$ifdef SYSTEMEXCEPTIONDEBUG}
  652. if IsConsole then
  653. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  654. {$endif SYSTEMEXCEPTIONDEBUG}
  655. if resetFPU[exceptLevel] then
  656. SysResetFPU;
  657. { build a fake stack }
  658. asm
  659. movq rbp,%r8
  660. movq rip,%rdx
  661. movl error,%ecx
  662. pushq rip
  663. movq rbp,%rbp // Change frame pointer
  664. {$ifdef SYSTEMEXCEPTIONDEBUG}
  665. jmpl DebugHandleErrorAddrFrame
  666. {$else not SYSTEMEXCEPTIONDEBUG}
  667. jmpl HandleErrorAddrFrame
  668. {$endif SYSTEMEXCEPTIONDEBUG}
  669. end;
  670. end;
  671. function syswin64_x86_64_exception_handler(excep : PExceptionPointers) : Longint;public;
  672. var
  673. res: longint;
  674. err: byte;
  675. must_reset_fpu: boolean;
  676. begin
  677. res:=EXCEPTION_CONTINUE_SEARCH;
  678. {$ifdef SYSTEMEXCEPTIONDEBUG}
  679. if IsConsole then
  680. Writeln(stderr,'syswin64_x86_64_exception_handler called');
  681. {$endif SYSTEMEXCEPTIONDEBUG}
  682. if excep^.ContextRecord^.SegSs=_SS then
  683. begin
  684. err := 0;
  685. must_reset_fpu := true;
  686. {$ifdef SYSTEMEXCEPTIONDEBUG}
  687. if IsConsole then Writeln(stderr,'Exception ',
  688. hexstr(excep^.ExceptionRecord^.ExceptionCode,8));
  689. {$endif SYSTEMEXCEPTIONDEBUG}
  690. case cardinal(excep^.ExceptionRecord^.ExceptionCode) of
  691. STATUS_INTEGER_DIVIDE_BY_ZERO,
  692. STATUS_FLOAT_DIVIDE_BY_ZERO :
  693. err := 200;
  694. STATUS_ARRAY_BOUNDS_EXCEEDED :
  695. begin
  696. err := 201;
  697. must_reset_fpu := false;
  698. end;
  699. STATUS_STACK_OVERFLOW :
  700. begin
  701. err := 202;
  702. must_reset_fpu := false;
  703. end;
  704. STATUS_FLOAT_OVERFLOW :
  705. err := 205;
  706. STATUS_FLOAT_DENORMAL_OPERAND,
  707. STATUS_FLOAT_UNDERFLOW :
  708. err := 206;
  709. { excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  710. STATUS_FLOAT_INEXACT_RESULT,
  711. STATUS_FLOAT_INVALID_OPERATION,
  712. STATUS_FLOAT_STACK_CHECK :
  713. err := 207;
  714. STATUS_INTEGER_OVERFLOW :
  715. begin
  716. err := 215;
  717. must_reset_fpu := false;
  718. end;
  719. STATUS_ILLEGAL_INSTRUCTION:
  720. err := 216;
  721. STATUS_ACCESS_VIOLATION:
  722. { Athlon prefetch bug? }
  723. if is_prefetch(pointer(excep^.ContextRecord^.rip)) then
  724. begin
  725. { if yes, then retry }
  726. excep^.ExceptionRecord^.ExceptionCode := 0;
  727. res:=EXCEPTION_CONTINUE_EXECUTION;
  728. end
  729. else
  730. err := 216;
  731. STATUS_CONTROL_C_EXIT:
  732. err := 217;
  733. STATUS_PRIVILEGED_INSTRUCTION:
  734. begin
  735. err := 218;
  736. must_reset_fpu := false;
  737. end;
  738. else
  739. begin
  740. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  741. err := 217
  742. else
  743. { pass through exceptions which aren't an error. The problem is that vectored handlers
  744. always are called before structured ones so we see also internal exceptions of libraries.
  745. I wonder if there is a better solution (FK)
  746. }
  747. res:=EXCEPTION_CONTINUE_SEARCH;
  748. end;
  749. end;
  750. if (err <> 0) and (exceptLevel < MaxExceptionLevel) then
  751. begin
  752. exceptRip[exceptLevel] := excep^.ContextRecord^.Rip;
  753. exceptError[exceptLevel] := err;
  754. resetFPU[exceptLevel] := must_reset_fpu;
  755. inc(exceptLevel);
  756. excep^.ContextRecord^.Rip := Int64(@JumpToHandleErrorFrame);
  757. excep^.ExceptionRecord^.ExceptionCode := 0;
  758. res := EXCEPTION_CONTINUE_EXECUTION;
  759. {$ifdef SYSTEMEXCEPTIONDEBUG}
  760. if IsConsole then begin
  761. writeln(stderr,'Exception Continue Exception set at ',
  762. hexstr(exceptRip[exceptLevel-1],16));
  763. writeln(stderr,'Rip changed to ',
  764. hexstr(int64(@JumpToHandleErrorFrame),16), ' error=', err);
  765. end;
  766. {$endif SYSTEMEXCEPTIONDEBUG}
  767. end;
  768. end;
  769. syswin64_x86_64_exception_handler := res;
  770. end;
  771. procedure install_exception_handlers;
  772. begin
  773. AddVectoredExceptionHandler(1,@syswin64_x86_64_exception_handler);
  774. end;
  775. procedure remove_exception_handlers;
  776. begin
  777. end;
  778. procedure fpc_cpucodeinit;
  779. begin
  780. end;
  781. {******************************************************************************}
  782. { include code common with win64 }
  783. {$I syswin.inc}
  784. {******************************************************************************}
  785. procedure LinkIn(p1,p2,p3: Pointer); inline;
  786. begin
  787. end;
  788. procedure _FPC_mainCRTStartup;stdcall;public name '_mainCRTStartup';
  789. begin
  790. IsConsole:=true;
  791. GetConsoleMode(GetStdHandle((Std_Input_Handle)),StartupConsoleMode);
  792. {$ifdef FPC_USE_TLS_DIRECTORY}
  793. LinkIn(@_tls_used,@FreePascal_TLS_callback,@FreePascal_end_of_TLS_callback);
  794. {$endif FPC_USE_TLS_DIRECTORY}
  795. Exe_entry;
  796. end;
  797. procedure _FPC_WinMainCRTStartup;stdcall;public name '_WinMainCRTStartup';
  798. begin
  799. IsConsole:=false;
  800. {$ifdef FPC_USE_TLS_DIRECTORY}
  801. LinkIn(@_tls_used,@FreePascal_TLS_callback,@FreePascal_end_of_TLS_callback);
  802. {$endif FPC_USE_TLS_DIRECTORY}
  803. Exe_entry;
  804. end;
  805. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;assembler;
  806. asm
  807. movq %gs:(8),%rax
  808. subq %gs:(16),%rax
  809. end;
  810. begin
  811. SysResetFPU;
  812. if not(IsLibrary) then
  813. SysInitFPU;
  814. { pass dummy value }
  815. StackLength := CheckInitialStkLen($1000000);
  816. StackBottom := StackTop - StackLength;
  817. { get some helpful informations }
  818. GetStartupInfo(@startupinfo);
  819. { some misc Win32 stuff }
  820. hprevinst:=0;
  821. if not IsLibrary then
  822. SysInstance:=getmodulehandle(nil);
  823. MainInstance:=SysInstance;
  824. cmdshow:=startupinfo.wshowwindow;
  825. { Setup heap }
  826. InitHeap;
  827. SysInitExceptions;
  828. { setup fastmove stuff }
  829. fpc_cpucodeinit;
  830. SysInitStdIO;
  831. { Arguments }
  832. setup_arguments;
  833. { Reset IO Error }
  834. InOutRes:=0;
  835. ProcessID := GetCurrentProcessID;
  836. { threading }
  837. InitSystemThreads;
  838. { Reset internal error variable }
  839. errno:=0;
  840. initvariantmanager;
  841. initwidestringmanager;
  842. {$ifndef VER2_2}
  843. initunicodestringmanager;
  844. {$endif VER2_2}
  845. InitWin32Widestrings;
  846. DispCallByIDProc:=@DoDispCallByIDError;
  847. end.