Staffan Gustafsson
Staffan Gustafsson

Reputation: 354

Inline stack frames with IDebugControl5.GetContextStackTraceEx?

How can I resolve the symbols of a DEBUG_STACK_FRAME_EX with inline frames?

I am aware of DEBUG_STACK_FRAME_EX and its ULONG InlineFrameContext, but I don't understand how to resolve the InlineFrameContext to the corresponding symbol.

And what is the FrameSignature and FrameId in INLINE_FRAME_CONTEXT?

Upvotes: 0

Views: 378

Answers (2)

Staffan Gustafsson
Staffan Gustafsson

Reputation: 354

This is using some wrappers, but the intention should be clear. Using IDebugSymbols4::GetNameByInlineContext if the InlineFrameContext indicates that it is an inline frame, and IDebugSymbols4::GetSymbolNameByOffset otherwise.

C# example below:

ulong displacement;
var builder = new StringBuilder(256);
var isInlineFrame = frame.InlineFrameContext.FrameType.HasFlag(StackFrameType.Inline);
if (isInlineFrame)
{
    _symbols5.GetNameByInlineContext(frame.InstructionOffset, frame.InlineFrameContext.ContextValue, ref builder, out displacement);                
}
else {
    _symbols5.GetSymbolNameByOffset(frame.InstructionOffset, ref builder, out displacement);
}
var name = builder.ToString();

Upvotes: 0

blabb
blabb

Reputation: 8997

InLineFrameContext is an union only FrameType is Defined which is the second byte in the ContextValue DWORD

