system.pp 32 KB

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