Как получить BACKTRACE (функция + номер строки) в Solaris?

Я сделал некоторый код на C, который с радостью отправляет полную обратную трассировку с именем функции и номером строки в файл журнала.

Это было сделано с использованием смеси backtrace, backtrace_symbols и dladdr и ADDR2LINE в LINUX. Также используя "execinfo.h" в Linux....

Итак, по существу, следующее:

Обратный след: Линия

signalErrorHandler
/home/lynton/Desktop/TestThreadLeak/TestThreadLeak/./main.c:211
??
??:0
*__GI_raise
/build/buildd/eglibc-2.12.1/signal/../nptl/sysdeps/unix/sysv/linux/raise.c:64
*__GI_abort
/build/buildd/eglibc-2.12.1/stdlib/abort.c:94
__libc_message
/build/buildd/eglibc-2.12.1/libio/../sysdeps/unix/sysv/linux/libc_fatal.c:168
malloc_printerr
/build/buildd/eglibc-2.12.1/malloc/malloc.c:6283
*__GI___libc_free
/build/buildd/eglibc-2.12.1/malloc/malloc.c:3739
threadMainLoop
/home/lynton/Desktop/TestThreadLeak/TestThreadLeak/./main.c:260
start_thread
/build/buildd/eglibc-2.12.1/nptl/pthread_create.c:304
??
/build/buildd/eglibc-2.12.1/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:114

