system.pp 32 KB

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