LinuxQuestions.org
LinuxAnswers - the LQ Linux tutorial section.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 05-23-2009, 12:05 AM   #1
mshindo
LQ Newbie
 
Registered: Jun 2008
Posts: 8

Rep: Reputation: 1
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 ?
 
Old 05-23-2009, 03:25 AM   #2
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 70
Quote:
Originally Posted by mshindo View Post
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?
 
Old 05-23-2009, 09:16 PM   #3
mshindo
LQ Newbie
 
Registered: Jun 2008
Posts: 8

Original Poster
Rep: Reputation: 1
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.
 
Old 05-23-2009, 10:08 PM   #4
mshindo
LQ Newbie
 
Registered: Jun 2008
Posts: 8

Original Poster
Rep: Reputation: 1
woooo, I worked it out. I wasn't linking with -g02
 
Old 05-23-2009, 10:14 PM   #5
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 70
Quote:
Originally Posted by mshindo View Post
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 View Post
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))
…
 
Old 05-26-2009, 06:50 PM   #6
osor
HCL Maintainer
 
Registered: Jan 2006
Distribution: (H)LFS, Gentoo
Posts: 2,450

Rep: Reputation: 70
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.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
gdb: backtrace to file eantoranz Programming 1 11-28-2008 03:11 PM
Generating a backtrace for dummies (me). Daws Programming 4 11-17-2007 07:18 PM
stack backtrace with pthreads virtualCoder Programming 2 10-06-2007 05:42 AM
backtrace your program? lswhbcb Programming 6 05-24-2007 11:35 PM
Alsa backtrace? hosler Slackware 9 02-07-2006 12:23 AM


All times are GMT -5. The time now is 04:56 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration