system.pp 28 KB

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