Quote:
Originally Posted by mshindo
(Post 3550705)
Anyway, __cxa_demangle returns null.
|
As in "(null)" or NULL? If the latter, then the error is stored in status. If the former, it means that the address does not correctly resolve to a symbol.
Quote:
Originally Posted by mshindo
(Post 3550705)
So I am wondering if pthreads is the culprit.
|
What versions are you using? What platform? Is this an open-source project, where we can all diagnose the code? If so, what’s the website/repository? If not, can you get a complete example which exhibits this behavior?
The best way to debug is to slowly increase sample code until “works for me” turns into “doesn’t work for me”. Here is what I had yesterday:
Code:
$ cat > backtrace.cc << EOF
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// To prevent threads from printing over each other
pthread_mutex_t print = PTHREAD_MUTEX_INITIALIZER;
void print_trace(void) {
using namespace abi;
enum { MAX_DEPTH = 20 };
void *trace[MAX_DEPTH];
Dl_info dlinfo;
int status;
const char *symname;
char *demangled;
int trace_size = backtrace(trace, MAX_DEPTH);
pthread_mutex_lock(&print);
printf("Call stack: \n");
for (int i=0; i<trace_size; ++i) {
if(!dladdr(trace[i], &dlinfo))
continue;
symname = dlinfo.dli_sname;
demangled = __cxa_demangle(symname, NULL, 0, &status);
if(status == 0 && demangled)
symname = demangled;
printf("object: %s, function: %s\n", dlinfo.dli_fname, symname);
if (demangled)
free(demangled);
}
printf("\n");
pthread_mutex_unlock(&print);
}
namespace foo {
struct baz {
static void bar(char c, int x) { print_trace(); }
static void bar(int x) { bar((char)x,x); }
static void bar(double d) { bar((int)d); }
void bar(double *d) { bar((int)*d); }
};
void bar(char c, int x) { print_trace(); }
void bar(int x) { bar((char)x,x); }
void bar(double d) { bar((int)d); }
void bar(baz &b, double d) { b.bar(&d); }
}
void bar(char c, int x) { foo::baz::bar(c,x); }
void bar(int x) { bar((char)x,x); }
void bar(double d) { bar((int)d); }
void *start(void *which) {
switch((int) which) {
case 1:
foo::baz::bar(1.2);
break;
case 2:
foo::bar(3.4);
break;
}
return NULL;
}
int main(int argc, char *argv[]) {
pthread_t t1, t2;
pthread_create(&t1, NULL, start, (void*)1);
pthread_create(&t2, NULL, start, (void*)2);
foo::baz b;
foo::bar(b, 3.4);
bar(5.6);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
EOF
$ g++ -rdynamic -ldl -lpthread backtrace.cc -o backtrace
$ ./backtrace
Call stack:
object: ./backtrace, function: print_trace()
object: ./backtrace, function: foo::bar(char, int)
object: ./backtrace, function: foo::bar(int)
object: ./backtrace, function: foo::bar(double)
object: ./backtrace, function: start(void*)
object: /lib/libpthread.so.0, function: (null)
object: /lib/libc.so.6, function: clone
Call stack:
object: ./backtrace, function: print_trace()
object: ./backtrace, function: foo::baz::bar(char, int)
object: ./backtrace, function: foo::baz::bar(int)
object: ./backtrace, function: foo::baz::bar(double)
object: ./backtrace, function: start(void*)
object: /lib/libpthread.so.0, function: (null)
object: /lib/libc.so.6, function: clone
Call stack:
object: ./backtrace, function: print_trace()
object: ./backtrace, function: foo::baz::bar(char, int)
object: ./backtrace, function: foo::baz::bar(int)
object: ./backtrace, function: foo::baz::bar(double*)
object: ./backtrace, function: foo::bar(foo::baz&, double)
object: ./backtrace, function: main
object: /lib/libc.so.6, function: __libc_start_main
object: ./backtrace, function: (null)
Call stack:
object: ./backtrace, function: print_trace()
object: ./backtrace, function: foo::baz::bar(char, int)
object: ./backtrace, function: bar(char, int)
object: ./backtrace, function: bar(int)
object: ./backtrace, function: bar(double)
object: ./backtrace, function: main
object: /lib/libc.so.6, function: __libc_start_main
object: ./backtrace, function: (null)
Here we have all sorts of mangling going on (overloading, class methods, namespaces, etc.) and three threads. As expected the order of the backtraces varies on each execution.
If the above works for you, then this means that we have to further add code to make the sample more like your situation. If the above doesn’t work, it means that there is some flaw in your build setup which isn’t there in mine.
P.S.
Just out of curiosity, your code has a fallback for the cases where demangled==NULL of printing the mangled callstack. Have you tried looking at both (mangled) callstacks to tell if there is a difference between threaded vs. unthreaded? E.g., you could add this code:
Code:
…
int trace_size = backtrace(trace, MAX_DEPTH);
pthread_mutex_lock(&print);
backtrace_symbols_fd(trace, trace_size, 1);
printf("Call stack: \n");
for (int i=0; i<trace_size; ++i) {
if(!dladdr(trace[i], &dlinfo))
…
|