Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capture the call stack quickly

I'm trying to capture the call stack as quickly as possible. Right now this is what I've got:

void* addrs[10] = {};
DWORD hash;
RtlCaptureStackBackTrace(0, 10, addrs, &hash);

for( size_t i = 0; i <10; ++i )
{
    std::cout << addrs[i] << '\n';
}

This is for use in a memory tracking system, so it's perfectly fine that I end up with an array of addresses if they can later (upon some user driven event) be turned into something human readable.

  • How can I turn addrs into something human readable? (see edit below)
  • Is there anything faster than RtlCaptureStackBackTrace?
  • Is there a cross platform way to capture the call stack?

Edit:

I turned the addresses into human readable information by using SymFromAddr and SymGetLineFromAddr64. However, my version of new that uses CaptureStackBackTrace takes ~30x longer than the original and almost all that time is because of the stack trace. I'm still looking for a faster solution!

like image 863
David Avatar asked Nov 04 '22 09:11

David


1 Answers

Is there a cross platform way to capture the call stack?

The quick answer is that unfortunately it's not possible. Different compilers and platforms will organize the stack differently, and without "help" from the compiler, you're not going to be able to accurately trace back through the stack ... the most you could do on platforms that are using a stack-frame base-pointer would be to move up the stack using the values in either EBP or RBP, and even that is dependent on if you're running a 32-bit x86 executable, or a x86_64 executable. Additionally the rules governing the UNIX application-binary-interface (ABI) and the Windows ABI are completely different. So in general, you're going to end up having to support at least four different possibilities:

  1. Unix 32-bit ABI
  2. Unix 64-bit ABI
  3. Windows 32-bit ABI
  4. Windows 64-bit ABI

Keep in mind that the UNIX 64-bit ABI allows for compilers to choose whether they will or will not support a stack-frame base-pointer ... so the use of a base-pointer is not guaranteed; a compiler may simply choose to reference all stack-variables against the stack-pointer itself without using a separate base-pointer. That would still be considered compliant with the UNIX 64-bit ABI.

So as you can see, with all these possible variations, you're going to have a very tough time making a reliable cross-platform stack-tracer. Your best-bet it to use the tools available to you for the platform you're targeting. If you need to support multiple platforms, then unfortunately there's going to be some level of code duplication as you utlize platform-specific tools to help you reliably perform the stack-trace.

like image 82
Jason Avatar answered Nov 12 '22 12:11

Jason