system.pp 33 KB

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