this normally would be 25ed0200 for an inline frame (most of the times i noticed though it can be b5b80200 too in some system dll's inline frames

the output is same as kvf and .inline 1 (.inline enable )

if you disable inline
the InlineFrameContext would be 0xffffffff

where ff is STACK_FRAME_TYPE_IGNORE

25ed / b5b8 , ffff , etc The Frame Signature and the 00 FrameID are fetched from symbols

(if you really want to know look into the dia sdk com sorcery which loads the symbols and fetches this signature from pdb ( dbghelp!g+0xxxx (2360 in win10 dbghelp.dll) )

whatever they are they don't appear to be useful for any co-relation with symbols and the signature varies on each invocation or windbg session and iirc on every .reload /f

even the OutputContextStackTraceEx function doesn't seem to use the signature and Id (type is used to denote inline if type was 02 )

if you want to experiment you can check this code (its an engextcpp extension so you compile and load it in windbg and run the command it will print the stack along with some spew exactly as if you issued kvf

#include <codeanalysis\warnings.h>
#pragma warning( push )
#pragma warning ( disable : ALL_CODE_ANALYSIS_WARNINGS )
#include <engextcpp.cpp>
#pragma warning( pop )
class EXT_CLASS : public ExtExtension {
public:
    EXT_COMMAND_METHOD(gcsex);
};
EXT_DECLARE_GLOBALS();
ULONG64 InstructionOffset; DEBUG_STACK_FRAME ScopeFrame; CONTEXT ScopeContext; 
DEBUG_STACK_FRAME_EX FrameEx[0x20];CONTEXT FrameContext[0x20];ULONG FramesFilled; 
INLINE_FRAME_CONTEXT Inlineframectx;
EXT_COMMAND( gcsex, "", "" ) {
    InstructionOffset = NULL; FramesFilled = NULL;
    memset(&ScopeFrame,0,sizeof(ScopeFrame));memset(&ScopeContext,0,sizeof(ScopeContext));
    memset(&FrameEx, 0, sizeof(FrameEx)); memset(&FrameContext,0,sizeof(FrameContext));
    memset(&Inlineframectx,0,sizeof(Inlineframectx));
    m_Symbols->GetScope(&InstructionOffset,&ScopeFrame,&ScopeContext,sizeof(ScopeContext));
    Out("%I64X%I64x %X\n",InstructionOffset,ScopeFrame.InstructionOffset,ScopeContext.Eip);
    m_Control5->GetContextStackTraceEx( &ScopeContext,sizeof(ScopeContext),
    FrameEx,0x20,FrameContext,0x20*sizeof(CONTEXT),sizeof(CONTEXT),&FramesFilled );
    Out("Frames Filled = %x\n" , FramesFilled);
    for(ULONG i = 0 ; i < FramesFilled; i++) {
        Inlineframectx.ContextValue = FrameEx[i].InlineFrameContext;
        Out("Inline Frame Context for frame %d=%x\n" , i , FrameEx[i].InlineFrameContext);
        Out("Frameid = %x FrameType = %x Frame Signature = %x\n" ,
        Inlineframectx.FrameId , Inlineframectx.FrameType , Inlineframectx.FrameSignature);
    }
    m_Control5->OutputContextStackTraceEx ( DEBUG_OUTCTL_ALL_CLIENTS,FrameEx,FramesFilled,
    &FrameContext,FramesFilled*sizeof(CONTEXT),sizeof(CONTEXT),0x1fff );
}

you should see some thing like this on executing the extension

0:000> kb
 # ChildEBP RetAddr  Args to Child              
00 (Inline) -------- -------- -------- -------- runasm!helper [e:\test\runasm\runasm.cpp @ 4]
01 0029fd44 0124159a 00000001 0008c5f0 00091a70 runasm!main+0x20 [e:\test\runasm\runasm.cpp @ 32]
02 (Inline) -------- -------- -------- -------- runasm!invoke_main+0x1d [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 74]
03 0029fd90 75d53c45 7ffdf000 0029fddc 778037f5 runasm!__scrt_common_main_seh+0xff [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 264]
04 0029fd9c 778037f5 7ffdf000 75826e8f 00000000 kernel32!BaseThreadInitThunk+0xe
05 0029fddc 778037c8 01241652 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70
06 0029fdf4 00000000 01241652 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> !gcsex
12412F0 12412f0 12412F0
Frames Filled = 7
Inline Frame Context = for frame 0 = 25ed0200
Frameid = 0 FrameType = 2 Frame Signature = 25ed
Inline Frame Context = for frame 1 = 25ed0100
Frameid = 0 FrameType = 1 Frame Signature = 25ed
Inline Frame Context = for frame 2 = 25ed8200
Frameid = 0 FrameType = 82 Frame Signature = 25ed
Inline Frame Context = for frame 3 = 25ed8100
Frameid = 0 FrameType = 81 Frame Signature = 25ed
Inline Frame Context = for frame 4 = 25ed8100
Frameid = 0 FrameType = 81 Frame Signature = 25ed
Inline Frame Context = for frame 5 = 25ed8100
Frameid = 0 FrameType = 81 Frame Signature = 25ed
Inline Frame Context = for frame 6 = 25ed8100
Frameid = 0 FrameType = 81 Frame Signature = 25ed
 #   Memory  ChildEBP RetAddr  Args to Child              
00           (Inline) -------- -------- -------- -------- runasm!helper (Inline Function @ 012412f0) (CONV: cdecl) [e:\test\runasm\runasm.cpp @ 4]
01           0029fd44 0124159a 00000001 0008c5f0 00091a70 runasm!main(void)+0x20 (FPO: [0,1,4]) (CONV: cdecl) [e:\test\runasm\runasm.cpp @ 32]
02        4c (Inline) -------- -------- -------- -------- runasm!invoke_main+0x1d (Inline Function @ 0124159a) (CONV: cdecl) [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 74]
03         0 0029fd90 75d53c45 7ffdf000 0029fddc 778037f5 runasm!__scrt_common_main_seh(void)+0xff (FPO: [Non-Fpo]) (CONV: cdecl) [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 264]
04         c 0029fd9c 778037f5 7ffdf000 75826e8f 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
05        40 0029fddc 778037c8 01241652 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
06        18 0029fdf4 00000000 01241652 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])
0:000> .inline 
Include inline function queries is "enabled".
0:000> .inline 0
Include inline function queries is "disabled".
0:000> kb
 # ChildEBP RetAddr  Args to Child              
00 0029fd44 0124159a 00000001 0008c5f0 00091a70 runasm!main+0x20 [e:\test\runasm\runasm.cpp @ 32]
01 0029fd90 75d53c45 7ffdf000 0029fddc 778037f5 runasm!__scrt_common_main_seh+0xff [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 264]
02 0029fd9c 778037f5 7ffdf000 75826e8f 00000000 kernel32!BaseThreadInitThunk+0xe
03 0029fddc 778037c8 01241652 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70
04 0029fdf4 00000000 01241652 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> !gcsex
12412F0 12412f0 12412F0
Frames Filled = 5
Inline Frame Context = for frame 0 = ffffffff
Frameid = ff FrameType = ff Frame Signature = ffff
Inline Frame Context = for frame 1 = ffffffff
Frameid = ff FrameType = ff Frame Signature = ffff
Inline Frame Context = for frame 2 = ffffffff
Frameid = ff FrameType = ff Frame Signature = ffff
Inline Frame Context = for frame 3 = ffffffff
Frameid = ff FrameType = ff Frame Signature = ffff
Inline Frame Context = for frame 4 = ffffffff
Frameid = ff FrameType = ff Frame Signature = ffff
 #   Memory  ChildEBP RetAddr  Args to Child              
00           0029fd44 0124159a 00000001 0008c5f0 00091a70 runasm!main(void)+0x20 (FPO: [0,1,4]) (CONV: cdecl) [e:\test\runasm\runasm.cpp @ 32]
01        4c 0029fd90 75d53c45 7ffdf000 0029fddc 778037f5 runasm!__scrt_common_main_seh(void)+0xff (FPO: [Non-Fpo]) (CONV: cdecl) [f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl @ 264]
02         c 0029fd9c 778037f5 7ffdf000 75826e8f 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
03        40 0029fddc 778037c8 01241652 7ffdf000 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
04        18 0029fdf4 00000000 01241652 7ffdf000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

results to corroborate the edit that the Signature varies per session

cdb -c "$$>a< gcsex.txt" runasm.exe | grep -i Sign
Frameid = 0 FrameType = 1 Frame Signature = 1e7e
Frameid = 0 FrameType = 82 Frame Signature = 1e7e
Frameid = 0 FrameType = 81 Frame Signature = 1e7e
Frameid = 0 FrameType = 81 Frame Signature = 1e7e
Frameid = 0 FrameType = 81 Frame Signature = 1e7e
Frameid = 0 FrameType = 81 Frame Signature = 1e7e

cdb -c "$$>a< gcsex.txt" runasm.exe | grep -i Sign
Frameid = 0 FrameType = 1 Frame Signature = b649
Frameid = 0 FrameType = 82 Frame Signature = b649
Frameid = 0 FrameType = 81 Frame Signature = b649
Frameid = 0 FrameType = 81 Frame Signature = b649
Frameid = 0 FrameType = 81 Frame Signature = b649
Frameid = 0 FrameType = 81 Frame Signature = b649

cdb -c "$$>a< gcsex.txt" runasm.exe | grep -i Sign
Frameid = 0 FrameType = 1 Frame Signature = decf
Frameid = 0 FrameType = 82 Frame Signature = decf
Frameid = 0 FrameType = 81 Frame Signature = decf
Frameid = 0 FrameType = 81 Frame Signature = decf
Frameid = 0 FrameType = 81 Frame Signature = decf
Frameid = 0 FrameType = 81 Frame Signature = decf

cat gcsex.txt
.load gcsex
bp runasm!main "!gcsex;q"
g

Upvotes: 0

Related Questions