其餘相關內容可參考個人部落格
走查程式碼,逐步新增printf列印,逐步定位,該方法最簡單,且在開發偵錯過程中也較爲快捷有效
編譯時加入-g參數,使用gdb偵錯執行程式,出現錯誤時直接列印堆疊資訊來定位
[root@VM_0_4_centos example_breakInSo]# gdb main
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/yu.tian/stackBreak/example_breakInSo/main...done.
(gdb) r
Starting program: /home/yu.tian/stackBreak/example_breakInSo/main
sum:3
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bd9812 in add (para1=1, para2=2) at add.cpp:21
21 memcpy((char *)0x9527, name, sizeof(name));
Missing separate debuginfos, use: debuginfo-install glibc-2.17-292.el7.x86_64 libgcc-4.8.5-39.el7.x86_64 libstdc++-4.8.5-39.el7.x86_64
(gdb) bt
#0 0x00007ffff7bd9812 in add (para1=1, para2=2) at add.cpp:21
#1 0x0000000000400634 in main () at main.c:10
(gdb)
適用場景:開發偵錯過程中,方便重新編譯和執行
開啓core dump,ulimi -c unlimited
,程式崩潰時會生成core檔案,使用gdb檢視堆疊資訊定位
適用場景:
其實段錯誤的core dump也是藉助了內核的反異常程式碼生成了core檔案,那麼發生段錯誤的時候在/var/log/messages
中也有相關的提示資訊,可使用dmesg
檢視內核列印
一般的形式爲
進程名[pid]: segfault at 錯誤地址 ip 錯誤指令 sp 錯誤堆疊 error 錯誤原因 in 錯誤發生的可執行檔名稱[載入基地址+不知道是啥東西]
例如
main[18281]: segfault at 9527 ip 00007fdd5de94812 sp 00007fff486ea9d0 error 6 in libadd.so[7fdd5de94000+1000]
錯誤原因由3個bit組成,含義如下:
我們可通過錯誤指令地址-動態庫載入的基地址得到函數的相對地址,再配合nm
找到地址附近的函數,使用gdb
或者objdump
反彙編後定位到函數內的具體位置
適用場景:
範例如下:
肥腸簡單的原始碼,爲了增大定位難度,簡單的加了些無用程式碼
#include "add.h"
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char name[] = "aaa12312312312312313123123123121231312123sdasfasasfafasdasdadasdasdadsad";
int testUp(int para)
{
return 0;
}
int add(int para1, int para2)
{
int a = 1,b = 2;
int sum = a + b;
printf("sum:%d\n",sum);
a = 3;
b = 4;
usleep(1);
memcpy((char *)0x9527, name, sizeof(name));
usleep(10);
sum = a + b;
a = 0;
b = 0;
return a+b;
}
int testDown(int para)
{
return 1;
}
執行程式,
[root@VM_0_4_centos example_breakInSo]# ./main
sum:3
Segmentation fault
出現了段錯誤,此時沒有開啓core檔案,可檢視內核列印資訊
[root@VM_0_4_centos example_breakInSo]# dmesg | tail -1
[19739.211945] main[18281]: segfault at 9527 ip 00007fdd5de94812 sp 00007fff486ea9d0 error 6 in libadd.so[7fdd5de94000+1000]
可見發生錯誤的指令地址爲0x7fdd5de94812
,並且錯誤位置爲libadd.so
,該動態庫載入的基地址爲0x7fdd5de94000
所以錯誤函數的相對地址爲0x7fdd5de94812-0x7fdd5de94000 = 0x812
接下來使用nm
命令檢視符號表,大概定位出現問題的函數
[root@VM_0_4_centos example_breakInSo]# nm libadd.so -n -l -C
w __cxa_finalize@@GLIBC_2.2.5
w __gmon_start__
w _ITM_deregisterTMCloneTable
w _ITM_registerTMCloneTable
w _Jv_RegisterClasses
U printf@@GLIBC_2.2.5
U usleep@@GLIBC_2.2.5
0000000000000648 T _init
00000000000006c0 t deregister_tm_clones
00000000000006f0 t register_tm_clones
0000000000000730 t __do_global_dtors_aux
0000000000000770 t frame_dummy
00000000000007a5 T testUp(int) /home/yu.tian/stackBreak/example_breakInSo/add.cpp:8
00000000000007b3 T add(int, int) /home/yu.tian/stackBreak/example_breakInSo/add.cpp:13
00000000000008b2 T testDown(int) /home/yu.tian/stackBreak/example_breakInSo/add.cpp:31
00000000000008c0 T _fini
00000000000008d4 r __GNU_EH_FRAME_HDR
00000000000009a0 r __FRAME_END__
0000000000200dc0 t __frame_dummy_init_array_entry
0000000000200dc8 t __do_global_dtors_aux_fini_array_entry
0000000000200dd0 d __JCR_END__
0000000000200dd0 d __JCR_LIST__
0000000000200dd8 d __dso_handle
0000000000200de0 d _DYNAMIC
0000000000201000 d _GLOBAL_OFFSET_TABLE_
0000000000201040 D name /home/yu.tian/stackBreak/example_breakInSo/add.cpp:6
0000000000201089 B __bss_start
0000000000201089 b completed.6355
0000000000201089 D _edata
0000000000201090 B _end
0000000000201090 d __TMC_END__
可以發現大致就是在add這個函數中出現錯誤嗒,那麼接下來使用objdump
命令反彙編來精確定位錯誤位置
[root@VM_0_4_centos example_breakInSo]# objdump libadd.so -S -C --start-address=0x7b3 --stop-address=0x8b2
libadd.so: file format elf64-x86-64
Disassembly of section .text:
00000000000007b3 <add(int, int)>:
{
return 0;
}
int add(int para1, int para2)
{
7b3: 55 push %rbp
7b4: 48 89 e5 mov %rsp,%rbp
7b7: 48 83 ec 20 sub $0x20,%rsp
7bb: 89 7d ec mov %edi,-0x14(%rbp)
7be: 89 75 e8 mov %esi,-0x18(%rbp)
int a = 1,b = 2;
7c1: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
7c8: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
int sum = a + b;
7cf: 8b 45 f8 mov -0x8(%rbp),%eax
7d2: 8b 55 fc mov -0x4(%rbp),%edx
7d5: 01 d0 add %edx,%eax
7d7: 89 45 f4 mov %eax,-0xc(%rbp)
printf("sum:%d\n",sum);
7da: 8b 45 f4 mov -0xc(%rbp),%eax
7dd: 89 c6 mov %eax,%esi
7df: 48 8d 3d e3 00 00 00 lea 0xe3(%rip),%rdi # 8c9 <_fini+0x9>
7e6: b8 00 00 00 00 mov $0x0,%eax
7eb: e8 90 fe ff ff callq 680 <printf@plt>
a = 3;
7f0: c7 45 fc 03 00 00 00 movl $0x3,-0x4(%rbp)
b = 4;
7f7: c7 45 f8 04 00 00 00 movl $0x4,-0x8(%rbp)
usleep(1);
7fe: bf 01 00 00 00 mov $0x1,%edi
803: e8 a8 fe ff ff callq 6b0 <usleep@plt>
memcpy((char *)0x9527, name, sizeof(name));
808: 48 8b 05 e9 07 20 00 mov 0x2007e9(%rip),%rax # 200ff8 <name@@Base-0x48>
80f: 48 8b 10 mov (%rax),%rdx
812: 48 89 14 25 27 95 00 mov %rdx,0x9527
819: 00
81a: 48 8b 50 08 mov 0x8(%rax),%rdx
81e: 48 89 14 25 2f 95 00 mov %rdx,0x952f
825: 00
826: 48 8b 50 10 mov 0x10(%rax),%rdx
82a: 48 89 14 25 37 95 00 mov %rdx,0x9537
831: 00
832: 48 8b 50 18 mov 0x18(%rax),%rdx
836: 48 89 14 25 3f 95 00 mov %rdx,0x953f
83d: 00
83e: 48 8b 50 20 mov 0x20(%rax),%rdx
842: 48 89 14 25 47 95 00 mov %rdx,0x9547
849: 00
84a: 48 8b 50 28 mov 0x28(%rax),%rdx
84e: 48 89 14 25 4f 95 00 mov %rdx,0x954f
855: 00
856: 48 8b 50 30 mov 0x30(%rax),%rdx
85a: 48 89 14 25 57 95 00 mov %rdx,0x9557
861: 00
862: 48 8b 50 38 mov 0x38(%rax),%rdx
866: 48 89 14 25 5f 95 00 mov %rdx,0x955f
86d: 00
86e: 48 8b 50 40 mov 0x40(%rax),%rdx
872: 48 89 14 25 67 95 00 mov %rdx,0x9567
879: 00
87a: 0f b6 40 48 movzbl 0x48(%rax),%eax
87e: 88 04 25 6f 95 00 00 mov %al,0x956f
usleep(10);
885: bf 0a 00 00 00 mov $0xa,%edi
88a: e8 21 fe ff ff callq 6b0 <usleep@plt>
sum = a + b;
88f: 8b 45 f8 mov -0x8(%rbp),%eax
892: 8b 55 fc mov -0x4(%rbp),%edx
895: 01 d0 add %edx,%eax
897: 89 45 f4 mov %eax,-0xc(%rbp)
a = 0;
89a: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
b = 0;
8a1: c7 45 f8 00 00 00 00 movl $0x0,-0x8(%rbp)
return a+b;
8a8: 8b 45 f8 mov -0x8(%rbp),%eax
8ab: 8b 55 fc mov -0x4(%rbp),%edx
8ae: 01 d0 add %edx,%eax
}
8b0: c9 leaveq
8b1: c3 retq
[root@VM_0_4_centos example_breakInSo]#
可以找到錯誤地址0x812
的具體位置啦,就是在這個memcpy處,可以看出確實是在向0x9527
地址寫內容的時候報錯啦,和我們構建的錯誤一致
使用GDB的方法如下
[root@VM_0_4_centos example_breakInSo]# gdb libadd.so
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/yu.tian/stackBreak/example_breakInSo/libadd.so...done.
(gdb) disas/m add
Dump of assembler code for function add(int, int):
14 {
0x00000000000007b3 <+0>: push %rbp
0x00000000000007b4 <+1>: mov %rsp,%rbp
0x00000000000007b7 <+4>: sub $0x20,%rsp
0x00000000000007bb <+8>: mov %edi,-0x14(%rbp)
0x00000000000007be <+11>: mov %esi,-0x18(%rbp)
15 int a = 1,b = 2;
0x00000000000007c1 <+14>: movl $0x1,-0x4(%rbp)
0x00000000000007c8 <+21>: movl $0x2,-0x8(%rbp)
16 int sum = a + b;
0x00000000000007cf <+28>: mov -0x8(%rbp),%eax
0x00000000000007d2 <+31>: mov -0x4(%rbp),%edx
0x00000000000007d5 <+34>: add %edx,%eax
0x00000000000007d7 <+36>: mov %eax,-0xc(%rbp)
17 printf("sum:%d\n",sum);
0x00000000000007da <+39>: mov -0xc(%rbp),%eax
0x00000000000007dd <+42>: mov %eax,%esi
0x00000000000007df <+44>: lea 0xe3(%rip),%rdi # 0x8c9
0x00000000000007e6 <+51>: mov $0x0,%eax
0x00000000000007eb <+56>: callq 0x680 <printf@plt>
18 a = 3;
0x00000000000007f0 <+61>: movl $0x3,-0x4(%rbp)
19 b = 4;
0x00000000000007f7 <+68>: movl $0x4,-0x8(%rbp)
20 usleep(1);
0x00000000000007fe <+75>: mov $0x1,%edi
0x0000000000000803 <+80>: callq 0x6b0 <usleep@plt>
21 memcpy((char *)0x9527, name, sizeof(name));
0x0000000000000808 <+85>: mov 0x2007e9(%rip),%rax # 0x200ff8
0x000000000000080f <+92>: mov (%rax),%rdx
0x0000000000000812 <+95>: mov %rdx,0x9527
0x000000000000081a <+103>: mov 0x8(%rax),%rdx
0x000000000000081e <+107>: mov %rdx,0x952f
0x0000000000000826 <+115>: mov 0x10(%rax),%rdx
0x000000000000082a <+119>: mov %rdx,0x9537
0x0000000000000832 <+127>: mov 0x18(%rax),%rdx
0x0000000000000836 <+131>: mov %rdx,0x953f
0x000000000000083e <+139>: mov 0x20(%rax),%rdx
0x0000000000000842 <+143>: mov %rdx,0x9547
0x000000000000084a <+151>: mov 0x28(%rax),%rdx
0x000000000000084e <+155>: mov %rdx,0x954f
0x0000000000000856 <+163>: mov 0x30(%rax),%rdx
0x000000000000085a <+167>: mov %rdx,0x9557
0x0000000000000862 <+175>: mov 0x38(%rax),%rdx
0x0000000000000866 <+179>: mov %rdx,0x955f
0x000000000000086e <+187>: mov 0x40(%rax),%rdx
0x0000000000000872 <+191>: mov %rdx,0x9567
0x000000000000087a <+199>: movzbl 0x48(%rax),%eax
0x000000000000087e <+203>: mov %al,0x956f
22
23 usleep(10);
0x0000000000000885 <+210>: mov $0xa,%edi
---Type <return> to continue, or q <return> to quit---
0x000000000000088a <+215>: callq 0x6b0 <usleep@plt>
24 sum = a + b;
0x000000000000088f <+220>: mov -0x8(%rbp),%eax
0x0000000000000892 <+223>: mov -0x4(%rbp),%edx
0x0000000000000895 <+226>: add %edx,%eax
0x0000000000000897 <+228>: mov %eax,-0xc(%rbp)
25 a = 0;
0x000000000000089a <+231>: movl $0x0,-0x4(%rbp)
26 b = 0;
0x00000000000008a1 <+238>: movl $0x0,-0x8(%rbp)
27 return a+b;
0x00000000000008a8 <+245>: mov -0x8(%rbp),%eax
0x00000000000008ab <+248>: mov -0x4(%rbp),%edx
0x00000000000008ae <+251>: add %edx,%eax
28 }
0x00000000000008b0 <+253>: leaveq
0x00000000000008b1 <+254>: retq
End of assembler dump.
結束、、、、
catchsegv
專門用於捕獲段錯誤
還是使用上一節的例子還定位問題
[root@VM_0_4_centos example_breakInSo]# catchsegv ./main
sum:3
*** Segmentation fault
Register dump:
RAX: 00007f22f9428040 RBX: 0000000000000000 RCX: 00007f22f86ff7f0
RDX: 3231333231616161 RSI: 0000000000000000 RDI: 00007ffecfd29eb0
RBP: 00007ffecfd29ef0 R8 : 0000000000000000 R9 : 00007f22f868727d
R10: 00007ffecfd29920 R11: 0000000000000246 R12: 0000000000400530
R13: 00007ffecfd29ff0 R14: 0000000000000000 R15: 0000000000000000
RSP: 00007ffecfd29ed0
RIP: 00007f22f9227812 EFLAGS: 00010202
CS: 0033 FS: 0000 GS: 0000
Trap: 0000000e Error: 00000006 OldMask: 00000000 CR2: 00009527
FPUCW: 0000037f FPUSW: 00000000 TAG: 00000000
RIP: 00000000 RDP: 00000000
ST(0) 0000 0000000000000000 ST(1) 0000 0000000000000000
ST(2) 0000 0000000000000000 ST(3) 0000 0000000000000000
ST(4) 0000 0000000000000000 ST(5) 0000 0000000000000000
ST(6) 0000 0000000000000000 ST(7) 0000 0000000000000000
mxcsr: 1f80
XMM0: 00000000000000000000000000000000 XMM1: 00000000000000000000000000000000
XMM2: 00000000000000000000000000000000 XMM3: 00000000000000000000000000000000
XMM4: 00000000000000000000000000000000 XMM5: 00000000000000000000000000000000
XMM6: 00000000000000000000000000000000 XMM7: 00000000000000000000000000000000
XMM8: 00000000000000000000000000000000 XMM9: 00000000000000000000000000000000
XMM10: 00000000000000000000000000000000 XMM11: 00000000000000000000000000000000
XMM12: 00000000000000000000000000000000 XMM13: 00000000000000000000000000000000
XMM14: 00000000000000000000000000000000 XMM15: 00000000000000000000000000000000
Backtrace:
./libadd.so(_Z3addii+0x5f)[0x7f22f9227812]
/home/yu.tian/stackBreak/example_breakInSo/main.c:10(main)[0x400634]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f22f865c505]
??:?(_start)[0x400559]
Memory map:
00400000-00401000 r-xp 00000000 fd:01 922445 /home/yu.tian/stackBreak/example_breakInSo/main
00600000-00601000 r--p 00000000 fd:01 922445 /home/yu.tian/stackBreak/example_breakInSo/main
00601000-00602000 rw-p 00001000 fd:01 922445 /home/yu.tian/stackBreak/example_breakInSo/main
00c7d000-00ca2000 rw-p 00000000 00:00 0 [heap]
7f22f863a000-7f22f87fd000 r-xp 00000000 fd:01 3911 /usr/lib64/libc-2.17.so
7f22f87fd000-7f22f89fd000 ---p 001c3000 fd:01 3911 /usr/lib64/libc-2.17.so
7f22f89fd000-7f22f8a01000 r--p 001c3000 fd:01 3911 /usr/lib64/libc-2.17.so
7f22f8a01000-7f22f8a03000 rw-p 001c7000 fd:01 3911 /usr/lib64/libc-2.17.so
7f22f8a03000-7f22f8a08000 rw-p 00000000 00:00 0
7f22f8a08000-7f22f8a1d000 r-xp 00000000 fd:01 13 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f22f8a1d000-7f22f8c1c000 ---p 00015000 fd:01 13 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f22f8c1c000-7f22f8c1d000 r--p 00014000 fd:01 13 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f22f8c1d000-7f22f8c1e000 rw-p 00015000 fd:01 13 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f22f8c1e000-7f22f8d1f000 r-xp 00000000 fd:01 3919 /usr/lib64/libm-2.17.so
7f22f8d1f000-7f22f8f1e000 ---p 00101000 fd:01 3919 /usr/lib64/libm-2.17.so
7f22f8f1e000-7f22f8f1f000 r--p 00100000 fd:01 3919 /usr/lib64/libm-2.17.so
7f22f8f1f000-7f22f8f20000 rw-p 00101000 fd:01 3919 /usr/lib64/libm-2.17.so
7f22f8f20000-7f22f9009000 r-xp 00000000 fd:01 4235 /usr/lib64/libstdc++.so.6.0.19
7f22f9009000-7f22f9208000 ---p 000e9000 fd:01 4235 /usr/lib64/libstdc++.so.6.0.19
7f22f9208000-7f22f9210000 r--p 000e8000 fd:01 4235 /usr/lib64/libstdc++.so.6.0.19
7f22f9210000-7f22f9212000 rw-p 000f0000 fd:01 4235 /usr/lib64/libstdc++.so.6.0.19
7f22f9212000-7f22f9227000 rw-p 00000000 00:00 0
7f22f9227000-7f22f9228000 r-xp 00000000 fd:01 922615 /home/yu.tian/stackBreak/example_breakInSo/libadd.so
7f22f9228000-7f22f9427000 ---p 00001000 fd:01 922615 /home/yu.tian/stackBreak/example_breakInSo/libadd.so
7f22f9427000-7f22f9428000 r--p 00000000 fd:01 922615 /home/yu.tian/stackBreak/example_breakInSo/libadd.so
7f22f9428000-7f22f9429000 rw-p 00001000 fd:01 922615 /home/yu.tian/stackBreak/example_breakInSo/libadd.so
7f22f9429000-7f22f942d000 r-xp 00000000 fd:01 3908 /usr/lib64/libSegFault.so
7f22f942d000-7f22f962c000 ---p 00004000 fd:01 3908 /usr/lib64/libSegFault.so
7f22f962c000-7f22f962d000 r--p 00003000 fd:01 3908 /usr/lib64/libSegFault.so
7f22f962d000-7f22f962e000 rw-p 00004000 fd:01 3908 /usr/lib64/libSegFault.so
7f22f962e000-7f22f9650000 r-xp 00000000 fd:01 3501 /usr/lib64/ld-2.17.so
7f22f983b000-7f22f9840000 rw-p 00000000 00:00 0
7f22f984c000-7f22f984f000 rw-p 00000000 00:00 0
7f22f984f000-7f22f9850000 r--p 00021000 fd:01 3501 /usr/lib64/ld-2.17.so
7f22f9850000-7f22f9851000 rw-p 00022000 fd:01 3501 /usr/lib64/ld-2.17.so
7f22f9851000-7f22f9852000 rw-p 00000000 00:00 0
7ffecfd0a000-7ffecfd2b000 rw-p 00000000 00:00 0 [stack]
7ffecfda8000-7ffecfdaa000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
[root@VM_0_4_centos example_breakInSo]#
可見在Backtrace堆疊資訊中,列出了出問題的地方,_Z3addii+0x5f
即代表問題出在add函數的5f位置,從上一個例子來看,add函數基地址7b3+5f=0x812
,相吻合