seh64.inc 19 KB

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