system.pp 33 KB

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