Теперь, когда я взял код в Solaris, я вижу, что он не поддерживается;-(

Я попробовал подход pstack в Solaris и получил что-то вроде:

15871:  ./exit_test
-----------------  lwp# 1 / thread# 1  --------------------
 ffffffff7efdaf48 lwp_wait (2, ffffffff7ffffb9c)
 ffffffff7efd34ac _thrp_join (2, 0, 0, 1, 0, ffffffff7ffffb9c) + 38
 00000001000012f0 main (1, ffffffff7ffffd28, ffffffff7ffffd38, 100101f68, 100000000, ffffffff7f500200) + 204
 0000000100000ba4 _start (0, 0, 0, 0, 0, 0) + 7c
-----------------  lwp# 2 / thread# 2  --------------------
 ffffffff7efdb210 waitid   (0, 3e01, ffffffff7eaf8c30, 3)
 ffffffff7efc9cbc waitpid (3e01, ffffffff7eaf8eb0, 0, 0, ffffffff7f100300, 0) + 64
 ffffffff7efbcc08 system (ffffffff7eaf9ff0, 1ad8, 1800, 0, ffffffff7f13c000, ffffffff7eaf8f18) + 394
 0000000100000fec signalErrorHandler (b, 0, ffffffff7eafbba0, 40000000, 0, 0) + 2bc
 ffffffff7efd6fdc __sighndlr (b, 0, ffffffff7eafbba0, 100000d30, 0, 0) + c
 ffffffff7efcab70 call_user_handler (ffffffff7f500a00, ffffffff7f500a00, ffffffff7eafbba0, 12, 0, 0) + 3e0
 ffffffff7efcad7c sigacthandler (0, 0, ffffffff7eafbba0, ffffffff7f500a00, 0, ffffffff7f13c000) + 68
 --- called from signal handler with signal 0 (SIGEXIT) ---
 ffffffff7ee0052c memcpy (ffffffff7ffffd28, 1fc000, 0, 0, 100001040, 0) + 30
 ffffffff7efd6eb0 _lwp_start (0, 0, 0, 0, 0, 0)

Как я могу как-то использовать вышеперечисленное, чтобы ПРОГРАММНО получить номера строк и имена функций? Я видел что-то про "walkcontext" или "walkstack".... у кого-нибудь есть пример кода, чтобы я мог получить номера строк и т. Д.?

Кроме того, я использовал ADDR2LINE в Linux, и он прекрасно работает..... может кто-нибудь сказать мне, как использовать его на Solaris из DUMP выше? Я не могу заставить его работать;-(

Любой совет будет высоко оценен

Спасибо

Линтон

1 ответ

Решение

Я начну с того, что C может оказаться не лучшим способом сделать это в 2011 году (в зависимости от ваших основных целей). Проверьте этот другой вопрос: Анализ двоичных файлов MIPS: есть ли библиотека Python для анализа двоичных данных? какие ссылки (например) pydevtools.

Тем не менее, пожалуйста, найдите ниже пример использования gaddr2line (это то, как заклинание Солярис addr2line).

Эта короткая программа просто вызывает функцию foo() который в свою очередь вызывает pstack(1) (в строке 9, через system(3C)). В выводе из программы pstack(1) говорит нам, что адрес в функции foo() когда system() вызывается 0x00010724. Наконец-то работает gaddr2line(1) на этот адрес говорит нам, что это соответствует строке 9 foo.c и мы прошли полный круг.

/tmp $ cat -n foo.c
     1  
     2  #include <stdio.h>
     3  #include <stdlib.h>
     4  #include <unistd.h>
     5  
     6  int foo() {
     7      char buf[64];
     8      snprintf(buf, 64, "/bin/pstack %i", getpid());
     9      return system(buf);
    10  }
    11  
    12  int main(int argc, char *argv[]) {
    13      return foo();
    14  }
    15  
/tmp $ gcc -g -o foo foo.c
/tmp $ 
/tmp $ ./foo 
15954:  ./foo
 ff2cd4d8 waitid   (0, 3e53, ffbff668, 3)
 ff2bce94 waitpid  (3e53, ffbff7bc, 0, 0, ffbff814, ff390140) + 60
 ff2afe20 system   (ffbff910, ff339bd0, 20000, 1, ff3303d8, ffbff814) + 2ec
 00010724 foo      (209b8, 1c00, ff335900, 4, ff392a00, ff2b6d6c) + 38
 00010748 main     (1, ffbffa34, ffbffa3c, 209dc, ff3900c0, 0) + c
 00010584 _start   (0, 0, 0, 0, 0, 0) + 5c
/tmp $ 
/tmp $ gaddr2line -e foo 00010724 
/tmp/foo.c:9
/tmp $ 

Исходя из этого, вот краткий пример использования walkcontext(3C) ходить по стеку. Однако, чтобы получить информацию о номере строки отладки, вам нужно будет запросить соответствующие разделы двоичного файла ELF(?), Используя (например) libdwarf в walker() функция, но это должно начать вас.

/tmp $ cat -n bar.c
     1  
     2  #include <stdio.h>
     3  #include <stdlib.h>
     4  #include <unistd.h>
     5  #include <ucontext.h>
     6  #include <dlfcn.h>
     7  
     8  int walker(uintptr_t pc, int sig, void *usrarg) {
     9  
    10      Dl_info dlip;
    11  
    12      if(dladdr((void *)pc, &dlip)) {
    13          (void)printf(" %08lx %s %s\n", pc, dlip.dli_fname, dlip.dli_sname);
    14          return 0;
    15      } else {
    16          perror("dladdr()");
    17          return -1;
    18      }
    19  
    20  }
    21  
    22  int bar() {
    23  
    24      char buf[64];
    25      snprintf(buf, 64, "/bin/pstack %i", getpid());
    26      system(buf);
    27  
    28      (void)printf("\nprintstack()\n");
    29      printstack(0);
    30  
    31      ucontext_t ucp;
    32      if(getcontext(&ucp)) {
    33          perror("\ngetcontext()");
    34          return -1;
    35      } else {
    36          (void)printf("\nwalkcontext()\n");
    37          return walkcontext(&ucp, &walker, NULL);
    38      }
    39  
    40  }
    41  
    42  int main(int argc, char *argv[]) {
    43      return bar();
    44  }
    45  
/tmp $ gcc -g -o bar bar.c
/tmp $
/tmp $ ./bar 
16486:  ./bar
 ff2cd4d8 waitid   (0, 4067, ffbff4b8, 3)
 ff2bce94 waitpid  (4067, ffbff60c, 0, 0, ffbff664, ff390140) + 60
 ff2afe20 system   (ffbff928, ff339bd0, 20000, 1, ff3303d8, ffbff664) + 2ec
 000108b8 bar      (20c70, 1c00, ff335900, 4, ff392a00, ff2b6d6c) + 38
 00010968 main     (1, ffbffa4c, ffbffa54, 20c94, ff3900c0, 0) + c
 00010698 _start   (0, 0, 0, 0, 0, 0) + 5c

printstack()
/tmp/bar:bar+0x54
/tmp/bar:main+0xc
/tmp/bar:_start+0x5c

walkcontext()
 00010968 /tmp/bar main
 00010698 /tmp/bar _start
Другие вопросы по тегам