system.pp 31 KB

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