1. 段錯誤是什麼
A segmentation fault (often shortened to segfault) is a particular error condition that can occur during the operation of computer software. In short, a segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (e.g., attempts to write to a read-only location, or to overwrite part of the operating system). Systems based on processors like the Motorola 68000 tend to refer to these events as Address or Bus errors.
Segmentation is one approach to memory management and protection in the operating system. It has been superseded by paging for most purposes, but much of the terminology of segmentation is still used, "segmentation fault" being an example. Some operating systems still have segmentation at some logical level although paging is used as the main memory management policy.
On Unix-like operating systems, a process that accesses invalid memory receives the SIGSEGV signal. On Microsoft Windows, a process that accesses invalid memory receives the STATUS_ACCESS_VIOLATION exception.
2. 段錯誤產生的緣由
2.1 訪問不存在的內存地址
##void main(){int *ptr = NULL; *ptr = 0;}
2.2 訪問系統保護的內存地址
##void main(){int *ptr = (int *)0; *ptr = 100;}
2.3 訪問只讀的內存地址
###void main(){char *ptr = "test"; strcpy(ptr, "TEST");}
2.4 棧溢出
##void main(){ main();}
等等其餘緣由。javascript
3. 段錯誤信息的獲取
3.1 dmesg
panfeng@ubuntu:~/segfault$ dmesg[ 2329.479037] segfault3[2700]: segfault at 80484e0 ip 00d2906a sp bfbbec3c error 7 in libc-2.10.1.so[cb4000+13e000]
3.2 -g
panfeng@ubuntu:~/segfault$ gcc -g -o segfault3 segfault3.c
3.3 nm
~/segfault$ nm segfault3 :08049f20 d _DYNAMIC08049ff4 d _GLOBAL_OFFSET_TABLE_080484dc R _IO_stdin_used w _Jv_RegisterClasses08049f10 d __CTOR_END__08049f0c d __CTOR_LIST__08049f18 D __DTOR_END__08049f14 d __DTOR_LIST__080484ec r __FRAME_END__08049f1c d __JCR_END__08049f1c d __JCR_LIST__0804a014 A __bss_start0804a00c D __data_start08048490 t __do_global_ctors_aux08048360 t __do_global_dtors_aux0804a010 D __dso_handle w __gmon_start__0804848a T __i686.get_pc_thunk.bx08049f0c d __init_array_end08049f0c d __init_array_start08048420 T __libc_csu_fini08048430 T __libc_csu_init U __libc_start_main@@GLIBC_2.00804a014 A _edata0804a01c A _end080484bc T _fini080484d8 R _fp_hw080482bc T _init08048330 T _start0804a014 b completed.69900804a00c W data_start0804a018 b dtor_idx.6992080483c0 t frame_dummy080483e4 T main U memcpy@@GLIBC_2.0
3.4 ldd
panfeng/segfault$ ldd ./segfault3 :~ linux-gate.so.1 => (0x00e08000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00675000) /lib/ld-linux.so.2 (0x00482000)
4. 段錯誤的調試方法
4.1 使用printf輸出信息
4.2 使用gcc和gdb
4.2.1 調試步驟
一、爲了可以使用gdb調試程序,在編譯階段加上-g參數,以程序2.3爲例:php
panfeng@ubuntu:~/segfault$ gcc -g -o segfault3 segfault3.c
二、使用gdb命令調試程序:html
panfeng@ubuntu:~/segfault$ gdb ./segfault3GNU gdb (GDB) 7.0-ubuntuCopyright (C) 2009 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 "i486-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/panfeng/segfault/segfault3...done.(gdb)
三、進入gdb後,運行程序:java
(gdb) runStarting program: /home/panfeng/segfault/segfault3
Program received signal SIGSEGV, Segmentation fault.0x001a306a in memcpy () from /lib/tls/i686/cmov/libc.so.6(gdb)
從輸出看出,程序2.3收到SIGSEGV信號,觸發段錯誤,並提示地址0x001a306a、調用memcpy報的錯,位於/lib/tls/i686/cmov/libc.so.6庫中。python
四、完成調試後,輸入quit命令退出gdb:linux
quit A debugging session is active.
Inferior 1 [process 3207] will be killed.
Quit anyway? (y or n) y
4.2.2 適用場景
4.3 使用core文件和gdb
在4.2節中提到段錯誤會觸發SIGSEGV信號,經過man 7 signal,能夠看到SIGSEGV默認的handler會打印段錯誤出錯信息,併產生core文件,由此咱們能夠藉助於程序異常退出時生成的core文件中的調試信息,使用gdb工具來調試程序中的段錯誤。程序員
4.3.1 調試步驟
一、在一些Linux版本下,默認是不產生core文件的,首先能夠查看一下系統core文件的大小限制:
redis
panfeng@ubuntu:~/segfault$ ulimit -c0
二、能夠看到默認設置狀況下,本機Linux環境下發生段錯誤時不會自動生成core文件,下面設置下core文件的大小限制(單位爲KB):typescript
panfeng@ubuntu:~/segfault$ ulimit -c 1024panfeng@ubuntu:~/segfault$ ulimit -c1024
panfeng@ubuntu:~/segfault$ ./segfault3段錯誤 (core dumped)
~/segfault$ gdb ./segfault3 ./core :GNU gdb (GDB) 7.0-ubuntuCopyright (C) 2009 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 "i486-linux-gnu".For bug reporting instructions, please see://www.gnu.org/software/gdb/bugs/>... :Reading symbols from /home/panfeng/segfault/segfault3...done.
warning: Can't read pathname for load map: 輸入/輸出錯誤.Reading symbols from /lib/tls/i686/cmov/libc.so.6...(no debugging symbols found)...done.Loaded symbols for /lib/tls/i686/cmov/libc.so.6Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.Loaded symbols for /lib/ld-linux.so.2Core was generated by `./segfault3'.Program terminated with signal 11, Segmentation fault.#0 0x0018506a in memcpy () from /lib/tls/i686/cmov/libc.6
(gdb) quit
4.3.2 適用場景
4.4 使用objdump
4.4.1 調試步驟
一、使用dmesg命令,找到最近發生的段錯誤輸出信息:ubuntu
panfeng@ubuntu:~/segfault$ dmesg... ...[17257.502808] segfault3[3320]: segfault at 80484e0 ip 0018506a sp bfc1cd6c error 7 in libc-2.10.1.so[110000+13e000]
其中,對咱們接下來的調試過程有用的是發生段錯誤的地址:80484e0和指令指針地址:0018506a。
二、使用objdump生成二進制的相關信息,重定向到文件中:
panfeng@ubuntu:~/segfault$ objdump -d ./segfault3 > segfault3Dump
其中,生成的segfault3Dump文件中包含了二進制文件的segfault3的彙編代碼。
三、在segfault3Dump文件中查找發生段錯誤的地址:
panfeng@ubuntu:~/segfault$ grep -n -A 10 -B 10 "80484e0" ./segfault3Dump121- 80483df: ff d0 call *%eax122- 80483e1: c9 leave123- 80483e2: c3 ret124- 80483e3: 90 nop125-126-080483e4 <main>:127- 80483e4: 55 push %ebp128- 80483e5: 89 e5 mov %esp,%ebp129- 80483e7: 83 e4 f0 and $0xfffffff0,%esp130- 80483ea: 83 ec 20 sub $0x20,%esp131: 80483ed: c7 44 24 1c e0 84 04 movl $0x80484e0,0x1c(%esp)132- 80483f4: 08133- 80483f5: b8 e5 84 04 08 mov $0x80484e5,%eax134- 80483fa: c7 44 24 08 05 00 00 movl $0x5,0x8(%esp)135- 8048401: 00136- 8048402: 89 44 24 04 mov %eax,0x4(%esp)137- 8048406: 8b 44 24 1c mov 0x1c(%esp),%eax138- 804840a: 89 04 24 mov %eax,(%esp)139- 804840d: e8 0a ff ff ff call 804831c <memcpy@plt>140- 8048412: c9 leave141- 8048413: c3 ret
經過對以上彙編代碼分析,得知段錯誤發生main函數,對應的彙編指令是movl $0x80484e0,0x1c(%esp),接下來打開程序的源碼,找到彙編指令對應的源碼,也就定位到段錯誤了。
4.4.2 適用場景
4.5 使用catchsegv
catchsegv命令專門用來撲獲段錯誤,它經過動態加載器(ld-linux.so)的預加載機制(PRELOAD)把一個事先寫好的庫(/lib/libSegFault.so)加載上,用於捕捉斷錯誤的出錯信息。
panfeng@ubuntu:~/segfault$ catchsegv ./segfault3Segmentation fault (core dumped)*** Segmentation faultRegister dump:
EAX: 00000000 EBX: 00fb3ff4 ECX: 00000002 EDX: 00000000 ESI: 080484e5 EDI: 080484e0 EBP: bfb7ad38 ESP: bfb7ad0c
EIP: 00ee806a EFLAGS: 00010203
CS: 0073 DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b
Trap: 0000000e Error: 00000007 OldMask: 00000000 ESP/signal: bfb7ad0c CR2: 080484e0
Backtrace:/lib/libSegFault.so[0x3b606f]??:0(??)[0xc76400]/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xe89b56]/build/buildd/eglibc-2.10.1/csu/../sysdeps/i386/elf/start.S:122(_start)[0x8048351]
Memory map:
00258000-00273000 r-xp 00000000 08:01 157 /lib/ld-2.10.1.so00273000-00274000 r--p 0001a000 08:01 157 /lib/ld-2.10.1.so00274000-00275000 rw-p 0001b000 08:01 157 /lib/ld-2.10.1.so003b4000-003b7000 r-xp 00000000 08:01 13105 /lib/libSegFault.so003b7000-003b8000 r--p 00002000 08:01 13105 /lib/libSegFault.so003b8000-003b9000 rw-p 00003000 08:01 13105 /lib/libSegFault.so00c76000-00c77000 r-xp 00000000 00:00 0 [vdso]00e0d000-00e29000 r-xp 00000000 08:01 4817 /lib/libgcc_s.so.100e29000-00e2a000 r--p 0001b000 08:01 4817 /lib/libgcc_s.so.100e2a000-00e2b000 rw-p 0001c000 08:01 4817 /lib/libgcc_s.so.100e73000-00fb1000 r-xp 00000000 08:01 1800 /lib/tls/i686/cmov/libc-2.10.1.so00fb1000-00fb2000 ---p 0013e000 08:01 1800 /lib/tls/i686/cmov/libc-2.10.1.so00fb2000-00fb4000 r--p 0013e000 08:01 1800 /lib/tls/i686/cmov/libc-2.10.1.so00fb4000-00fb5000 rw-p 00140000 08:01 1800 /lib/tls/i686/cmov/libc-2.10.1.so00fb5000-00fb8000 rw-p 00000000 00:00 008048000-08049000 r-xp 00000000 08:01 303895 /home/panfeng/segfault/segfault308049000-0804a000 r--p 00000000 08:01 303895 /home/panfeng/segfault/segfault30804a000-0804b000 rw-p 00001000 08:01 303895 /home/panfeng/segfault/segfault309432000-09457000 rw-p 00000000 00:00 0 [heap]b78cf000-b78d1000 rw-p 00000000 00:00 0b78df000-b78e1000 rw-p 00000000 00:00 0bfb67000-bfb7c000 rw-p 00000000 00:00 0 [stack]
5. 一些注意事項
6. 參考資料列表
一、http://www.docin.com/p-105923877.html
二、http://blog.chinaunix.net/space.php?uid=317451&do=blog&id=92412
本文分享自微信公衆號 - 人人都是極客(rrgeek)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。