system.pp 29 KB

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