system.pp 29 KB

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