Получить стек вызовов из любого потока в C - PullRequest
6 голосов
/ 21 августа 2009

В C на Solaris 10 я хотел бы получить стек вызовов из произвольного потока внутри процесса.

У меня много рабочих потоков и один поток, который отслеживает их все, чтобы обнаружить узкие петли и тупики. Функция, которую я хотел бы реализовать, заключается в том, чтобы поток мониторинга печатал стек вызовов из «зависшего» потока несколько раз, прежде чем он его убьет.

Я знаю, как реализовать это с помощью потока мониторинга, выполняющего pstack (с помощью system () или разветвления). Но я хотел бы иметь возможность реализовать эту функцию в C. Есть ли способ сделать это?

Я знаю, как заставить поток напечатать свой собственный стек вызовов, обходя стек, что полезно, если он достигает утверждения, но не знаю, как это сделать для другого потока в том же процессе.

Спасибо за любую помощь. NickB

Ответы [ 2 ]

4 голосов
/ 21 августа 2009

Вы можете использовать walkcontext() для обхода стека, используя dladdr() / dladdr1() для преобразования адресов в имена функций. walkcontext() принимает ucontext для потока. Если у вас нет сотрудничества с этим потоком, вы можете получить ucontext для него, остановив поток (например, с помощью PCTWSTOP), а затем считав его адрес из поля pr_oldcontext в lwpstatus структура для этой нити, полученная из /proc/self/lstatus.

3 голосов
/ 21 августа 2009

Если вы используете gcc, вы можете использовать встроенную функцию __builtin_return_address. void * __builtin_return_address (неподписанный int уровень)

Функция возвращает адрес функции, из которой вызывается функция. то есть вызывающая функция.

Уровень указывает, сколько уровней. 0 означает текущую функцию 1 означает вызывающего абонента, 2 означает вызывающего абонента. Следующий пример предоставит использование. Распечатывая адреса функции, можно определить стек вызовов.

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