LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Backtrace and _cxa_demangle (https://www.linuxquestions.org/questions/programming-9/backtrace-and-_cxa_demangle-727932/)

mshindo 05-23-2009 12:05 AM

Backtrace and _cxa_demangle
 
Hey Guys

Trying to use backtrace from within a large multithreaded application, its working but __cxa_demangle( isnt returning the function names like gdb does.

Code:

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);

    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);
    } 
}

I am compiling with -rdynamic and -ldl

Any suggestions ?

osor 05-23-2009 03:25 AM

Quote:

Originally Posted by mshindo (Post 3549936)
but __cxa_demangle( isnt returning the function names like gdb does.

So… what is it returning (what kind of error)? The code sample verbatim seems to work for me (g++-4.3.3). Perhaps you need to use “-fnew-abi” when compiling?

mshindo 05-23-2009 09:16 PM

I tried with that compile option, but g++ returned an error stating its not supported anymore :(

Anyway, __cxa_demangle returns null. What is interesting is that this code sample seems to work fine in a single threaded program. The application in question however has 8 threads normally and more are forked when clients connect.

So I am wondering if pthreads is the culprit.

mshindo 05-23-2009 10:08 PM

woooo, I worked it out. I wasn't linking with -g02

osor 05-23-2009 10:14 PM

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))


osor 05-26-2009 06:50 PM

What a difference 6 minutes makes :).

I’m glad you got it working, but I don’t understand your solution. What do you mean by “linking with -g02”? I am curious to know what this linker flag does and why it was necessary for you yet not for me.


All times are GMT -5. The time now is 07:57 PM.