system.pp 27 KB

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