Что делает RtlRestoreContext, когда ExceptionCode имеет значение STATUS_UNWIND_CONSOLIDATE? - PullRequest
1 голос
/ 24 февраля 2012

Я пытаюсь понять, как обработка исключений C ++ реализована в x64 во время выполнения Visual C ++.

После прочтения блога Nynaeve по реализации SEH для x64 в http://www.nynaeve.net/?p=110, кажется, что RtlUnwindEx вызываетRtlRestoreContext с ExceptionCode, установленным в STATUS_UNWIND_CONSOLIDATE для объединения кадров, раскручивается.

Что мне не совсем понятно, что делает тогда RtlRestoreContext?MSDN заявляет в http://msdn.microsoft.com/en-us/site/ms680605, что «RtlRestoreContext объединяет кадры вызова между своим кадром и кадром, указанным в записи контекста, перед вызовом функции обратного вызова. Это скрывает кадры от любой обработки исключений, которая может возникнуть в функции обратного вызова».

Что подразумевается под «объединением фреймов вызова между его фреймом и фреймом, указанным в записи контекста»?Как это «скрывает фреймы от обработки исключений, которые могут возникнуть в функции обратного вызова»?Что означает «консолидация фреймов» и где именно консолидируется фрейм?

Допустим, обработчик перехвата C ++ должен вызываться из RtlRestoreContext, и он вызывает другое исключение - это (повторно) выбрасываемое исключение, защищенноекакой-то блок SEH?ИЛИ, этот бизнес консолидации структуры как-то заботится об этом?Если да, то как?

Ответы [ 2 ]

1 голос
/ 25 августа 2014

Если вы следуете этой функции, вы увидите, что в обстоятельствах, на которые вы ссылаетесь, код устанавливает поддельный фрейм машины в стеке (относительно [r8] только с заполненным RIP и RSP) из оригинала контекст передан в RtlRestoreContext. Затем он копирует исходный контекст в пространство стека, выделенное ниже фрейма машины.

См. http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx для получения дополнительной информации о раме машины (в разделе UWOP_PUSH_MACHFRAME).

0:004> u ntdll!RtlRestoreContext+0x296
00000000`771f0c05 83ec30          sub     esp,30h
00000000`771f0c08 4c8bc4          mov     r8,rsp
00000000`771f0c0b 4881ecd0040000  sub     rsp,4D0h
00000000`771f0c12 488bf1          mov     rsi,rcx
00000000`771f0c15 488bfc          mov     rdi,rsp
00000000`771f0c18 b99a000000      mov     ecx,9Ah
00000000`771f0c1d f348a5          rep movs qword ptr [rdi],qword ptr [rsi]
00000000`771f0c20 488b842498000000 mov     rax,qword ptr [rsp+98h]
0:004> u
ntdll!RtlRestoreContext+0x2ba:
00000000`771f0c28 49894018        mov     qword ptr [r8+18h],rax
00000000`771f0c2c 488b8424f8000000 mov     rax,qword ptr [rsp+0F8h]
00000000`771f0c34 498900          mov     qword ptr [r8],rax
00000000`771f0c37 488bca          mov     rcx,rdx
00000000`771f0c3a eb12            jmp     ntdll!RcFrameConsolidation (00000000`771f0c4e)

Код переходит к псевдо-функции, о которой говорит блог, NTDLL! RcFrameConsolidation.

Если мы рассмотрим таблицу функций и записи UNWIND для этой функции, мы увидим, что она содержит метаданные, соответствующие настройке фальшивого стека:

0:004>.fnent ntdll!rcframeconsolidation

...snip...

Unwind info at 00000000`772c8e0c, 52 bytes
  version 1, flags 0, prolog 0, codes 27
  00: offs 0, unwind op 8, op info f    UWOP_SAVE_XMM128 FrameOffset: 290 reg: xmm15.
  02: offs 0, unwind op 8, op info e    UWOP_SAVE_XMM128 FrameOffset: 280 reg: xmm14.
  04: offs 0, unwind op 8, op info d    UWOP_SAVE_XMM128 FrameOffset: 270 reg: xmm13.
  06: offs 0, unwind op 8, op info c    UWOP_SAVE_XMM128 FrameOffset: 260 reg: xmm12.
  08: offs 0, unwind op 8, op info b    UWOP_SAVE_XMM128 FrameOffset: 250 reg: xmm11.
  0a: offs 0, unwind op 8, op info a    UWOP_SAVE_XMM128 FrameOffset: 240 reg: xmm10.
  0c: offs 0, unwind op 8, op info 9    UWOP_SAVE_XMM128 FrameOffset: 230 reg: xmm9.
  0e: offs 0, unwind op 8, op info 8    UWOP_SAVE_XMM128 FrameOffset: 220 reg: xmm8.
  10: offs 0, unwind op 8, op info 7    UWOP_SAVE_XMM128 FrameOffset: 210 reg: xmm7.
  12: offs 0, unwind op 8, op info 6    UWOP_SAVE_XMM128 FrameOffset: 200 reg: xmm6.
  14: offs 0, unwind op 4, op info f    UWOP_SAVE_NONVOL FrameOffset: f0 reg: r15.
  16: offs 0, unwind op 4, op info e    UWOP_SAVE_NONVOL FrameOffset: e8 reg: r14.
  18: offs 0, unwind op 4, op info d    UWOP_SAVE_NONVOL FrameOffset: e0 reg: r13.
  1a: offs 0, unwind op 4, op info c    UWOP_SAVE_NONVOL FrameOffset: d8 reg: r12.
  1c: offs 0, unwind op 4, op info 7    UWOP_SAVE_NONVOL FrameOffset: b0 reg: rdi.
  1e: offs 0, unwind op 4, op info 6    UWOP_SAVE_NONVOL FrameOffset: a8 reg: rsi.
  20: offs 0, unwind op 4, op info 5    UWOP_SAVE_NONVOL FrameOffset: a0 reg: rbp.
  22: offs 0, unwind op 4, op info 3    UWOP_SAVE_NONVOL FrameOffset: 90 reg: rbx.
  24: offs 0, unwind op 1, op info 0    UWOP_ALLOC_LARGE FrameOffset: 4d0.
  26: offs 0, unwind op a, op info 0    UWOP_PUSH_MACHFRAME.

Эффект этого состоит в том, чтобы «обмануть» код обработки исключений VirtualUnwindEx / и заставить думать, что функция, описанная ContextRecord, является непосредственным абонентом RtlRestoreContext.

С точки зрения VirtualUnwind, стек вызовов - это OriginalContext -> RtlRestoreContext -> [обратный вызов, предоставленный пользователем], между которыми ничего нет.

Таким образом, если стек «размотан», все промежуточные кадры между кадром, описанным ContextRecord, и текущим контекстом в RtlRestoreContext являются «забытыми». то есть кадры были объединены в один кадр, который разматывается как одна функция. Таким образом, если исключение происходит внутри функции обратного вызова, переданной в ExceptionRecord, любые обработчики исключений в этих промежуточных кадрах скрыты. Как отмечается в блоге, эта функциональность в значительной степени полезна для обработки языковых исключений.

Как также указывается в документации MS, локальные элементы кадров промежуточного стека не уничтожаются перед вызовом обратного вызова, что полезно, если в кадре стека этой функции был выделен объект исключения на каком-либо языке.

0 голосов
/ 25 апреля 2012

См.

Рисунок 6 Разматывание из исключения в http://www.microsoft.com/msj/0197/exception/exception.aspx

Может быть, это то, что означает "консолидация"

...