views:

10883

answers:

11

I know there's no standard C function to do this. I was wondering what are the techniques to to this on Windows and *nix? (Windows XP is my most important OS to do this on right now.)

Thanks for the help!

A: 

You can do it by walking the stack backwards. In reality, though, it's frequently easier to add an identifier onto a call stack at the beginning of each function and pop it at the end, then just walk that printing the contents. It's a bit of a PITA, but it works well and will save you time in the end.

Cody Brocious
+2  A: 

There is no platform independent way to do it.

The nearest thing you can do is to run the code without optimizations. That way you can attach to the process (using the visual c++ debugger or GDB) and get a usable stack trace.

Nils Pipenbrinck
That doesn't help me when a crash happens on an embedded computer in the field. :(
Kevin
@Kevin: Even on embedded machines, there's usually a way to get a remote debugger stub or at least a core dump. Maybe not once it's deployed to the field, though...
ephemient
+24  A: 

glibc provides backtrace() function.

http://www.gnu.org/software/libc/manual/html_node/Backtraces.html

sanxiyn
+11  A: 

We've used this for our projects:

http://www.codeproject.com/threads/StackWalker.asp

The code is a tad messy IMHO, but it works well. Windows only.

Mark
Link doesn't work. Should it be http://www.codeproject.com/KB/threads/StackWalker.aspx ?
squelart
+1  A: 

solaris has the pstack command, which was also copied into linux.

wnoise
Useful, but not really C (it's an external utility).
ephemient
+9  A: 

For Windows check the StackWalk64() API (also on 32bit Windows). For UNIX you should use the OS' native way to do it, or fallback to glibc's backtrace(), if availabe.

Note however that taking a Stacktrace in native code is rarely a good idea - not because it is not possible, but because you're usally trying to achieve the wrong thing.

Most of the time people try to get a stacktrace in, say, an exceptional circumstance, like when an exception is caught, an assert fails or - worst and most wrong of them all - when you get a fatal "exception" or signal like a segmentation violation.

Considering the last issue, most of the APIs will require you to explicitly allocate memory or may do it internally. Doing so in the fragile state in which your program may be currently in, may acutally make things even worse. For example, the crash report (or coredump) will not reflect the actual cause of the problem, but your failed attempt to handle it).

I assume you're trying to achive that fatal-error-handling thing, as most people seem to try that when it comes to getting a stacktrace. If so, I would rely on the debugger (during development) and letting the process coredump in production (or mini-dump on windows). Together with proper symbol-management, you should have no trouble figuring the causing instruction post-mortem.

Christian.K
You're right about it being fragile to attempt memory allocation in a signal or exception handler. One potential way out is to allocate a fixed amount of "emergency" space at program start, or use a static buffer.
j_random_hacker
+3  A: 

For Windows, CaptureStackBackTrace() is also an option, which requires less preparation code on the user's end than StackWalk64() does. (Also, for a similar scenario I had, CaptureStackBackTrace() ended up working better (more reliably) than StackWalk64().)

Quasidart
+2  A: 

May i point you to my article. Its only a few lines of code.

Post Mortem Debugging

Although i currently have problems with the x64 implementation of this.

RED SOFT ADAIR
+3  A: 

You should be using the unwind library.

unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
unsigned long a[100];
int ctr = 0;

while (unw_step(&cursor) > 0) {
  unw_get_reg(&cursor, UNW_REG_IP, &ip);
  unw_get_reg(&cursor, UNW_REG_SP, &sp);
  if (ctr >= 10) break;
  a[ctr++] = ip;
}

Your approach also would work fine unless you make a call from a shared library.

You can use the addr2line command on Linux to get the source function / line number of the corresponding PC.

"source function/line number"? What if linking is optimized for reduced code size?I will say, though, that this looks like a useful project. A pity that's there's no way to get the registers. I will definitely look into this. Do you know that it is absolutely processor independent? Just works on anything that has a C compiler?
Mawg
Ok this comment was worth it, if only because of the mention of the helpful addr2line command!
Ogre Psalm33
A: 

"I know there's no standard C function to do this. I was wondering what are the techniques to to this on Windows and *nix? "

No standard function ... "aye, there's the rub".

Dumping the stack has nothing to do with programming language - at least not high level languages, but certainly assembler - and everything to do with being processor specific.

I am going to guess that you are thinking of "Windows and *nix" on a standard "IBM compatible" PC, but I seem to recall that even windows runs on powerPC (motorola processor) and Linux runs on just about anything.

In short, "there are more processors in heaven and earth, Horatio..." and every single one needs its own stack dump routine.

Doubly so for registers, which are also useful to dump.

Mawg
+2  A: 
Tom