0%

Some Debugging tips for linux

寫起來,免得忘記。

在程式Crash前直接呼叫gdb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void dump(int signo)
{
char buf[1024];
char cmd[1024];
FILE *fh;

snprintf(buf, sizeof(buf), "/proc/%d/cmdline", getpid());
if (!(fh = fopen(buf, "r")))
exit(0);
if (!fgets(buf, sizeof(buf), fh))
exit(0);
fclose(fh);
if (buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = '\0';
snprintf(cmd, sizeof(cmd), "gdb %s %d", buf, getpid());
system(cmd);

exit(0);
}
signal(SIGSEGV, &dump);

沒有gdb的情況下,使用backtrace和objdump / addr2line 進行分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <execinfo.h> // Important
void dump(int signo)
{
void *array[10];
size_t size;
char **strings;
size_t i;

size = backtrace(array, 10);
strings = backtrace_symbols(array, size);

printf("Obtained %zd stack frames.\n", size);

for (i = 0; i < size; i++)
printf ("%s\n", strings[i]);

free(strings);

exit(0);
}

在編譯的時候記得加上-rdynamic選項,這樣會有比較多的資訊產出。執行結果

1
2
3
4
5
6
7
8
Obtained 6 stack frames.
./a(dump+0x1c) [0x4009c9]
/lib/x86_64-linux-gnu/libc.so.6(+0x36ff0) [0x7fdbdcad7ff0]
./a(dummy_function+0x10) [0x400a5a]
./a(main+0x18) [0x400a77]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7fdbdcac2ec5]
./a() [0x4008e9]

透過 objdump 可以找到可能出錯得地方

1
2
3
4
5
6
7
8
9
10
11
$ objdump -d a
0000000000400a4a <dummy_function>:
400a4a: 55 push %rbp
400a4b: 48 89 e5 mov %rsp,%rbp
400a4e: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp)
400a55: 00
400a56: 48 8b 45 f8 mov -0x8(%rbp),%rax
400a5a: c6 00 00 movb $0x0,(%rax) <------ Here
400a5d: 5d pop %rbp
400a5e: c3 retq

或者是用Binary Hacks上寫的方法

1
2
3
4
$ gcc a.c -o a -rdynamic -g
$ addr2line -f -e a 0x400a5a
dummy_function
/home/hm/a.c:30