How do I obtain a stack trace on Windows without using dbghelp.dll?
Asked Answered
N

3

7

How do I obtain a stack trace of addresses on Windows without using dbghelp.dll?

I don't need to know what the symbols or function names associated with the addresses, I just want the list of addresses -- something similar to backtrace of *nix systems.

Thanks!

Newhall answered 24/12, 2008 at 23:16 Comment(1)
Why would you want to do this without DbgHelp.dll. DbgHelp.dll is builtin to Windows, since Windows 2000. Also check out Jochen Kalmbach's Stackwalker: codeproject.com/KB/threads/StackWalker.aspxLomeli
R
9

Check out the CaptureStackBackTrace() function, which is in Kernel32.dll. This should do all that you need.

Captures a stack back trace by walking up the stack and recording the information for each frame.

USHORT WINAPI CaptureStackBackTrace(
  __in       ULONG FramesToSkip,
  __in       ULONG FramesToCapture,
  __out      PVOID *BackTrace,
  __out_opt  PULONG BackTraceHash
);
Rheinlander answered 24/12, 2008 at 23:42 Comment(3)
Looks good. But I'm using VS 2005, and CaptureStackBackTrace no RtlCaptureBackTrace isn't defined in winbase.h. I'll try manually including the function prototype for RtlCaptureBackTrace(...) and see if that will work for me. Thanks!Newhall
Way cool! I've written stack tracing code ateast 3 times and had no idea this exists. Thank you!Thirtieth
@Uhall: You can try installing a newer Windows SDK. The minimum supported client is listed as Windows XP although the MSDN page does list that it was included in the Windows SDK starting with Windows Vista.Rheinlander
R
2

If you want to do this extremely non-portably, you can just read the EBP register and walk the stack yourself. This will only work for the x86 architecture, and it also assumes that the C runtime you're using properly initializes EBP to 0 before calling the first function.

uint32_t read_ebp(void)
{
    uint32_t my_ebp;
    __asm
    {
        mov ebp, my_ebp
    }

    return my_ebp;
}

void backtrace(void)
{
    uint32_t ebp = read_ebp();

    printf("backtrace:\n");

    while(ebp != 0)
    {
        printf("0x%08x\n", ebp);
        ebp = ((uint32_t *)ebp)[1];
    }
}
Rapt answered 25/12, 2008 at 0:30 Comment(2)
With release builds this will only give you the first few frames. For this to actually work reliably you need to set "Omit Frame Pointers"=No.Thirtieth
destination comes first, so you need to mov my_ebp, ebp.. other than that it's pretty coolFen
A
1

Previous variant doesn't work for me(msvc 6), so:

unsigned long prev;
unsigned long addr;
__asm { mov prev, ebp }
while(addr!=0) { 
  addr = ((unsigned long *)prev)[1]; 
  printf("0x%08x\n", addr); 
  prev = ((unsigned long *)prev)[0]; 
}
Adam, thanks for highlighting the way!
Angleworm answered 19/3, 2009 at 17:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.