seh64.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2011 by Free Pascal development team
  4. Support for 64-bit Windows exception handling
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. { exception flags }
  12. const
  13. EXCEPTION_UNWIND = EXCEPTION_UNWINDING or EXCEPTION_EXIT_UNWIND or
  14. EXCEPTION_TARGET_UNWIND or EXCEPTION_COLLIDED_UNWIND;
  15. UNWIND_HISTORY_TABLE_SIZE = 12;
  16. UNW_FLAG_NHANDLER = 0;
  17. {$ifdef CPUAARCH64}
  18. ARM64_MAX_BREAKPOINTS = 8;
  19. ARM64_MAX_WATCHPOINTS = 2;
  20. {$endif CPUAARCH64}
  21. type
  22. PM128A=^M128A;
  23. M128A = record
  24. Low : QWord;
  25. High : Int64;
  26. end;
  27. PContext = ^TContext;
  28. {$if defined(CPUX86_64)}
  29. TContext = record
  30. P1Home : QWord;
  31. P2Home : QWord;
  32. P3Home : QWord;
  33. P4Home : QWord;
  34. P5Home : QWord;
  35. P6Home : QWord;
  36. ContextFlags : DWord;
  37. MxCsr : DWord;
  38. SegCs : word;
  39. SegDs : word;
  40. SegEs : word;
  41. SegFs : word;
  42. SegGs : word;
  43. SegSs : word;
  44. EFlags : DWord;
  45. Dr0 : QWord;
  46. Dr1 : QWord;
  47. Dr2 : QWord;
  48. Dr3 : QWord;
  49. Dr6 : QWord;
  50. Dr7 : QWord;
  51. Rax : QWord;
  52. Rcx : QWord;
  53. Rdx : QWord;
  54. Rbx : QWord;
  55. Rsp : QWord;
  56. Rbp : QWord;
  57. Rsi : QWord;
  58. Rdi : QWord;
  59. R8 : QWord;
  60. R9 : QWord;
  61. R10 : QWord;
  62. R11 : QWord;
  63. R12 : QWord;
  64. R13 : QWord;
  65. R14 : QWord;
  66. R15 : QWord;
  67. Rip : QWord;
  68. Header : array[0..1] of M128A;
  69. Legacy : array[0..7] of M128A;
  70. Xmm0 : M128A;
  71. Xmm1 : M128A;
  72. Xmm2 : M128A;
  73. Xmm3 : M128A;
  74. Xmm4 : M128A;
  75. Xmm5 : M128A;
  76. Xmm6 : M128A;
  77. Xmm7 : M128A;
  78. Xmm8 : M128A;
  79. Xmm9 : M128A;
  80. Xmm10 : M128A;
  81. Xmm11 : M128A;
  82. Xmm12 : M128A;
  83. Xmm13 : M128A;
  84. Xmm14 : M128A;
  85. Xmm15 : M128A;
  86. VectorRegister : array[0..25] of M128A;
  87. VectorControl : QWord;
  88. DebugControl : QWord;
  89. LastBranchToRip : QWord;
  90. LastBranchFromRip : QWord;
  91. LastExceptionToRip : QWord;
  92. LastExceptionFromRip : QWord;
  93. end;
  94. { This is a simplified definition, only array part of unions }
  95. PKNONVOLATILE_CONTEXT_POINTERS=^KNONVOLATILE_CONTEXT_POINTERS;
  96. KNONVOLATILE_CONTEXT_POINTERS=record
  97. FloatingContext: array[0..15] of PM128A;
  98. IntegerContext: array[0..15] of PQWord;
  99. end;
  100. {$elseif defined(CPUAARCH64)}
  101. TContext = record
  102. ContextFlags: DWord;
  103. Cpsr: DWord;
  104. X0: QWord;
  105. X1: QWord;
  106. X2: QWord;
  107. X3: QWord;
  108. X4: QWord;
  109. X5: QWord;
  110. X6: QWord;
  111. X7: QWord;
  112. X8: QWord;
  113. X9: QWord;
  114. X10: QWord;
  115. X11: QWord;
  116. X12: QWord;
  117. X13: QWord;
  118. X14: QWord;
  119. X15: QWord;
  120. X16: QWord;
  121. X17: QWord;
  122. X18: QWord;
  123. X19: QWord;
  124. X20: QWord;
  125. X21: QWord;
  126. X22: QWord;
  127. X23: QWord;
  128. X24: QWord;
  129. X25: QWord;
  130. X26: QWord;
  131. X27: QWord;
  132. X28: QWord;
  133. Fp: QWord;
  134. Lr: QWord;
  135. Sp: QWord;
  136. Pc: QWord;
  137. V: array[0..31] of M128A;
  138. Fpcr: DWord;
  139. Fpsr: DWord;
  140. Bcr: array[0..ARM64_MAX_BREAKPOINTS-1] of DWord;
  141. Bvr: array[0..ARM64_MAX_BREAKPOINTS-1] of QWord;
  142. Wcr: array[0..ARM64_MAX_WATCHPOINTS-1] of DWord;
  143. Wvr: array[0..ARM64_MAX_WATCHPOINTS-1] of QWord;
  144. end;
  145. { This is a simplified definition, only array part of unions }
  146. PKNONVOLATILE_CONTEXT_POINTERS=^KNONVOLATILE_CONTEXT_POINTERS;
  147. KNONVOLATILE_CONTEXT_POINTERS=record
  148. IntegerContext: array[0..12] of PQWord;
  149. FloatingContext: array[0..7] of PM128A;
  150. end;
  151. {$endif NOT (X86_64 or AARCH64)}
  152. PExceptionPointers = ^TExceptionPointers;
  153. TExceptionPointers = record
  154. ExceptionRecord : PExceptionRecord;
  155. ContextRecord : PContext;
  156. end;
  157. EXCEPTION_ROUTINE = function(
  158. var ExceptionRecord: TExceptionRecord;
  159. EstablisherFrame: Pointer;
  160. var ContextRecord: TContext;
  161. DispatcherContext: Pointer ): EXCEPTION_DISPOSITION;
  162. PRUNTIME_FUNCTION=^RUNTIME_FUNCTION;
  163. {$if defined(CPUX86_64)}
  164. RUNTIME_FUNCTION=record
  165. BeginAddress: DWORD;
  166. EndAddress: DWORD;
  167. UnwindData: DWORD;
  168. end;
  169. {$elseif defined(CPUAARCH64)}
  170. RUNTIME_FUNCTION=record
  171. BeginAddress: DWORD;
  172. UnwindData: DWORD;
  173. end;
  174. {$endif}
  175. UNWIND_HISTORY_TABLE_ENTRY=record
  176. ImageBase: QWord;
  177. FunctionEntry: PRUNTIME_FUNCTION;
  178. end;
  179. PUNWIND_HISTORY_TABLE=^UNWIND_HISTORY_TABLE;
  180. UNWIND_HISTORY_TABLE=record
  181. Count: DWORD;
  182. Search: Byte;
  183. RaiseStatusIndex: Byte;
  184. Unwind: Byte;
  185. Exception: Byte;
  186. LowAddress: QWord;
  187. HighAddress: QWord;
  188. Entry: array[0..UNWIND_HISTORY_TABLE_SIZE-1] of UNWIND_HISTORY_TABLE_ENTRY;
  189. end;
  190. PDispatcherContext = ^TDispatcherContext;
  191. TDispatcherContext = record
  192. ControlPc: QWord;
  193. ImageBase: QWord;
  194. FunctionEntry: PRUNTIME_FUNCTION;
  195. EstablisherFrame: QWord;
  196. TargetIp: QWord;
  197. ContextRecord: PContext;
  198. LanguageHandler: EXCEPTION_ROUTINE;
  199. HandlerData: Pointer;
  200. HistoryTable: PUNWIND_HISTORY_TABLE;
  201. ScopeIndex: DWord;
  202. {$if defined(CPUX86_64)}
  203. Fill0: DWord;
  204. {$elseif defined(CPUAARCH64)}
  205. ControlPCIsUnwound: Byte;
  206. NonVolatileRegisters: PByte;
  207. {$endif}
  208. end;
  209. procedure RtlCaptureContext(var ctx: TContext); stdcall;
  210. external 'kernel32.dll' name 'RtlCaptureContext';
  211. function RtlCaptureStackBackTrace(
  212. FramesToSkip: DWORD;
  213. FramesToCapture: DWORD;
  214. var BackTrace: Pointer;
  215. BackTraceHash: PDWORD): Word; stdcall;
  216. external 'kernel32.dll' name 'RtlCaptureStackBackTrace';
  217. function RtlLookupFunctionEntry(
  218. ControlPC: QWord;
  219. out ImageBase: QWord;
  220. HistoryTable: PUNWIND_HISTORY_TABLE): PRUNTIME_FUNCTION;
  221. external 'kernel32.dll' name 'RtlLookupFunctionEntry';
  222. function RtlVirtualUnwind(
  223. HandlerType: DWORD;
  224. ImageBase: QWord;
  225. ControlPc: QWord;
  226. FunctionEntry: PRUNTIME_FUNCTION;
  227. var ContextRecord: TContext;
  228. HandlerData: PPointer;
  229. EstablisherFrame: PQWord;
  230. ContextPointers: PKNONVOLATILE_CONTEXT_POINTERS): EXCEPTION_ROUTINE;
  231. external 'kernel32.dll' name 'RtlVirtualUnwind';
  232. procedure RtlUnwindEx(
  233. TargetFrame: Pointer;
  234. TargetIp: Pointer;
  235. ExceptionRecord: PExceptionRecord;
  236. ReturnValue: Pointer;
  237. OriginalContext: PContext; { scratch space, initial contents ignored }
  238. HistoryTable: PUNWIND_HISTORY_TABLE);
  239. external 'kernel32.dll' name 'RtlUnwindEx';
  240. { FPC specific stuff }
  241. {$ifdef SYSTEM_USE_WIN_SEH}
  242. function ContextGetIP(const Context: TContext): PtrUInt; inline;
  243. begin
  244. {$if defined(CPUX86_64)}
  245. Result := Context.Rip;
  246. {$elseif defined(CPUAARCH64)}
  247. Result := Context.Pc;
  248. {$endif}
  249. end;
  250. procedure ContextSetIP(var Context: TContext; IP: PtrUInt); inline;
  251. begin
  252. {$if defined(CPUX86_64)}
  253. Context.Rip := IP;
  254. {$elseif defined(CPUAARCH64)}
  255. Context.Pc := IP;
  256. {$endif}
  257. end;
  258. function ContextGetFP(const Context: TContext): PtrUInt; inline;
  259. begin
  260. {$if defined(CPUX86_64)}
  261. Result := Context.Rbp;
  262. {$elseif defined(CPUAARCH64)}
  263. Result := Context.Fp;
  264. {$endif}
  265. end;
  266. const
  267. SCOPE_FINALLY=0;
  268. SCOPE_CATCHALL=1;
  269. SCOPE_IMPLICIT=2;
  270. type
  271. PScopeRec=^TScopeRec;
  272. TScopeRec=record
  273. Typ: DWord; { SCOPE_FINALLY: finally code in RvaHandler
  274. SCOPE_CATCHALL: unwinds to RvaEnd, RvaHandler is the end of except block
  275. SCOPE_IMPLICIT: finally code in RvaHandler, unwinds to RvaEnd
  276. otherwise: except with 'on' stmts, value is RVA of filter data }
  277. RvaStart: DWord;
  278. RvaEnd: DWord;
  279. RvaHandler: DWord;
  280. end;
  281. function CaptureBacktrace(skipframes,count:sizeint;frames:PCodePointer):sizeint;
  282. begin
  283. { skipframes is increased because this function adds a call level }
  284. Result:=RtlCaptureStackBackTrace(skipframes+1,count,frames^,nil);
  285. end;
  286. { note: context must be passed by value, so modifications are made to a local copy }
  287. function GetBacktrace(Context: TContext; StartingFrame: Pointer; out Frames: PPointer): Longint;
  288. var
  289. UnwindHistory: UNWIND_HISTORY_TABLE;
  290. RuntimeFunction: PRUNTIME_FUNCTION;
  291. HandlerData: Pointer;
  292. EstablisherFrame: QWord;
  293. ImageBase: QWord;
  294. FrameCount,FrameBufSize: Longint;
  295. begin
  296. FillChar(UnwindHistory,sizeof(UNWIND_HISTORY_TABLE),0);
  297. UnwindHistory.Unwind:=1;
  298. FrameCount:=0;
  299. FrameBufSize:=0;
  300. Frames:=nil;
  301. repeat
  302. RuntimeFunction:=RtlLookupFunctionEntry(ContextGetIP(Context), ImageBase, @UnwindHistory);
  303. if Assigned(RuntimeFunction) then
  304. RtlVirtualUnwind(UNW_FLAG_NHANDLER, ImageBase, ContextGetIP(Context),
  305. RuntimeFunction, Context, @HandlerData, @EstablisherFrame, nil)
  306. else { a leaf function }
  307. begin
  308. {$if defined(CPUX86_64)}
  309. Context.Rip:=PQWord(Context.Rsp)^;
  310. Inc(Context.Rsp, sizeof(Pointer));
  311. {$elseif defined(CPUAARCH64)}
  312. { ToDo }
  313. //Context.Pc:=Context.Lr;
  314. ContextSetIP(Context,0);
  315. {$else}
  316. ContextSetIP(Context,0);
  317. {$endif}
  318. end;
  319. if (ContextGetIP(Context)=0) or (FrameCount>=RaiseMaxFrameCount) then
  320. break;
  321. { The StartingFrame provides a way to skip several initial calls.
  322. It's better to specify the number of skipped calls directly,
  323. because the very purpose of this function is to retrieve stacktrace
  324. even in optimized code (i.e. without rbp-based frames). But that's
  325. limited by factors such as 'raise' syntax. }
  326. if (Pointer(ContextGetFP(Context))>StartingFrame) or (FrameCount>0) then
  327. begin
  328. if (FrameCount>=FrameBufSize) then
  329. begin
  330. Inc(FrameBufSize,16);
  331. ReallocMem(Frames,FrameBufSize*sizeof(Pointer));
  332. end;
  333. Frames[FrameCount]:=Pointer(ContextGetIP(Context));
  334. Inc(FrameCount);
  335. end;
  336. until False;
  337. Result:=FrameCount;
  338. end;
  339. function RunErrorCodeSEH(const rec: TExceptionRecord; const context: TContext): Longint;
  340. begin
  341. result:=RunErrorCode(rec);
  342. {$if defined(CPUX86_64)}
  343. if (result=-255) then
  344. TranslateMxcsr(context.MxCsr,result);
  345. {$endif}
  346. end;
  347. {$push}
  348. {$codealign localmin=16} { TContext record requires this }
  349. procedure fpc_RaiseException(Obj: TObject; AnAddr,AFrame: Pointer); [public,alias: 'FPC_RAISEEXCEPTION']; compilerproc;
  350. var
  351. ctx: TContext;
  352. args: array[0..3] of PtrUint;
  353. begin
  354. RtlCaptureContext(ctx);
  355. args[0]:=PtrUint(AnAddr);
  356. args[1]:=PtrUint(Obj);
  357. args[2]:=GetBacktrace(ctx,AFrame,PPointer(args[3]));
  358. RaiseException(FPC_EXCEPTION_CODE,EXCEPTION_NONCONTINUABLE,4,@args[0]);
  359. end;
  360. procedure _fpc_local_unwind(frame,target: Pointer);[public,alias:'_FPC_local_unwind'];compilerproc;
  361. var
  362. ctx: TContext;
  363. begin
  364. RtlUnwindEx(frame,target,nil,nil,@ctx,nil);
  365. end;
  366. {$pop}
  367. procedure fpc_reraise; [public,alias:'FPC_RERAISE']; compilerproc;
  368. var
  369. hp : PExceptObject;
  370. args: array[0..3] of PtrUint;
  371. begin
  372. hp:=ExceptObjectStack;
  373. args[0]:=PtrUint(hp^.addr); { copy and clear the exception stack top }
  374. args[1]:=PtrUint(hp^.FObject);
  375. args[2]:=hp^.FrameCount;
  376. args[3]:=PtrUint(hp^.Frames);
  377. hp^.refcount:=0;
  378. hp^.FObject:=nil;
  379. hp^.Frames:=nil;
  380. RaiseException(FPC_EXCEPTION_CODE,EXCEPTION_NONCONTINUABLE,4,@args[0]);
  381. end;
  382. {$ifdef DEBUG_SEH}
  383. procedure PrintScope(idx: integer; scope: PScopeRec);
  384. begin
  385. if IsConsole then
  386. begin
  387. write(stderr,'Scope #',idx,' ',hexstr(Scope^.RvaStart,8),' - ',hexStr(Scope^.RvaEnd,8));
  388. writeln(stderr,' type=',Scope^.Typ);
  389. end;
  390. end;
  391. {$endif DEBUG_SEH}
  392. function PushException(var rec: TExceptionRecord; var context: TContext;
  393. out obj: TObject; AcceptNull: Boolean): Boolean;
  394. var
  395. adr: Pointer;
  396. Exc: PExceptObject;
  397. Frames: PPointer;
  398. FrameCount: Longint;
  399. code: Longint;
  400. begin
  401. Adr:=rec.ExceptionInformation[0];
  402. Obj:=TObject(rec.ExceptionInformation[1]);
  403. Framecount:=Longint(PtrUInt(rec.ExceptionInformation[2]));
  404. Frames:=rec.ExceptionInformation[3];
  405. if rec.ExceptionCode<>FPC_EXCEPTION_CODE then
  406. begin
  407. Obj:=nil;
  408. Result:=False;
  409. code:=RunErrorCodeSEH(rec,context);
  410. if Assigned(ExceptObjProc) then
  411. Obj:=TObject(TExceptObjProc(ExceptObjProc)(abs(code),rec));
  412. if (Obj=nil) and (not AcceptNull) then
  413. Exit;
  414. adr:=rec.ExceptionAddress;
  415. FrameCount:=GetBacktrace(context,nil,Frames);
  416. if code<0 then
  417. SysResetFPU;
  418. end;
  419. New(Exc);
  420. Exc^.FObject:=Obj;
  421. Exc^.Addr:=adr;
  422. Exc^.Frames:=Frames;
  423. Exc^.FrameCount:=FrameCount;
  424. Exc^.Refcount:=0;
  425. { link to RaiseList }
  426. Exc^.Next:=ExceptObjectStack;
  427. ExceptObjectStack:=Exc;
  428. Result:=True;
  429. end;
  430. { This is an outermost exception handler, installed using assembler around the
  431. entrypoint and thread procedures. Its sole purpose is to provide sensible exitcode. }
  432. function __FPC_default_handler(
  433. var rec: TExceptionRecord;
  434. frame: Pointer;
  435. var context: TCONTEXT;
  436. var dispatch: TDispatcherContext): EXCEPTION_DISPOSITION; [public,alias:'__FPC_DEFAULT_HANDLER'];
  437. label L1;
  438. var
  439. exc: PExceptObject;
  440. obj: TObject;
  441. hstdout: ^text;
  442. i,code: Longint;
  443. begin
  444. if (rec.ExceptionFlags and EXCEPTION_UNWIND)=0 then
  445. begin
  446. {$ifdef CPUX86_64}
  447. { Athlon prefetch bug? }
  448. if (rec.ExceptionCode=STATUS_ACCESS_VIOLATION) and is_prefetch(pointer(ContextGetIP(Context))) then
  449. begin
  450. result:=ExceptionContinueExecution;
  451. exit;
  452. end;
  453. {$endif CPUX86_64}
  454. PushException(rec,context,obj,True);
  455. RtlUnwindEx(frame, @L1, @rec, nil, dispatch.ContextRecord, dispatch.HistoryTable);
  456. end
  457. else if (rec.ExceptionFlags and EXCEPTION_TARGET_UNWIND)<>0 then
  458. begin
  459. Exc:=ExceptObjectStack;
  460. if Exc^.FObject=nil then
  461. begin
  462. hstdout:=@stdout;
  463. code:=abs(RunErrorCodeSEH(rec,context));
  464. Writeln(hstdout^,'Runtime error ',code,' at $',hexstr(Exc^.addr));
  465. Writeln(hstdout^,BackTraceStrFunc(Exc^.Addr));
  466. if (Exc^.FrameCount>0) then
  467. begin
  468. for i:=0 to Exc^.FrameCount-1 do
  469. Writeln(hstdout^,BackTraceStrFunc(Exc^.Frames[i]));
  470. end;
  471. Writeln(hstdout^,'');
  472. ErrorCode:=word(code);
  473. Halt(code);
  474. end
  475. else
  476. begin
  477. { if ExceptObjProc=nil, ExceptProc is typically also nil,
  478. so we cannot make much use of this backtrace }
  479. if Assigned(ExceptProc) then
  480. begin
  481. ExceptProc(Exc^.FObject,Exc^.Addr,Exc^.FrameCount,Exc^.Frames);
  482. Halt(217);
  483. end;
  484. L1:
  485. { RtlUnwindEx above resets execution context to the point where the handler
  486. was installed, i.e. main_wrapper. It makes exiting this procedure no longer
  487. possible. Halting is the only possible action here.
  488. Furthermore, this is not expected to execute at all, because the above block
  489. definitely halts. }
  490. Halt(217);
  491. end;
  492. end;
  493. result:=ExceptionContinueSearch;
  494. end;
  495. { This handler is installed by compiler for every try..finally and try..except statement,
  496. including implicit ones. }
  497. function __FPC_specific_handler(
  498. var rec: TExceptionRecord;
  499. frame: Pointer;
  500. var context: TCONTEXT;
  501. var dispatch: TDispatcherContext): EXCEPTION_DISPOSITION; [public,alias:'__FPC_specific_handler'];
  502. var
  503. TargetRva,ControlRva: DWord;
  504. scope: PScopeRec;
  505. scopeIdx: DWord;
  506. TargetAddr: Pointer;
  507. obj:TObject;
  508. begin
  509. {$ifdef DEBUG_SEH}
  510. if IsConsole then
  511. begin
  512. writeln(stderr,'Exception handler for ',BacktraceStrFunc(Pointer(dispatch.FunctionEntry^.BeginAddress+dispatch.ImageBase)));
  513. writeln(stderr,'Code=', hexstr(rec.ExceptionCode,8),' Flags=',hexstr(rec.ExceptionFlags,2), ' CtrlPc=',hexstr(dispatch.ControlPc,16));
  514. end;
  515. {$endif DEBUG_SEH}
  516. result:=ExceptionContinueSearch;
  517. ControlRva:=dispatch.ControlPc-dispatch.ImageBase;
  518. ScopeIdx:=dispatch.ScopeIndex;
  519. if (rec.ExceptionFlags and EXCEPTION_UNWIND)=0 then
  520. begin
  521. while ScopeIdx<PDWord(dispatch.HandlerData)^ do
  522. begin
  523. scope:=@PScopeRec(dispatch.HandlerData+sizeof(Dword))[ScopeIdx];
  524. {$ifdef DEBUG_SEH}
  525. PrintScope(ScopeIdx, scope);
  526. {$endif DEBUG_SEH}
  527. { Check if the exception was raised in the 'except' block,
  528. and dispose the existing exception object if so. }
  529. if (ControlRva>=scope^.RvaEnd) and (ControlRva<scope^.RvaHandler) and
  530. ((scope^.Typ=SCOPE_CATCHALL) or (scope^.Typ>SCOPE_IMPLICIT)) then
  531. Internal_PopObjectStack.Free
  532. else if (ControlRva>=scope^.RvaStart) and (ControlRva<scope^.RvaEnd) and
  533. (scope^.Typ<>SCOPE_FINALLY)then
  534. begin
  535. {$ifdef CPUX86_64}
  536. { Athlon prefetch bug? }
  537. if (rec.ExceptionCode=STATUS_ACCESS_VIOLATION) and is_prefetch(pointer(ContextGetIP(Context))) then
  538. begin
  539. result:=ExceptionContinueExecution;
  540. exit;
  541. end;
  542. {$endif CPUX86_64}
  543. if scope^.Typ>SCOPE_IMPLICIT then // filtering needed
  544. begin
  545. TargetAddr:=FilterException(rec,dispatch.ImageBase,scope^.Typ,abs(RunErrorCodeSEH(rec,context)));
  546. if TargetAddr=nil then
  547. begin
  548. Inc(ScopeIdx);
  549. Continue;
  550. end;
  551. end
  552. else
  553. TargetAddr:=Pointer(scope^.RvaEnd+dispatch.ImageBase);
  554. {$ifdef DEBUG_SEH}
  555. if IsConsole then
  556. writeln(stderr,'match at scope #',scopeIdx,', unwind target=',hexstr(TargetAddr));
  557. {$endif DEBUG_SEH}
  558. if not PushException(rec,context,obj,Scope^.Typ=SCOPE_IMPLICIT) then
  559. Exit;
  560. { Does not return, control is transferred to TargetAddr,
  561. obj is placed into RAX. }
  562. RtlUnwindEx(frame, TargetAddr, @rec, obj, dispatch.ContextRecord, dispatch.HistoryTable);
  563. end;
  564. Inc(ScopeIdx);
  565. end;
  566. end
  567. else
  568. begin
  569. TargetRva:=dispatch.TargetIp-dispatch.ImageBase;
  570. {$ifdef DEBUG_SEH}
  571. if IsConsole then
  572. writeln(stderr,'Unwind, TargetRva=',hexstr(TargetRva,8),' CtrlRva=',hexstr(ControlRva,8),' idx=',ScopeIdx);
  573. {$endif DEBUG_SEH}
  574. while ScopeIdx<PDword(dispatch.HandlerData)^ do
  575. begin
  576. scope:=@PScopeRec(dispatch.HandlerData+sizeof(Dword))[ScopeIdx];
  577. {$ifdef DEBUG_SEH}
  578. PrintScope(scopeIdx, scope);
  579. {$endif DEBUG_SEH}
  580. if (ControlRva>=scope^.RvaStart) and (ControlRva<scope^.RvaEnd) and
  581. ((scope^.Typ=SCOPE_FINALLY) or (scope^.Typ=SCOPE_IMPLICIT)) then
  582. begin
  583. if (TargetRva>=scope^.RvaStart) and (TargetRva<scope^.RvaEnd) and
  584. ((rec.ExceptionFlags and EXCEPTION_TARGET_UNWIND)<>0) then
  585. begin
  586. Exit;
  587. end;
  588. dispatch.ScopeIndex:=ScopeIdx+1;
  589. {$ifdef DEBUG_SEH}
  590. if IsConsole then
  591. writeln(stderr,'calling handler @',hexstr(dispatch.imagebase+scope^.RvaHandler,16));
  592. {$endif DEBUG_SEH}
  593. TUnwindProc(dispatch.ImageBase+scope^.RvaHandler)(ContextGetFP(context));
  594. end;
  595. Inc(ScopeIdx);
  596. end;
  597. end;
  598. end;
  599. {$endif SYSTEM_USE_WIN_SEH}