<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    linux/unix 段錯誤捕獲【續】

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接 本文為“在C/C++中捕獲段錯誤,打印出錯的具體位置”的續篇,進一步解決涉及動態鏈接庫的情況。   背景知識: ·linux/unix下動態鏈接庫的基本原理 ·/proc/pid/maps文件的基本格式 ·動態鏈接庫:在進程執行過程中動態加載,進程間可以共享代碼,可用在發布升級包等場合   概述:     用戶自己編寫的代碼均編譯進了可執行文件里的時候,“在C/C++中捕獲段錯誤,打印出錯的具體位置”里給出了在發生段錯誤(或其他錯誤,讀者可以修改附件里面的頭文件,增加捕獲的錯誤類型)的情況下,輸出代碼執行路徑的方法。本文在此基礎上,分析了當用戶編寫的部分代碼不在可執行文件中時,如何獲取代碼執行路徑。     為簡潔起見,后文用“原方法”指代前一文章內的分析方法。   正文: 先給出本文示例代碼RFID設備管理軟件 segvCatch_ext.rar ) 命令行下執行的命令行次序如下: [root@redhat tcpBreak]# g++ -fPIC -shared -g -o libtest.so lib.cpp 
    [root@redhat tcpBreak]# g++ -g test.cpp ./libtest.so [root@redhat tcpBreak]# ./a.out [root@redhat tcpBreak]# addr2line...(省略)   一、出錯代碼在動態鏈接庫內時,原方法的輸出       有些情況下,我們會采用動態鏈接庫,如果出錯代碼行恰巧在動態鏈接庫內,原方法仍可得到出錯時的地址。例如:
    1. signal[8] catched when running code at 8048ab3
    2. signal[8] catched when running code at 4001771b
    3. signal[8] catched when running code at 400176fd
        此例中,調用addr2line小工具的輸出為
    1. [root@redhat tcpBreak]# addr2line 8048ab3 4001771b 400176fd -s -C -f -e a.out
    2. main
    3. test.cpp:15
    4. ??
    5. ??:0
    6. ??
    7. ??:0
        顯然,后面兩個地址翻譯不出來了,因為其實出錯代碼根本不在可執行文件 a.out 內,而是位于一個動態鏈接庫內。   二、動態鏈接庫的偏移地址        動態鏈接庫無非就是編譯后的代碼,里面有一些基本的段、符號信息。如果出錯代碼行在動態鏈接庫內,那必然可以從動態鏈接庫內找到出錯時的代碼行號。      好吧,那就讓我們試一下:
    1. [root@redhat tcpBreak]# addr2line 4001771b 400176fd -s -C -f -e libtest.so
    2. ??
    3. ??:0
    4. ??
    5. ??:0
        還是翻譯不出來。當然出不來了,因為進程掛掉時輸出的地址,和動態鏈接庫文件內的靜態偏移地址根本就不是一回事。所以我們需要知道出錯時,所輸出的代碼地址與動態鏈接庫偏移地址之間的關系。     事實上,每一個進程都對應了一個 /proc/pid 目錄,下面記載了諸多與該進程相關的信息,其中有一個maps文件,里面記錄了各個動態鏈接庫的加載地址。我們只需要根據所得到的出錯地址,以及這個maps文件,就可以得出具體是哪一個庫,相應的偏移地址是多少。本文用例產生的輸出為:
    1. -------------------------- 進程掛掉時的MAPS文件 --------------------------
    2. 08048000-08049000 r-xp 00000000 00:09 17256 /mnt/hgfs/share/net/tcpBreak/a.out
    3. 08049000-0804a000 rw-p 00001000 00:09 17256 /mnt/hgfs/share/net/tcpBreak/a.out
    4. 0804a000-0804b000 rwxp 00000000 00:00 0
    5. 40000000-40015000 r-xp 00000000 08:02 271023 /lib/ld-2.3.2.so
    6. 40015000-40016000 rw-p 00014000 08:02 271023 /lib/ld-2.3.2.so
    7. 40016000-40017000 rw-p 00000000 00:00 0
    8. 40017000-40018000 r-xp 00000000 00:09 17255 /mnt/hgfs/share/net/tcpBreak/libtest.so
    9. 40018000-40019000 rw-p 00000000 00:09 17255 /mnt/hgfs/share/net/tcpBreak/libtest.so
    10. 40019000-4001b000 rw-p 00000000 00:00 0
    11. 40026000-400cf000 r-xp 00000000 08:02 350892 /usr/lib/libstdc++.so.5.0.3
    12. 400cf000-400d4000 rw-p 000a9000 08:02 350892 /usr/lib/libstdc++.so.5.0.3
    13. 400d4000-400d9000 rw-p 00000000 00:00 0
    14. 400d9000-400fa000 r-xp 00000000 08:02 286922 /lib/tls/libm-2.3.2.so
    15. 400fa000-400fb000 rw-p 00020000 08:02 286922 /lib/tls/libm-2.3.2.so
    16. 400fb000-40102000 r-xp 00000000 08:02 271272 /lib/libgcc_s-3.2.2-20030225.so.1
    17. 40102000-40103000 rw-p 00007000 08:02 271272 /lib/libgcc_s-3.2.2-20030225.so.1
    18. 40103000-40104000 rw-p 00000000 00:00 0
    19. 42000000-4212e000 r-xp 00000000 08:02 286920 /lib/tls/libc-2.3.2.so
    20. 4212e000-42131000 rw-p 0012e000 08:02 286920 /lib/tls/libc-2.3.2.so
    21. 42131000-42133000 rw-p 00000000 00:00 0
    22. bfffd000-c0000000 rwxp ffffe000 00:00 0
    23. -------------------------------------------------------------------------
    24. --------------------------- 進程掛掉時的棧幀 --------------------------
    25. signal[8] catched when running code at 8048ab3
    26. signal[8] catched when running code at 4001771b
    27. signal[8] catched when running code at 400176fd
    28. -------------------------------------------------------------------------
        顯然 4001771b 400176fd 對應的庫是 libtest.so,偏移地址分別為 71b 6fd。   三、臨門一腳       知道了對應的動態鏈接庫和偏移地址后,我們進一步用 addr2line 將這個偏移地址翻譯一下就可以了。
    1. [root@redhat tcpBreak]# addr2line 71b 6fd -s -C -f -e libtest.so
    2. a()
    3. lib.cpp:14
    4. b()
    5. lib.cpp:10
        至此,大功告成。   四、簡而言之       不管是否有用到動態鏈接庫,我們將原方法得到的輸出,結合進程掛掉時maps文件的內容,就可以得到代碼出錯時的執行路徑。根據代碼所在部分,指定相應的文件給 addr2line 的 -e 參數即可。對于上面那個例子:
    1. [root@redhat tcpBreak]# addr2line 8048ab3 -s -C -f -e a.out
    2. main
    3. test.cpp:15
    4. [root@redhat tcpBreak]# addr2line 71b 6fd -s -C -f -e libtest.so
    5. a()
    6. lib.cpp:14
    7. b()
    8. lib.cpp:10
        本文發布的捕獲出錯執行路徑的方法:         1 在含有main函數的那個源碼文件里,包含segvCatch_ext.h這個頭文件         2 具體如何解析出錯時代碼的執行路徑,閱讀segvCatch_ext.h頭部的說明     適用場景已經在前一篇文章里面描述過了,有問題可以給我發郵件(fireworks2@foxmail.com)。     五、似有余味       一個程序啟動后,地址是如何進行映射的,MAPS文件是怎么生成的,庫又是怎么加載的,自行編寫動態鏈接庫時,有什么注意事項...     這些問題我也不甚明了,因為我自己也沒深究過,以后有時間可能會陸續補到博客里面。       參考資料: [1] Linux debug : addr2line追蹤出錯地址, http://www.linuxidc.com/Linux/2011-05/35780.htm [2] addr2line,可以根據一個地址打印出對應的代碼行, http://archive.cnblogs.com/a/1996110/ [3] Linux下 /proc/maps 文件分析,http://bbs.chinaunix.net/viewthread.php?tid=2000825 [4] 《程序員的自我修養—鏈接、裝載與庫》,俞甲子,石凡,潘愛民. (PS 此書甚好,推薦大家閱讀)RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全