seh64.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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_NONCONTINUABLE = $01;
  14. EXCEPTION_UNWINDING = $02;
  15. EXCEPTION_EXIT_UNWIND = $04;
  16. EXCEPTION_STACK_INVALID = $08;
  17. EXCEPTION_NESTED_CALL = $10;
  18. EXCEPTION_TARGET_UNWIND = $20;
  19. EXCEPTION_COLLIDED_UNWIND = $40;
  20. EXCEPTION_UNWIND = $66;
  21. UNWIND_HISTORY_TABLE_SIZE = 12;
  22. UNW_FLAG_NHANDLER = 0;
  23. type
  24. PM128A=^M128A;
  25. M128A = record
  26. Low : QWord;
  27. High : Int64;
  28. end;
  29. PContext = ^TContext;
  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. EXCEPTION_DISPOSITION=(
  102. ExceptionContinueExecution,
  103. ExceptionContinueSearch,
  104. ExceptionNestedException,
  105. ExceptionCollidedUnwind
  106. );
  107. PExceptionPointers = ^TExceptionPointers;
  108. TExceptionPointers = record
  109. ExceptionRecord : PExceptionRecord;
  110. ContextRecord : PContext;
  111. end;
  112. EXCEPTION_ROUTINE = function(
  113. var ExceptionRecord: TExceptionRecord;
  114. EstablisherFrame: Pointer;
  115. var ContextRecord: TContext;
  116. DispatcherContext: Pointer ): EXCEPTION_DISPOSITION;
  117. PRUNTIME_FUNCTION=^RUNTIME_FUNCTION;
  118. RUNTIME_FUNCTION=record
  119. BeginAddress: DWORD;
  120. EndAddress: DWORD;
  121. UnwindData: DWORD;
  122. end;
  123. UNWIND_HISTORY_TABLE_ENTRY=record
  124. ImageBase: QWord;
  125. FunctionEntry: PRUNTIME_FUNCTION;
  126. end;
  127. PUNWIND_HISTORY_TABLE=^UNWIND_HISTORY_TABLE;
  128. UNWIND_HISTORY_TABLE=record
  129. Count: DWORD;
  130. Search: Byte;
  131. RaiseStatusIndex: Byte;
  132. Unwind: Byte;
  133. Exception: Byte;
  134. LowAddress: QWord;
  135. HighAddress: QWord;
  136. Entry: array[0..UNWIND_HISTORY_TABLE_SIZE-1] of UNWIND_HISTORY_TABLE_ENTRY;
  137. end;
  138. PDispatcherContext = ^TDispatcherContext;
  139. TDispatcherContext = record
  140. ControlPc: QWord;
  141. ImageBase: QWord;
  142. FunctionEntry: PRUNTIME_FUNCTION;
  143. EstablisherFrame: QWord;
  144. TargetIp: QWord;
  145. ContextRecord: PContext;
  146. LanguageHandler: EXCEPTION_ROUTINE;
  147. HandlerData: Pointer;
  148. HistoryTable: PUNWIND_HISTORY_TABLE;
  149. ScopeIndex: DWord;
  150. Fill0: DWord;
  151. end;
  152. procedure RtlCaptureContext(var ctx: TContext); stdcall;
  153. external 'kernel32.dll' name 'RtlCaptureContext';
  154. function RtlCaptureStackBackTrace(
  155. FramesToSkip: DWORD;
  156. FramesToCapture: DWORD;
  157. var BackTrace: Pointer;
  158. BackTraceHash: PDWORD): Word; stdcall;
  159. external 'kernel32.dll' name 'RtlCaptureStackBackTrace';
  160. function RtlLookupFunctionEntry(
  161. ControlPC: QWord;
  162. out ImageBase: QWord;
  163. HistoryTable: PUNWIND_HISTORY_TABLE): PRUNTIME_FUNCTION;
  164. external 'kernel32.dll' name 'RtlLookupFunctionEntry';
  165. function RtlVirtualUnwind(
  166. HandlerType: DWORD;
  167. ImageBase: QWord;
  168. ControlPc: QWord;
  169. FunctionEntry: PRUNTIME_FUNCTION;
  170. var ContextRecord: TContext;
  171. HandlerData: PPointer;
  172. EstablisherFrame: PQWord;
  173. ContextPointers: PKNONVOLATILE_CONTEXT_POINTERS): EXCEPTION_ROUTINE;
  174. external 'kernel32.dll' name 'RtlVirtualUnwind';
  175. procedure RtlUnwindEx(
  176. TargetFrame: Pointer;
  177. TargetIp: Pointer;
  178. ExceptionRecord: PExceptionRecord;
  179. ReturnValue: Pointer;
  180. OriginalContext: PContext; { scratch space, initial contents ignored }
  181. HistoryTable: PUNWIND_HISTORY_TABLE);
  182. external 'kernel32.dll' name 'RtlUnwindEx';
  183. procedure RaiseException(
  184. dwExceptionCode: DWORD;
  185. dwExceptionFlags: DWORD;
  186. dwArgCount: DWORD;
  187. lpArguments: Pointer); // msdn: *ULONG_PTR
  188. external 'kernel32.dll' name 'RaiseException';
  189. { FPC specific stuff }
  190. {$ifdef FPC_USE_WIN64_SEH}
  191. const
  192. FPC_EXCEPTION_CODE=$E0465043;
  193. SCOPE_FINALLY=0;
  194. SCOPE_CATCHALL=1;
  195. SCOPE_IMPLICIT=2;
  196. type
  197. PScopeRec=^TScopeRec;
  198. TScopeRec=record
  199. Typ: DWord; { SCOPE_FINALLY: finally code in RvaHandler
  200. SCOPE_CATCHALL: unwinds to RvaEnd, RvaHandler is the end of except block
  201. SCOPE_IMPLICIT: finally code in RvaHandler, unwinds to RvaEnd
  202. otherwise: except with 'on' stmts, value is RVA of filter data }
  203. RvaStart: DWord;
  204. RvaEnd: DWord;
  205. RvaHandler: DWord;
  206. end;
  207. PFilterRec=^TFilterRec;
  208. TFilterRec=record
  209. RvaClass: DWord;
  210. RvaHandler: DWord;
  211. end;
  212. TUnwindProc=procedure(frame: QWord);
  213. TExceptObjProc=function(code: Longint; const rec: TExceptionRecord): Pointer; { Exception }
  214. TExceptClsProc=function(code: Longint): Pointer; { ExceptClass }
  215. { note: context must be passed by value, so modifications are made to a local copy }
  216. function GetBacktrace(Context: TContext; StartingFrame: Pointer; out Frames: PPointer): Longint;
  217. var
  218. UnwindHistory: UNWIND_HISTORY_TABLE;
  219. RuntimeFunction: PRUNTIME_FUNCTION;
  220. HandlerData: Pointer;
  221. EstablisherFrame: QWord;
  222. ImageBase: QWord;
  223. FrameCount,FrameBufSize: Longint;
  224. begin
  225. FillChar(UnwindHistory,sizeof(UNWIND_HISTORY_TABLE),0);
  226. UnwindHistory.Unwind:=1;
  227. FrameCount:=0;
  228. FrameBufSize:=0;
  229. Frames:=nil;
  230. repeat
  231. RuntimeFunction:=RtlLookupFunctionEntry(Context.Rip, ImageBase, @UnwindHistory);
  232. if Assigned(RuntimeFunction) then
  233. RtlVirtualUnwind(UNW_FLAG_NHANDLER, ImageBase, Context.Rip,
  234. RuntimeFunction, Context, @HandlerData, @EstablisherFrame, nil)
  235. else { a leaf function }
  236. begin
  237. Context.Rip:=PQWord(Context.Rsp)^;
  238. Inc(Context.Rsp, sizeof(Pointer));
  239. end;
  240. if (Context.Rip=0) or (FrameCount>=RaiseMaxFrameCount) then
  241. break;
  242. { The StartingFrame provides a way to skip several initial calls.
  243. It's better to specify the number of skipped calls directly,
  244. because the very purpose of this function is to retrieve stacktrace
  245. even in optimized code (i.e. without rbp-based frames). But that's
  246. limited by factors such as 'raise' syntax. }
  247. if (Pointer(Context.Rbp)>StartingFrame) or (FrameCount>0) then
  248. begin
  249. if (FrameCount>=FrameBufSize) then
  250. begin
  251. Inc(FrameBufSize,16);
  252. ReallocMem(Frames,FrameBufSize*sizeof(Pointer));
  253. end;
  254. Frames[FrameCount]:=Pointer(Context.Rip);
  255. Inc(FrameCount);
  256. end;
  257. until False;
  258. Result:=FrameCount;
  259. end;
  260. {$push}
  261. {$codealign localmin=16} { TContext record requires this }
  262. function fpc_RaiseException(Obj: TObject; AnAddr,AFrame: Pointer): TObject; [public,alias: 'FPC_RAISEEXCEPTION']; compilerproc;
  263. var
  264. ctx: TContext;
  265. args: array[0..3] of PtrUint;
  266. begin
  267. RtlCaptureContext(ctx);
  268. args[0]:=PtrUint(AnAddr);
  269. args[1]:=PtrUint(Obj);
  270. args[2]:=GetBacktrace(ctx,AFrame,PPointer(args[3]));
  271. RaiseException(FPC_EXCEPTION_CODE,EXCEPTION_NONCONTINUABLE,4,@args[0]);
  272. end;
  273. procedure localUnwind(frame,target: Pointer);[public,alias:'_FPC_local_unwind'];
  274. var
  275. ctx: TContext;
  276. begin
  277. RtlUnwindEx(frame,target,nil,nil,@ctx,nil);
  278. end;
  279. {$pop}
  280. procedure fpc_reraise; [public,alias:'FPC_RERAISE']; compilerproc;
  281. var
  282. hp : PExceptObject;
  283. args: array[0..3] of PtrUint;
  284. begin
  285. hp:=ExceptObjectStack;
  286. args[0]:=PtrUint(hp^.addr); { copy and clear the exception stack top }
  287. args[1]:=PtrUint(hp^.FObject);
  288. args[2]:=hp^.FrameCount;
  289. args[3]:=PtrUint(hp^.Frames);
  290. hp^.refcount:=0;
  291. hp^.FObject:=nil;
  292. hp^.Frames:=nil;
  293. RaiseException(FPC_EXCEPTION_CODE,EXCEPTION_NONCONTINUABLE,4,@args[0]);
  294. end;
  295. { The only difference from fpc_reraise is removing the topmost exception.
  296. Normally this is done in __FPC_specific_handler, but it won't work for implicit
  297. frames, as there's no room in scope record to store the end rva of 'except' part.
  298. This can only happen in functions which return managed result in register;
  299. eventually compiler must be fixed to return managed types in parameters only. }
  300. procedure fpc_reraise_implicit; [public,alias:'FPC_RERAISE_IMPLICIT'];
  301. var
  302. hp: PExceptObject;
  303. args: array[0..3] of PtrUInt;
  304. begin
  305. hp:=ExceptObjectStack;
  306. args[0]:=PtrUint(hp^.addr);
  307. args[1]:=PtrUint(hp^.FObject);
  308. args[2]:=hp^.FrameCount;
  309. args[3]:=PtrUint(hp^.Frames);
  310. hp^.refcount:=0;
  311. hp^.FObject:=nil;
  312. hp^.Frames:=nil;
  313. Internal_PopObjectStack.Free;
  314. RaiseException(FPC_EXCEPTION_CODE,EXCEPTION_NONCONTINUABLE,4,@args[0]);
  315. end;
  316. function RunErrorCode(const rec: TExceptionRecord): longint;
  317. begin
  318. { negative result means 'FPU reset required' }
  319. case rec.ExceptionCode of
  320. STATUS_INTEGER_DIVIDE_BY_ZERO: result := 200; { reDivByZero }
  321. STATUS_FLOAT_DIVIDE_BY_ZERO: result := -208; { !!reZeroDivide }
  322. STATUS_ARRAY_BOUNDS_EXCEEDED: result := 201; { reRangeError }
  323. STATUS_STACK_OVERFLOW: result := 202; { reStackOverflow }
  324. STATUS_FLOAT_OVERFLOW: result := -205; { reOverflow }
  325. STATUS_FLOAT_DENORMAL_OPERAND,
  326. STATUS_FLOAT_UNDERFLOW: result := -206; { reUnderflow }
  327. STATUS_FLOAT_INEXACT_RESULT,
  328. STATUS_FLOAT_INVALID_OPERATION,
  329. STATUS_FLOAT_STACK_CHECK: result := -207; { reInvalidOp }
  330. STATUS_INTEGER_OVERFLOW: result := 215; { reIntOverflow }
  331. STATUS_ILLEGAL_INSTRUCTION: result := -216;
  332. STATUS_ACCESS_VIOLATION: result := 216; { reAccessViolation }
  333. STATUS_CONTROL_C_EXIT: result := 217; { reControlBreak }
  334. STATUS_PRIVILEGED_INSTRUCTION: result := 218; { rePrivilegedInstruction }
  335. else
  336. result := 255; { reExternalException }
  337. end;
  338. end;
  339. function FilterException(var rec:TExceptionRecord; imagebase: QWord; scope: PScopeRec): Pointer;
  340. var
  341. ExClass: TClass;
  342. i: Longint;
  343. Filter: Pointer;
  344. curFilt: PFilterRec;
  345. begin
  346. result:=nil;
  347. if rec.ExceptionCode=FPC_EXCEPTION_CODE then
  348. ExClass:=TObject(rec.ExceptionInformation[1]).ClassType
  349. else if Assigned(ExceptClsProc) then
  350. ExClass:=TClass(TExceptClsProc(ExceptClsProc)(abs(RunErrorCode(rec))))
  351. else
  352. Exit; { if we cannot determine type of exception, don't handle it }
  353. Filter:=Pointer(imagebase+scope^.Typ);
  354. for i:=0 to PLongint(Filter)^-1 do
  355. begin
  356. CurFilt:=@PFilterRec(Filter+sizeof(Longint))[i];
  357. if (CurFilt^.RvaClass=$FFFFFFFF) or
  358. { TODO: exception might be coming from another module, need more advanced comparing }
  359. (ExClass.InheritsFrom(TClass(imagebase+CurFilt^.RvaClass))) then
  360. begin
  361. result:=Pointer(imagebase+CurFilt^.RvaHandler);
  362. exit;
  363. end;
  364. end;
  365. end;
  366. {$ifdef DEBUG_SEH}
  367. procedure PrintScope(idx: integer; scope: PScopeRec);
  368. begin
  369. if IsConsole then
  370. begin
  371. write(stderr,'Scope #',idx,' ',hexstr(Scope^.RvaStart,8),' - ',hexStr(Scope^.RvaEnd,8));
  372. writeln(stderr,' type=',Scope^.Typ);
  373. end;
  374. end;
  375. {$endif DEBUG_SEH}
  376. function PushException(var rec: TExceptionRecord; var context: TContext;
  377. out obj: TObject; AcceptNull: Boolean): Boolean;
  378. var
  379. adr: Pointer;
  380. Exc: PExceptObject;
  381. Frames: PPointer;
  382. FrameCount: Longint;
  383. code: Longint;
  384. begin
  385. Adr:=rec.ExceptionInformation[0];
  386. Obj:=TObject(rec.ExceptionInformation[1]);
  387. Framecount:=Longint(rec.ExceptionInformation[2]);
  388. Frames:=rec.ExceptionInformation[3];
  389. if rec.ExceptionCode<>FPC_EXCEPTION_CODE then
  390. begin
  391. Obj:=nil;
  392. Result:=False;
  393. code:=RunErrorCode(rec);
  394. if Assigned(ExceptObjProc) then
  395. Obj:=TObject(TExceptObjProc(ExceptObjProc)(abs(code),rec));
  396. if (Obj=nil) and (not AcceptNull) then
  397. Exit;
  398. adr:=rec.ExceptionAddress;
  399. FrameCount:=GetBacktrace(context,nil,Frames);
  400. if code<0 then
  401. SysResetFPU;
  402. end;
  403. New(Exc);
  404. Exc^.FObject:=Obj;
  405. Exc^.Addr:=adr;
  406. Exc^.Frames:=Frames;
  407. Exc^.FrameCount:=FrameCount;
  408. Exc^.Refcount:=0;
  409. { link to RaiseList }
  410. Exc^.Next:=ExceptObjectStack;
  411. ExceptObjectStack:=Exc;
  412. Result:=True;
  413. end;
  414. function __FPC_default_handler(
  415. var rec: TExceptionRecord;
  416. frame: Pointer;
  417. var context: TCONTEXT;
  418. var dispatch: TDispatcherContext): EXCEPTION_DISPOSITION; [public,alias:'__FPC_DEFAULT_HANDLER'];
  419. label L1;
  420. var
  421. exc: PExceptObject;
  422. obj: TObject;
  423. begin
  424. if (rec.ExceptionFlags and EXCEPTION_UNWIND)=0 then
  425. begin
  426. { Athlon prefetch bug? }
  427. if (rec.ExceptionCode=STATUS_ACCESS_VIOLATION) and is_prefetch(pointer(Context.rip)) then
  428. begin
  429. result:=ExceptionContinueExecution;
  430. exit;
  431. end;
  432. PushException(rec,context,obj,True);
  433. RtlUnwindEx(frame, @L1, @rec, nil, dispatch.ContextRecord, dispatch.HistoryTable);
  434. end
  435. else if (rec.ExceptionFlags and EXCEPTION_TARGET_UNWIND)<>0 then
  436. begin
  437. Exc:=ExceptObjectStack;
  438. if Exc^.FObject=nil then
  439. RunError(abs(RunErrorCode(rec))) // !!prints wrong backtrace
  440. else
  441. begin
  442. { if ExceptObjProc=nil, ExceptProc is typically also nil,
  443. so we cannot make much use of this backtrace }
  444. if Assigned(ExceptProc) then
  445. begin
  446. ExceptProc(Exc^.FObject,Exc^.Addr,Exc^.FrameCount,Exc^.Frames);
  447. Halt(217);
  448. end;
  449. L1:
  450. RunError(217);
  451. end;
  452. end;
  453. result:=ExceptionContinueSearch;
  454. end;
  455. function __FPC_specific_handler(
  456. var rec: TExceptionRecord;
  457. frame: Pointer;
  458. var context: TCONTEXT;
  459. var dispatch: TDispatcherContext): EXCEPTION_DISPOSITION; [public,alias:'__FPC_specific_handler'];
  460. var
  461. TargetRva,ControlRva: DWord;
  462. scope: PScopeRec;
  463. scopeIdx: DWord;
  464. TargetAddr: Pointer;
  465. obj:TObject;
  466. begin
  467. {$ifdef DEBUG_SEH}
  468. if IsConsole then
  469. begin
  470. writeln(stderr,'Exception handler for ',BacktraceStrFunc(Pointer(dispatch.FunctionEntry^.BeginAddress+dispatch.ImageBase)));
  471. writeln(stderr,'Code=', hexstr(rec.ExceptionCode,8),' Flags=',hexstr(rec.ExceptionFlags,2), ' CtrlPc=',hexstr(dispatch.ControlPc,16));
  472. end;
  473. {$endif DEBUG_SEH}
  474. result:=ExceptionContinueSearch;
  475. ControlRva:=dispatch.ControlPc-dispatch.ImageBase;
  476. ScopeIdx:=dispatch.ScopeIndex;
  477. if (rec.ExceptionFlags and EXCEPTION_UNWIND)=0 then
  478. begin
  479. while ScopeIdx<PDWord(dispatch.HandlerData)^ do
  480. begin
  481. scope:=@PScopeRec(dispatch.HandlerData+sizeof(Dword))[ScopeIdx];
  482. {$ifdef DEBUG_SEH}
  483. PrintScope(ScopeIdx, scope);
  484. {$endif DEBUG_SEH}
  485. { Check if the exception was raised in the 'except' block,
  486. and dispose the existing exception object if so. }
  487. if (ControlRva>=scope^.RvaEnd) and (ControlRva<scope^.RvaHandler) and
  488. ((scope^.Typ=SCOPE_CATCHALL) or (scope^.Typ>SCOPE_IMPLICIT)) then
  489. Internal_PopObjectStack.Free
  490. else if (ControlRva>=scope^.RvaStart) and (ControlRva<scope^.RvaEnd) and
  491. (scope^.Typ<>SCOPE_FINALLY)then
  492. begin
  493. { Athlon prefetch bug? }
  494. if (rec.ExceptionCode=STATUS_ACCESS_VIOLATION) and is_prefetch(pointer(Context.rip)) then
  495. begin
  496. result:=ExceptionContinueExecution;
  497. exit;
  498. end;
  499. if scope^.Typ>SCOPE_IMPLICIT then // filtering needed
  500. begin
  501. TargetAddr:=FilterException(rec,dispatch.ImageBase,scope);
  502. if TargetAddr=nil then
  503. begin
  504. Inc(ScopeIdx);
  505. Continue;
  506. end;
  507. end
  508. else
  509. TargetAddr:=Pointer(scope^.RvaEnd+dispatch.ImageBase);
  510. {$ifdef DEBUG_SEH}
  511. if IsConsole then
  512. writeln(stderr,'match at scope #',scopeIdx,', unwind target=',hexstr(TargetAddr));
  513. {$endif DEBUG_SEH}
  514. if not PushException(rec,context,obj,Scope^.Typ=SCOPE_IMPLICIT) then
  515. Exit;
  516. { Does not return, control is transferred to TargetAddr,
  517. obj is placed into RAX. }
  518. RtlUnwindEx(frame, TargetAddr, @rec, obj, dispatch.ContextRecord, dispatch.HistoryTable);
  519. end;
  520. Inc(ScopeIdx);
  521. end;
  522. end
  523. else
  524. begin
  525. TargetRva:=dispatch.TargetIp-dispatch.ImageBase;
  526. {$ifdef DEBUG_SEH}
  527. if IsConsole then
  528. writeln(stderr,'Unwind, TargetRva=',hexstr(TargetRva,8),' CtrlRva=',hexstr(ControlRva,8),' idx=',ScopeIdx);
  529. {$endif DEBUG_SEH}
  530. while ScopeIdx<PDword(dispatch.HandlerData)^ do
  531. begin
  532. scope:=@PScopeRec(dispatch.HandlerData+sizeof(Dword))[ScopeIdx];
  533. {$ifdef DEBUG_SEH}
  534. PrintScope(scopeIdx, scope);
  535. {$endif DEBUG_SEH}
  536. if (ControlRva>=scope^.RvaStart) and (ControlRva<scope^.RvaEnd) and
  537. ((scope^.Typ=SCOPE_FINALLY) or (scope^.Typ=SCOPE_IMPLICIT)) then
  538. begin
  539. if (TargetRva>=scope^.RvaStart) and (TargetRva<scope^.RvaEnd) and
  540. ((rec.ExceptionFlags and EXCEPTION_TARGET_UNWIND)<>0) then
  541. begin
  542. Exit;
  543. end;
  544. dispatch.ScopeIndex:=ScopeIdx+1;
  545. {$ifdef DEBUG_SEH}
  546. if IsConsole then
  547. writeln(stderr,'calling handler @',hexstr(dispatch.imagebase+scope^.RvaHandler,16));
  548. {$endif DEBUG_SEH}
  549. TUnwindProc(dispatch.ImageBase+scope^.RvaHandler)(context.rbp);
  550. end;
  551. Inc(ScopeIdx);
  552. end;
  553. end;
  554. end;
  555. {$endif FPC_USE_WIN64_SEH}