system.pp 27 KB

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