Game Development Community

Some help for those developing under linux

by Jack Vice · in Torque Game Engine · 05/03/2005 (2:40 pm) · 6 replies

After breaking the code that I was working on in such a way that Torque hung the X mouse cursor, I came up with a simple way to dump the stack to a file in the case of a segfault. Since some of you may hit similar problems, or have bugs that only segfault during runtime, and not under gdb, I thought I would post it for everyone. I'd post it as a resource, but this will only work under linux (possibly OSX).

Fire up your editor of choice and open up: paltformX86UNIX/x86UNIXProcessControl.cc

At the top after the includes Add:

#include

Then, just before the function:

static void SignalHandler( int sigtype )

Add:

static void dumpStack() {
void *syms[64];
FILE *dump;
int step, num_syms;

dump = fopen( "Dump.txt", "w+");
num_syms = backtrace( syms, 64 );

for( step = 3; step < num_syms; step++ ) {
fprintf( dump, "%p\n", syms[step] );
}
fclose( dump );
}

Then in the SignalHandler function just after the line:

signal(SIGTRAP, SIG_DFL );

Add:

if( sigtype == SIGSEGV ) {
dumpStack();
}

Compile, and you are ready to crash....

So, your code runs, segfaults, and spits out some text to Dump.txt, for example you might get something like:

0x81e7ef9
0x81e86da
.....
0x5579a7f8

which means nothing to you, so open up the editor again, and in your example directory create viewdump.sh which contains:

#!/bin/sh
cat Dump.txt | addr2line -e torqueDemo_Debug.bin

Then do a "chmod a+x viewdump.sh", and run ./viewdump.sh
Now you get something like:

game/ODESimpleObject.cc:271
game/ODESimpleObject.cc:380
game/ODESimpleObject.ccc:478
game/gameProcess.cc:246
...
platformX86UNIX/x86UNIXWindow.cc:886
??:0

which is the stack trace for the program at the time it segfaulted.

This won't save your project, but it will at least point you to where you problems are.

#1
05/03/2005 (2:51 pm)
Very nice. Thanks for sharing. I'd say make this a resource too (there's lots of OS specific resources.)
#2
05/04/2005 (10:26 am)
Yup very nice, should be a resource as jerry says.
#3
05/04/2005 (1:18 pm)
Don't forget to use backtrace_symbols to save yourself half that work...
My canned code looks more like this:

void *array[64];
int size, i;
char **syms;
fprintf(stderr, "Process %d Stack dump:\n\n", getpid());
size = backtrace(array, (sizeof array)/(sizeof array[0]));
syms = backtrace_symbols(array, size);
for ( i=1; i fprintf(stderr, "\t%s\n", syms[i]);
}
free(syms);
fprintf(stderr, "\n");

Gary (-;
#4
05/04/2005 (1:22 pm)
Oh, and since I'm being hardcore *nixy, don't forget that signal() is the very old and very broken way of doing it [there's a harsh race condition, consider it to be unreliable].

Of course, since this is mostly last-ditch scary stuff, you might *want* the older, "broken", behaviour. If you get another segfault inside the handler, you might not want it calling the SEGV handler again. But since I don't know how well signal sets and signal() work together, I'd still recommend using sets...

Gary (-;
#5
05/04/2005 (7:12 pm)
From my experience, or in my case at lateast backtrace_symbols only gave me the executable, and no line numbers, for some reason the dlfcn functions wouldn't give me the info either so...

As for the race condition, the standard handler disables itself so you are somewhat safer.
#6
05/07/2005 (11:59 am)
Another approach is to use the standard Linux core dump. Make sure "ulimit -c" is set high enough to capture a copy of memory, and then call abort() to dump all of memory into a file. You can then load the dump and your debug binary into gdb and use the "bt" (backtrace) command to dump out the stack.