精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux環境下段錯誤的產生原因及調試方法小結

Linux閱碼場 ? 來源:Linuxer ? 2020-04-30 15:23 ? 次閱讀

最近在Linux環境下做C語言項目,由于是在一個原有項目基礎之上進行二次開發,而且項目工程龐大復雜,出現了不少問題,其中遇到最多、花費時間最長的問題就是著名的“段錯誤”(Segmentation Fault)。借此機會系統學習了一下,這里對Linux環境下的段錯誤做個小結,方便以后同類問題的排查與解決。

1. 段錯誤是什么

一句話來說,段錯誤是指訪問的內存超出了系統給這個程序所設定的內存空間,例如訪問了不存在的內存地址、訪問了系統保護的內存地址、訪問了只讀的內存地址等等情況。這里貼一個對于“段錯誤”的準確定義(參考Answers.com):

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 訪問不存在的內存地址

#include#includevoid main(){int *ptr = NULL; *ptr = 0;}

2.2 訪問系統保護的內存地址

#include#includevoid main(){int *ptr = (int *)0; *ptr = 100;}

2.3 訪問只讀的內存地址

#include#include#includevoid main(){char *ptr = "test"; strcpy(ptr, "TEST");}

2.4 棧溢出

#include#includevoid main(){ main();}

等等其他原因。

3. 段錯誤信息的獲取

程序發生段錯誤時,提示信息很少,下面有幾種查看段錯誤的發生信息的途徑。

3.1 dmesg

dmesg可以在應用程序crash掉時,顯示內核中保存的相關信息。如下所示,通過dmesg命令可以查看發生段錯誤的程序名稱、引起段錯誤發生的內存地址、指令指針地址、堆棧指針地址、錯誤代碼、錯誤原因等。以程序2.3為例:

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

使用gcc編譯程序的源碼時,加上-g參數,這樣可以使得生成的二進制文件中加入可以用于gdb調試的有用信息。以程序2.3為例:

panfeng@ubuntu:~/segfault$ gcc -g -o segfault3 segfault3.c

3.3 nm

使用nm命令列出二進制文件中的符號表,包括符號地址、符號類型、符號名等,這樣可以幫助定位在哪里發生了段錯誤。以程序2.3為例:

panfeng@ubuntu:~/segfault$ nm segfault308049f20 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

使用ldd命令查看二進制程序的共享鏈接庫依賴,包括庫的名稱、起始地址,這樣可以確定段錯誤到底是發生在了自己的程序中還是依賴的共享庫中。以程序2.3為例:

panfeng@ubuntu:~/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輸出信息

這個是看似最簡單但往往很多情況下十分有效的調試方式,也許可以說是程序員用的最多的調試方式。簡單來說,就是在程序的重要代碼附近加上像printf這類輸出信息,這樣可以跟蹤并打印出段錯誤在代碼中可能出現的位置。

為了方便使用這種方法,可以使用條件編譯指令#ifdef DEBUG和#endif把printf函數包起來。這樣在程序編譯時,如果加上-DDEBUG參數就能查看調試信息;否則不加該參數就不會顯示調試信息。

4.2 使用gcc和gdb

4.2.1 調試步驟

1、為了能夠使用gdb調試程序,在編譯階段加上-g參數,以程序2.3為例:

panfeng@ubuntu:~/segfault$ gcc -g -o segfault3 segfault3.c

2、使用gdb命令調試程序:

panfeng@ubuntu:~/segfault$ gdb ./segfault3GNU gdb (GDB) 7.0-ubuntuCopyright (C) 2009 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later 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:...Reading symbols from /home/panfeng/segfault/segfault3...done.(gdb)

3、進入gdb后,運行程序:

