system.pp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2006 by Florian Klaempfl and Pavel Ozerski
  4. member of the Free Pascal development team.
  5. FPC Pascal system unit for the Win64 API.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit System;
  13. interface
  14. { $define SYSTEMEXCEPTIONDEBUG}
  15. {$ifdef SYSTEMDEBUG}
  16. {$define SYSTEMEXCEPTIONDEBUG}
  17. {$endif SYSTEMDEBUG}
  18. {$define DISABLE_NO_THREAD_MANAGER}
  19. { include system-independent routine headers }
  20. {$I systemh.inc}
  21. const
  22. LineEnding = #13#10;
  23. LFNSupport = true;
  24. DirectorySeparator = '\';
  25. DriveSeparator = ':';
  26. ExtensionSeparator = '.';
  27. PathSeparator = ';';
  28. AllowDirectorySeparators : set of char = ['\','/'];
  29. AllowDriveSeparators : set of char = [':'];
  30. { FileNameCaseSensitive is defined separately below!!! }
  31. maxExitCode = 65535;
  32. MaxPathLen = 260;
  33. AllFilesMask = '*';
  34. type
  35. PEXCEPTION_FRAME = ^TEXCEPTION_FRAME;
  36. TEXCEPTION_FRAME = record
  37. next : PEXCEPTION_FRAME;
  38. handler : pointer;
  39. end;
  40. const
  41. { Default filehandles }
  42. UnusedHandle : THandle = THandle(-1);
  43. StdInputHandle : THandle = 0;
  44. StdOutputHandle : THandle = 0;
  45. StdErrorHandle : THandle = 0;
  46. FileNameCaseSensitive : boolean = true;
  47. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  48. sLineBreak = LineEnding;
  49. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  50. { Thread count for DLL }
  51. Thread_count : longint = 0;
  52. type
  53. TStartupInfo = record
  54. cb : longint;
  55. lpReserved : Pointer;
  56. lpDesktop : Pointer;
  57. lpTitle : Pointer;
  58. dwX : longint;
  59. dwY : longint;
  60. dwXSize : longint;
  61. dwYSize : longint;
  62. dwXCountChars : longint;
  63. dwYCountChars : longint;
  64. dwFillAttribute : longint;
  65. dwFlags : longint;
  66. wShowWindow : Word;
  67. cbReserved2 : Word;
  68. lpReserved2 : Pointer;
  69. hStdInput : THandle;
  70. hStdOutput : THandle;
  71. hStdError : THandle;
  72. end;
  73. var
  74. { C compatible arguments }
  75. argc : longint;
  76. argv : ppchar;
  77. { Win32 Info }
  78. startupinfo : tstartupinfo;
  79. 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. { keep stack aligned }
  361. pushq $0
  362. pushq %rbp
  363. movq %rsp,%rax
  364. movq %rax,st
  365. end;
  366. StackTop:=st;
  367. asm
  368. xorl %rax,%rax
  369. movw %ss,%ax
  370. {$ifdef FPC_HAS_RIP_RELATIVE}
  371. movl %eax,_SS(%rip)
  372. {$else}
  373. movl %eax,_SS
  374. {$endif}
  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. function GetConsoleMode(hConsoleHandle: THandle; var lpMode: DWORD): Boolean; stdcall; external 'kernel32' name 'GetConsoleMode';
  384. function Dll_entry{$ifdef FPC_HAS_INDIRECT_MAIN_INFORMATION}(const info : TEntryInformation){$endif FPC_HAS_INDIRECT_MAIN_INFORMATION} : longbool;forward;
  385. procedure _FPC_mainCRTStartup;stdcall;public name '_mainCRTStartup';
  386. begin
  387. IsConsole:=true;
  388. GetConsoleMode(GetStdHandle((Std_Input_Handle)),StartupConsoleMode);
  389. Exe_entry;
  390. end;
  391. procedure _FPC_WinMainCRTStartup;stdcall;public name '_WinMainCRTStartup';
  392. begin
  393. IsConsole:=false;
  394. Exe_entry;
  395. end;
  396. procedure _FPC_DLLMainCRTStartup(_hinstance : qword;_dllreason,_dllparam:longint);stdcall;public name '_DLLMainCRTStartup';
  397. begin
  398. IsConsole:=true;
  399. sysinstance:=_hinstance;
  400. dllreason:=_dllreason;
  401. dllparam:=_dllparam;
  402. DLL_Entry;
  403. end;
  404. procedure _FPC_DLLWinMainCRTStartup(_hinstance : qword;_dllreason,_dllparam:longint);stdcall;public name '_DLLWinMainCRTStartup';
  405. begin
  406. IsConsole:=false;
  407. sysinstance:=_hinstance;
  408. dllreason:=_dllreason;
  409. dllparam:=_dllparam;
  410. DLL_Entry;
  411. end;
  412. function GetCurrentProcess : dword;
  413. stdcall;external 'kernel32' name 'GetCurrentProcess';
  414. function ReadProcessMemory(process : dword;address : pointer;dest : pointer;size : dword;bytesread : pdword) : longbool;
  415. stdcall;external 'kernel32' name 'ReadProcessMemory';
  416. function is_prefetch(p : pointer) : boolean;
  417. var
  418. a : array[0..15] of byte;
  419. doagain : boolean;
  420. instrlo,instrhi,opcode : byte;
  421. i : longint;
  422. begin
  423. result:=false;
  424. { read memory savely without causing another exeception }
  425. if not(ReadProcessMemory(GetCurrentProcess,p,@a,sizeof(a),nil)) then
  426. exit;
  427. i:=0;
  428. doagain:=true;
  429. while doagain and (i<15) do
  430. begin
  431. opcode:=a[i];
  432. instrlo:=opcode and $f;
  433. instrhi:=opcode and $f0;
  434. case instrhi of
  435. { prefix? }
  436. $20,$30:
  437. doagain:=(instrlo and 7)=6;
  438. $60:
  439. doagain:=(instrlo and $c)=4;
  440. $f0:
  441. doagain:=instrlo in [0,2,3];
  442. $0:
  443. begin
  444. result:=(instrlo=$f) and (a[i+1] in [$d,$18]);
  445. exit;
  446. end;
  447. else
  448. doagain:=false;
  449. end;
  450. inc(i);
  451. end;
  452. end;
  453. //
  454. // Hardware exception handling
  455. //
  456. {
  457. Error code definitions for the Win32 API functions
  458. Values are 32 bit values layed out as follows:
  459. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  460. 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
  461. +---+-+-+-----------------------+-------------------------------+
  462. |Sev|C|R| Facility | Code |
  463. +---+-+-+-----------------------+-------------------------------+
  464. where
  465. Sev - is the severity code
  466. 00 - Success
  467. 01 - Informational
  468. 10 - Warning
  469. 11 - Error
  470. C - is the Customer code flag
  471. R - is a reserved bit
  472. Facility - is the facility code
  473. Code - is the facility's status code
  474. }
  475. const
  476. SEVERITY_SUCCESS = $00000000;
  477. SEVERITY_INFORMATIONAL = $40000000;
  478. SEVERITY_WARNING = $80000000;
  479. SEVERITY_ERROR = $C0000000;
  480. const
  481. STATUS_SEGMENT_NOTIFICATION = $40000005;
  482. DBG_TERMINATE_THREAD = $40010003;
  483. DBG_TERMINATE_PROCESS = $40010004;
  484. DBG_CONTROL_C = $40010005;
  485. DBG_CONTROL_BREAK = $40010008;
  486. STATUS_GUARD_PAGE_VIOLATION = $80000001;
  487. STATUS_DATATYPE_MISALIGNMENT = $80000002;
  488. STATUS_BREAKPOINT = $80000003;
  489. STATUS_SINGLE_STEP = $80000004;
  490. DBG_EXCEPTION_NOT_HANDLED = $80010001;
  491. STATUS_ACCESS_VIOLATION = $C0000005;
  492. STATUS_IN_PAGE_ERROR = $C0000006;
  493. STATUS_INVALID_HANDLE = $C0000008;
  494. STATUS_NO_MEMORY = $C0000017;
  495. STATUS_ILLEGAL_INSTRUCTION = $C000001D;
  496. STATUS_NONCONTINUABLE_EXCEPTION = $C0000025;
  497. STATUS_INVALID_DISPOSITION = $C0000026;
  498. STATUS_ARRAY_BOUNDS_EXCEEDED = $C000008C;
  499. STATUS_FLOAT_DENORMAL_OPERAND = $C000008D;
  500. STATUS_FLOAT_DIVIDE_BY_ZERO = $C000008E;
  501. STATUS_FLOAT_INEXACT_RESULT = $C000008F;
  502. STATUS_FLOAT_INVALID_OPERATION = $C0000090;
  503. STATUS_FLOAT_OVERFLOW = $C0000091;
  504. STATUS_FLOAT_STACK_CHECK = $C0000092;
  505. STATUS_FLOAT_UNDERFLOW = $C0000093;
  506. STATUS_INTEGER_DIVIDE_BY_ZERO = $C0000094;
  507. STATUS_INTEGER_OVERFLOW = $C0000095;
  508. STATUS_PRIVILEGED_INSTRUCTION = $C0000096;
  509. STATUS_STACK_OVERFLOW = $C00000FD;
  510. STATUS_CONTROL_C_EXIT = $C000013A;
  511. STATUS_FLOAT_MULTIPLE_FAULTS = $C00002B4;
  512. STATUS_FLOAT_MULTIPLE_TRAPS = $C00002B5;
  513. STATUS_REG_NAT_CONSUMPTION = $C00002C9;
  514. EXCEPTION_EXECUTE_HANDLER = 1;
  515. EXCEPTION_CONTINUE_EXECUTION = -1;
  516. EXCEPTION_CONTINUE_SEARCH = 0;
  517. EXCEPTION_MAXIMUM_PARAMETERS = 15;
  518. CONTEXT_X86 = $00010000;
  519. CONTEXT_CONTROL = CONTEXT_X86 or $00000001;
  520. CONTEXT_INTEGER = CONTEXT_X86 or $00000002;
  521. CONTEXT_SEGMENTS = CONTEXT_X86 or $00000004;
  522. CONTEXT_FLOATING_POINT = CONTEXT_X86 or $00000008;
  523. CONTEXT_DEBUG_REGISTERS = CONTEXT_X86 or $00000010;
  524. CONTEXT_EXTENDED_REGISTERS = CONTEXT_X86 or $00000020;
  525. CONTEXT_FULL = CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS;
  526. MAXIMUM_SUPPORTED_EXTENSION = 512;
  527. type
  528. M128A = record
  529. Low : QWord;
  530. High : Int64;
  531. end;
  532. PContext = ^TContext;
  533. TContext = record
  534. P1Home : QWord;
  535. P2Home : QWord;
  536. P3Home : QWord;
  537. P4Home : QWord;
  538. P5Home : QWord;
  539. P6Home : QWord;
  540. ContextFlags : DWord;
  541. MxCsr : DWord;
  542. SegCs : word;
  543. SegDs : word;
  544. SegEs : word;
  545. SegFs : word;
  546. SegGs : word;
  547. SegSs : word;
  548. EFlags : DWord;
  549. Dr0 : QWord;
  550. Dr1 : QWord;
  551. Dr2 : QWord;
  552. Dr3 : QWord;
  553. Dr6 : QWord;
  554. Dr7 : QWord;
  555. Rax : QWord;
  556. Rcx : QWord;
  557. Rdx : QWord;
  558. Rbx : QWord;
  559. Rsp : QWord;
  560. Rbp : QWord;
  561. Rsi : QWord;
  562. Rdi : QWord;
  563. R8 : QWord;
  564. R9 : QWord;
  565. R10 : QWord;
  566. R11 : QWord;
  567. R12 : QWord;
  568. R13 : QWord;
  569. R14 : QWord;
  570. R15 : QWord;
  571. Rip : QWord;
  572. Header : array[0..1] of M128A;
  573. Legacy : array[0..7] of M128A;
  574. Xmm0 : M128A;
  575. Xmm1 : M128A;
  576. Xmm2 : M128A;
  577. Xmm3 : M128A;
  578. Xmm4 : M128A;
  579. Xmm5 : M128A;
  580. Xmm6 : M128A;
  581. Xmm7 : M128A;
  582. Xmm8 : M128A;
  583. Xmm9 : M128A;
  584. Xmm10 : M128A;
  585. Xmm11 : M128A;
  586. Xmm12 : M128A;
  587. Xmm13 : M128A;
  588. Xmm14 : M128A;
  589. Xmm15 : M128A;
  590. VectorRegister : array[0..25] of M128A;
  591. VectorControl : QWord;
  592. DebugControl : QWord;
  593. LastBranchToRip : QWord;
  594. LastBranchFromRip : QWord;
  595. LastExceptionToRip : QWord;
  596. LastExceptionFromRip : QWord;
  597. end;
  598. type
  599. PExceptionRecord = ^TExceptionRecord;
  600. TExceptionRecord = record
  601. ExceptionCode : DWord;
  602. ExceptionFlags : DWord;
  603. ExceptionRecord : PExceptionRecord;
  604. ExceptionAddress : Pointer;
  605. NumberParameters : DWord;
  606. ExceptionInformation : array[0..EXCEPTION_MAXIMUM_PARAMETERS-1] of Pointer;
  607. end;
  608. PExceptionPointers = ^TExceptionPointers;
  609. TExceptionPointers = packed record
  610. ExceptionRecord : PExceptionRecord;
  611. ContextRecord : PContext;
  612. end;
  613. TVectoredExceptionHandler = function (excep : PExceptionPointers) : Longint;
  614. function AddVectoredExceptionHandler(FirstHandler : DWORD;VectoredHandler : TVectoredExceptionHandler) : longint;
  615. external 'kernel32' name 'AddVectoredExceptionHandler';
  616. const
  617. MaxExceptionLevel = 16;
  618. exceptLevel : Byte = 0;
  619. var
  620. exceptRip : array[0..MaxExceptionLevel-1] of Int64;
  621. exceptError : array[0..MaxExceptionLevel-1] of Byte;
  622. resetFPU : array[0..MaxExceptionLevel-1] of Boolean;
  623. {$ifdef SYSTEMEXCEPTIONDEBUG}
  624. procedure DebugHandleErrorAddrFrame(error : longint; addr, frame : pointer);
  625. begin
  626. if IsConsole then
  627. begin
  628. write(stderr,'HandleErrorAddrFrame(error=',error);
  629. write(stderr,',addr=',hexstr(int64(addr),16));
  630. writeln(stderr,',frame=',hexstr(int64(frame),16),')');
  631. end;
  632. HandleErrorAddrFrame(error,addr,frame);
  633. end;
  634. {$endif SYSTEMEXCEPTIONDEBUG}
  635. procedure JumpToHandleErrorFrame;
  636. var
  637. rip, rbp : int64;
  638. error : longint;
  639. begin
  640. // save ebp
  641. asm
  642. movq (%rbp),%rax
  643. movq %rax,rbp
  644. end;
  645. if exceptLevel>0 then
  646. dec(exceptLevel);
  647. rip:=exceptRip[exceptLevel];
  648. error:=exceptError[exceptLevel];
  649. {$ifdef SYSTEMEXCEPTIONDEBUG}
  650. if IsConsole then
  651. writeln(stderr,'In JumpToHandleErrorFrame error=',error);
  652. {$endif SYSTEMEXCEPTIONDEBUG}
  653. if resetFPU[exceptLevel] then
  654. SysResetFPU;
  655. { build a fake stack }
  656. asm
  657. movq rbp,%r8
  658. movq rip,%rdx
  659. movl error,%ecx
  660. pushq rip
  661. movq rbp,%rbp // Change frame pointer
  662. {$ifdef SYSTEMEXCEPTIONDEBUG}
  663. jmpl DebugHandleErrorAddrFrame
  664. {$else not SYSTEMEXCEPTIONDEBUG}
  665. jmpl HandleErrorAddrFrame
  666. {$endif SYSTEMEXCEPTIONDEBUG}
  667. end;
  668. end;
  669. function syswin64_x86_64_exception_handler(excep : PExceptionPointers) : Longint;public;
  670. var
  671. res: longint;
  672. err: byte;
  673. must_reset_fpu: boolean;
  674. begin
  675. res:=EXCEPTION_CONTINUE_SEARCH;
  676. {$ifdef SYSTEMEXCEPTIONDEBUG}
  677. if IsConsole then
  678. Writeln(stderr,'syswin64_x86_64_exception_handler called');
  679. {$endif SYSTEMEXCEPTIONDEBUG}
  680. if excep^.ContextRecord^.SegSs=_SS then
  681. begin
  682. err := 0;
  683. must_reset_fpu := true;
  684. {$ifdef SYSTEMEXCEPTIONDEBUG}
  685. if IsConsole then Writeln(stderr,'Exception ',
  686. hexstr(excep^.ExceptionRecord^.ExceptionCode,8));
  687. {$endif SYSTEMEXCEPTIONDEBUG}
  688. case cardinal(excep^.ExceptionRecord^.ExceptionCode) of
  689. STATUS_INTEGER_DIVIDE_BY_ZERO,
  690. STATUS_FLOAT_DIVIDE_BY_ZERO :
  691. err := 200;
  692. STATUS_ARRAY_BOUNDS_EXCEEDED :
  693. begin
  694. err := 201;
  695. must_reset_fpu := false;
  696. end;
  697. STATUS_STACK_OVERFLOW :
  698. begin
  699. err := 202;
  700. must_reset_fpu := false;
  701. end;
  702. STATUS_FLOAT_OVERFLOW :
  703. err := 205;
  704. STATUS_FLOAT_DENORMAL_OPERAND,
  705. STATUS_FLOAT_UNDERFLOW :
  706. err := 206;
  707. { excep^.ContextRecord^.FloatSave.StatusWord := excep^.ContextRecord^.FloatSave.StatusWord and $ffffff00;}
  708. STATUS_FLOAT_INEXACT_RESULT,
  709. STATUS_FLOAT_INVALID_OPERATION,
  710. STATUS_FLOAT_STACK_CHECK :
  711. err := 207;
  712. STATUS_INTEGER_OVERFLOW :
  713. begin
  714. err := 215;
  715. must_reset_fpu := false;
  716. end;
  717. STATUS_ILLEGAL_INSTRUCTION:
  718. err := 216;
  719. STATUS_ACCESS_VIOLATION:
  720. { Athlon prefetch bug? }
  721. if is_prefetch(pointer(excep^.ContextRecord^.rip)) then
  722. begin
  723. { if yes, then retry }
  724. excep^.ExceptionRecord^.ExceptionCode := 0;
  725. res:=EXCEPTION_CONTINUE_EXECUTION;
  726. end
  727. else
  728. err := 216;
  729. STATUS_CONTROL_C_EXIT:
  730. err := 217;
  731. STATUS_PRIVILEGED_INSTRUCTION:
  732. begin
  733. err := 218;
  734. must_reset_fpu := false;
  735. end;
  736. else
  737. begin
  738. if ((excep^.ExceptionRecord^.ExceptionCode and SEVERITY_ERROR) = SEVERITY_ERROR) then
  739. err := 217
  740. else
  741. { pass through exceptions which aren't an error. The problem is that vectored handlers
  742. always are called before structured ones so we see also internal exceptions of libraries.
  743. I wonder if there is a better solution (FK)
  744. }
  745. res:=EXCEPTION_CONTINUE_SEARCH;
  746. end;
  747. end;
  748. if (err <> 0) and (exceptLevel < MaxExceptionLevel) then
  749. begin
  750. exceptRip[exceptLevel] := excep^.ContextRecord^.Rip;
  751. exceptError[exceptLevel] := err;
  752. resetFPU[exceptLevel] := must_reset_fpu;
  753. inc(exceptLevel);
  754. excep^.ContextRecord^.Rip := Int64(@JumpToHandleErrorFrame);
  755. excep^.ExceptionRecord^.ExceptionCode := 0;
  756. res := EXCEPTION_CONTINUE_EXECUTION;
  757. {$ifdef SYSTEMEXCEPTIONDEBUG}
  758. if IsConsole then begin
  759. writeln(stderr,'Exception Continue Exception set at ',
  760. hexstr(exceptRip[exceptLevel-1],16));
  761. writeln(stderr,'Rip changed to ',
  762. hexstr(int64(@JumpToHandleErrorFrame),16), ' error=', err);
  763. end;
  764. {$endif SYSTEMEXCEPTIONDEBUG}
  765. end;
  766. end;
  767. syswin64_x86_64_exception_handler := res;
  768. end;
  769. procedure install_exception_handlers;
  770. begin
  771. AddVectoredExceptionHandler(1,@syswin64_x86_64_exception_handler);
  772. end;
  773. procedure remove_exception_handlers;
  774. begin
  775. end;
  776. procedure fpc_cpucodeinit;
  777. begin
  778. end;
  779. {****************************************************************************
  780. OS dependend widestrings
  781. ****************************************************************************}
  782. const
  783. { MultiByteToWideChar }
  784. MB_PRECOMPOSED = 1;
  785. CP_ACP = 0;
  786. WC_NO_BEST_FIT_CHARS = $400;
  787. function MultiByteToWideChar(CodePage:UINT; dwFlags:DWORD; lpMultiByteStr:PChar; cchMultiByte:longint; lpWideCharStr:PWideChar;cchWideChar:longint):longint;
  788. stdcall; external 'kernel32' name 'MultiByteToWideChar';
  789. function WideCharToMultiByte(CodePage:UINT; dwFlags:DWORD; lpWideCharStr:PWideChar; cchWideChar:longint; lpMultiByteStr:PChar;cchMultiByte:longint; lpDefaultChar:PChar; lpUsedDefaultChar:pointer):longint;
  790. stdcall; external 'kernel32' name 'WideCharToMultiByte';
  791. function CharUpperBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  792. stdcall; external 'user32' name 'CharUpperBuffW';
  793. function CharLowerBuff(lpsz:LPWSTR; cchLength:DWORD):DWORD;
  794. stdcall; external 'user32' name 'CharLowerBuffW';
  795. procedure Win32Wide2AnsiMove(source:pwidechar;var dest:ansistring;len:SizeInt);
  796. var
  797. destlen: SizeInt;
  798. begin
  799. // retrieve length including trailing #0
  800. // not anymore, because this must also be usable for single characters
  801. destlen:=WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, source, len, nil, 0, nil, nil);
  802. // this will null-terminate
  803. setlength(dest, destlen);
  804. WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, source, len, @dest[1], destlen, nil, nil);
  805. end;
  806. procedure Win32Ansi2WideMove(source:pchar;var dest:widestring;len:SizeInt);
  807. var
  808. destlen: SizeInt;
  809. begin
  810. // retrieve length including trailing #0
  811. // not anymore, because this must also be usable for single characters
  812. destlen:=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, nil, 0);
  813. // this will null-terminate
  814. setlength(dest, destlen);
  815. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, source, len, @dest[1], destlen);
  816. end;
  817. function Win32WideUpper(const s : WideString) : WideString;
  818. begin
  819. result:=s;
  820. UniqueString(result);
  821. if length(result)>0 then
  822. CharUpperBuff(LPWSTR(result),length(result));
  823. end;
  824. function Win32WideLower(const s : WideString) : WideString;
  825. begin
  826. result:=s;
  827. UniqueString(result);
  828. if length(result)>0 then
  829. CharLowerBuff(LPWSTR(result),length(result));
  830. end;
  831. {******************************************************************************}
  832. { include code common with win64 }
  833. {$I syswin.inc}
  834. {******************************************************************************}
  835. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;assembler;
  836. asm
  837. movq %gs:(8),%rax
  838. subq %gs:(16),%rax
  839. end;
  840. begin
  841. SysResetFPU;
  842. if not(IsLibrary) then
  843. SysInitFPU;
  844. { pass dummy value }
  845. StackLength := CheckInitialStkLen($1000000);
  846. StackBottom := StackTop - StackLength;
  847. { get some helpful informations }
  848. GetStartupInfo(@startupinfo);
  849. { some misc Win32 stuff }
  850. hprevinst:=0;
  851. if not IsLibrary then
  852. SysInstance:=getmodulehandle(nil);
  853. MainInstance:=SysInstance;
  854. cmdshow:=startupinfo.wshowwindow;
  855. { Setup heap }
  856. InitHeap;
  857. SysInitExceptions;
  858. { setup fastmove stuff }
  859. fpc_cpucodeinit;
  860. SysInitStdIO;
  861. { Arguments }
  862. setup_arguments;
  863. { Reset IO Error }
  864. InOutRes:=0;
  865. ProcessID := GetCurrentProcessID;
  866. { threading }
  867. InitSystemThreads;
  868. { Reset internal error variable }
  869. errno:=0;
  870. initvariantmanager;
  871. initwidestringmanager;
  872. {$ifndef VER2_2}
  873. initunicodestringmanager;
  874. {$endif VER2_2}
  875. InitWin32Widestrings;
  876. DispCallByIDProc:=@DoDispCallByIDError;
  877. end.