Как получить 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 ответ:
Я начну с того, что 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