2
0

system.pp 33 KB

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