Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get call stack from any thread within C

In C on Solaris 10, I'd like to get the call stack from an arbitrary thread within a process.

I have many worker threads and one thread which monitors them all to detect tight loops and deadlocks. The function I'd like to implement is for the monitoring thread to print the call stack from the "hung" thread several times before it kills it.

I know how to implement this by having the monitoring thread execute pstack (with system() or by forking). But I would like to be able to implement this function in C. Is there any way to do this?

I know how to make a thread print its OWN call stack, by walking the stack, which is useful if it hits an assert, but not how to do this for another thread within the same process.

Thanks for any help. NickB

like image 633
NickB Avatar asked Aug 21 '09 08:08

NickB


2 Answers

You can use walkcontext() to walk the stack, using dladdr()/dladdr1() to convert the addresses to function names. walkcontext() takes a ucontext for the thread. If you don't have the cooperation of that thread then you can obtain a ucontext for it by stopping the thread (e.g. with PCTWSTOP) and then reading its address from the pr_oldcontext field of the lwpstatus structure for that thread, obtained from /proc/self/lstatus.

like image 143
mark4o Avatar answered Oct 05 '22 22:10

mark4o


If you are using gcc you can use the inbuilt function __builtin_return_address. void * __builtin_return_address (unsigned int level)

The function returns the address of the function from which the function is called. i.e the caller of the function.

The level specifies how many levels. 0 means current function 1 means caller, 2 means callers caller. The following example will provide the usage. By printing the addresses of the function, the call stack can be determined.

int calla()
{
   printf("Inside calla\n");
   printf("A1=%x\n",__builtin_return_address (0));
   printf("A2=%x\n",__builtin_return_address (1) );
   printf("A3=%x\n",__builtin_return_address (2) );
}
int callb()
{
    printf("Inside callb\n");
    calle();
    printf("B1=%x\n",__builtin_return_address (0) );
    printf("B2=%x\n",__builtin_return_address (1) );
    printf("B3=%x\n",__builtin_return_address (2) );
}
int callc()
{
    printf("Inside callc\n");
    printf("C1=%x\n",__builtin_return_address (0) );
    printf("C2=%x\n",__builtin_return_address (1) );
    printf("C3=%x\n",__builtin_return_address (2) );
}
int calld()
{
    printf("Inside calld\n");
    printf("D1=%x\n",__builtin_return_address (0) );
    printf("D2=%x\n",__builtin_return_address (1) );
    printf("D3=%x\n",__builtin_return_address (2) );
}
int calle()
{
    printf("Inside calle\n");
    printf("E1=%x\n",__builtin_return_address (0) );
    printf("E2=%x\n",__builtin_return_address (1) );
    printf("E3=%x\n",__builtin_return_address (2) );
}
main()
{
    printf("Address of main=%x calla=%x callb=%x callc=%x calld=%x calle=%x\n",main,calla,callb,callc,calld,calle);
    calla();
    callb();
    calld();
}
like image 25
Saradhi Avatar answered Oct 05 '22 22:10

Saradhi