system.pp 33 KB

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