(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庫中。

4、完成調試后,輸入quit命令退出gdb:

(gdb) quitA debugging session is active. Inferior 1 [process 3207] will be killed. Quit anyway? (y or n) y

4.2.2 適用場景

1、僅當能確定程序一定會發生段錯誤的情況下使用。

2、當程序的源碼可以獲得的情況下,使用-g參數編譯程序。

3、一般用于測試階段,生產環境下gdb會有副作用:使程序運行減慢,運行不夠穩定,等等。

4、即使在測試階段,如果程序過于復雜,gdb也不能處理。

4.3 使用core文件和gdb

在4.2節中提到段錯誤會觸發SIGSEGV信號,通過man 7 signal,可以看到SIGSEGV默認的handler會打印段錯誤出錯信息,并產生core文件,由此我們可以借助于程序異常退出時生成的core文件中的調試信息,使用gdb工具來調試程序中的段錯誤。

4.3.1 調試步驟

1、在一些Linux版本下,默認是不產生core文件的,首先可以查看一下系統core文件的大小限制:

panfeng@ubuntu:~/segfault$ ulimit -c0

2、可以看到默認設置情況下,本機Linux環境下發生段錯誤時不會自動生成core文件,下面設置下core文件的大小限制(單位為KB):

panfeng@ubuntu:~/segfault$ ulimit -c 1024panfeng@ubuntu:~/segfault$ ulimit -c1024

3、運行程序2.3,發生段錯誤生成core文件:

panfeng@ubuntu:~/segfault$ ./segfault3段錯誤 (core dumped)

4、加載core文件,使用gdb工具進行調試:

panfeng@ubuntu:~/segfault$ gdb ./segfault3 ./coreGNU gdb (GDB) 7.0-ubuntuCopyright (C) 2009 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later 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:...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

從輸出看出,同4.2.1中一樣的段錯誤信息。

5、完成調試后,輸入quit命令退出gdb:

(gdb) quit

4.3.2 適用場景

1、適合于在實際生成環境下調試程序的段錯誤(即在不用重新發生段錯誤的情況下重現段錯誤)。

2、當程序很復雜,core文件相當大時,該方法不可用。

4.4 使用objdump

4.4.1 調試步驟

1、使用dmesg命令,找到最近發生的段錯誤輸出信息:

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。

2、使用objdump生成二進制的相關信息,重定向到文件中:

panfeng@ubuntu:~/segfault$ objdump -d ./segfault3 > segfault3Dump

其中,生成的segfault3Dump文件中包含了二進制文件的segfault3的匯編代碼。

3、在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

: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 140- 8048412: c9 leave141- 8048413: c3 ret

通過對以上匯編代碼分析,得知段錯誤發生main函數,對應的匯編指令是movl $0x80484e0,0x1c(%esp),接下來打開程序的源碼,找到匯編指令對應的源碼,也就定位到段錯誤了。

4.4.2 適用場景

1、不需要-g參數編譯,不需要借助于core文件,但需要有一定的匯編語言基礎。

2、如果使用了gcc編譯優化參數(-O1,-O2,-O3)的話,生成的匯編指令將會被優化,使得調試過程有些難度。

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. 一些注意事項

1、出現段錯誤時,首先應該想到段錯誤的定義,從它出發考慮引發錯誤的原因。

2、在使用指針時,定義了指針后記得初始化指針,在使用的時候記得判斷是否為NULL。

3、在使用數組時,注意數組是否被初始化,數組下標是否越界,數組元素是否存在等。

4、在訪問變量時,注意變量所占地址空間是否已經被程序釋放掉。

5、在處理變量時,注意變量的格式控制是否合理等。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 二進制
    +關注

    關注

    2

    文章

    794

    瀏覽量

    41603
  • Linux
    +關注

    關注

    87

    文章

    11232

    瀏覽量

    208958
  • 內存
    +關注

    關注

    8

    文章

    3004

    瀏覽量

    73900

原文標題:Linux環境下段錯誤的產生原因及調試方法小結

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    BGA焊接產生不飽滿焊點的原因和解決方法

    BGA問題,其根本原因是焊點錫膏不足,下面深圳佳金源錫膏廠家來講解一下原因和解決方法有哪些?一、產生原因BGA維修過程中遇到的不飽滿焊點的另
    的頭像 發表于 11-18 17:11 ?271次閱讀
    BGA焊接<b class='flag-5'>產生</b>不飽滿焊點的<b class='flag-5'>原因</b>和解決<b class='flag-5'>方法</b>

    Linux環境變量配置方法

    Linux環境變量配置分為設置永久變量和臨時變量兩種。環境變量設置方法同時要考慮環境Shell類型,不同類型的SHELL設置臨時變量
    的頭像 發表于 10-23 13:39 ?129次閱讀

    紋波電壓的產生原因及控制方法

    紋波電壓是電源系統中常見的一種現象,它是指電源輸出電壓在平均值附近波動的幅度。紋波電壓的大小直接影響到電源系統的穩定性和可靠性,因此對紋波電壓的控制非常重要。 紋波電壓的產生原因 紋波電壓的產生
    的頭像 發表于 08-29 09:30 ?639次閱讀

    服務器錯誤是怎么回事?常見錯誤原因及解決方法匯總

    服務器錯誤是怎么回事?最常見的原因分有六個,分別是:硬件問題、軟件問題、網絡問題、資源耗盡、數據庫、文件權限問題。可以根據以下具體錯誤原因進行辨別,并選擇適合的解決
    的頭像 發表于 08-12 10:11 ?1347次閱讀

    交越失真產生原因和消除方法

    和運算放大器中。本文將介紹交越失真的產生原因、影響因素以及消除方法。 一、交越失真的產生原因 放大器的非線性特性 放大器的非線性特性是交越失
    的頭像 發表于 08-01 15:07 ?2747次閱讀

    變頻器產生震動和噪音的原因和處理方法

    變頻器產生震動和噪音的原因和處理方法吧。 ? ? ??振動與噪聲產生原因是變頻器工作時,輸出波形中的高次諧波引起的磁場對許多機械部件
    的頭像 發表于 06-16 11:37 ?1809次閱讀

    變頻器產生噪音的原因及處理方法

    噪音的原因并采取有效的處理方法,對于確保設備安全、提高工作效率具有重要意義。本文將對變頻器產生噪音的原因進行深入分析,并提出相應的處理方法
    的頭像 發表于 06-11 17:50 ?3566次閱讀

    競爭與冒險產生原因,判斷方法和避免競爭與冒險的方法

    在實際的電路設計過程中,存在傳播延時和信號變換延時。由延時引起的競爭與冒險現象會影響輸出的正確與否。下面將就 競爭與冒險產生原因 , 判斷方法 和 避免競爭與冒險的方法 進行討論,希
    的頭像 發表于 02-18 14:34 ?6909次閱讀
    競爭與冒險<b class='flag-5'>產生</b>的<b class='flag-5'>原因</b>,判斷<b class='flag-5'>方法</b>和避免競爭與冒險的<b class='flag-5'>方法</b>

    如何使用linux下gdb來調試python程序

    如何使用linux下gdb來調試python程序? 在Linux下,可以使用GDB(GNU調試器)來調試Python程序。GDB是一個強大的
    的頭像 發表于 01-31 10:41 ?2437次閱讀

    PCB產生串擾的原因及解決方法

    PCB產生串擾的原因及解決方法? PCB(印刷電路板)是電子產品中非常重要的組成部分,它連接著各種電子元件,并提供電氣連接和機械支撐。在 PCB 設計和制造過程中,串擾是一個常見的問題,它可
    的頭像 發表于 01-18 11:21 ?1934次閱讀

    DCS系統調試內容及方法

    在這一層次中,通過設置斷點1、2,使DCS調試與輔助儀表盤儀表調試相對獨立、互不干擾,從而便于實現對這兩個工序的平行作業,并可避免因設備狀態不正常或接線錯誤原因造成設備的損壞。
    發表于 01-18 10:46 ?1692次閱讀
    DCS系統<b class='flag-5'>調試</b>內容及<b class='flag-5'>方法</b>

    Linux環境變量配置方法

    想必大家平時工作中也會配置Linux環境變量,但是可能也僅僅是為解決某些工具的運行環境,對于Linux環境變量本身的配置學問還沒深入了解。
    的頭像 發表于 01-04 09:51 ?509次閱讀

    ug內部錯誤,內存訪問違例怎么解決

    問題,并提供一些預防這些問題的最佳實踐方法。 一、內部錯誤原因和解決方法 1. 軟件錯誤:軟件錯誤
    的頭像 發表于 12-27 16:27 ?6100次閱讀

    linux打開文本文件命令提示錯誤

    Linux中打開文本文件的命令通常是使用文本編輯器打開,例如常用的命令有 vi 、 vim 、 nano 等。如果在使用其中一個命令時出現錯誤提示,可能有以下幾種原因和解決方法
    的頭像 發表于 12-22 15:10 ?806次閱讀

    鋰電池熱失控氣體產生原因、分析方法

    設計缺陷、電池使用不當以及惡劣工作環境。以下將對這三個方面進行詳盡、詳實、細致的分析,并介紹相應的分析方法。 首先,電池設計缺陷是導致鋰電池熱失控氣體產生的一個重要原因。電池的設計缺陷
    的頭像 發表于 12-08 15:55 ?1117次閱讀