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


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

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

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

Backtrace: Расположение Линий:

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, и он отлично работает.....кто-нибудь может сказать мне, как использовать его на Солярисе из свалки наверху? Я не могу заставить его работать ; - (

Любой совет будет чрезвычайно оценил

Спасибо

Линтон

1 4

1 ответ:

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

Тем не менее, пожалуйста, найдите ниже пример использования gaddr2line (именно так Solaris пишет 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