system.pp 34 KB

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