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.
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.
About the author
#2
05/04/2005 (10:26 am)
Yup very nice, should be a resource as jerry says.
#3
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 (-;
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
}
free(syms);
fprintf(stderr, "\n");
Gary (-;
#4
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 (-;
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
As for the race condition, the standard handler disables itself so you are somewhat safer.
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.
Torque Owner Jerry Shaw
Roaming Gamer LLC