免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
在C/C++程序中打印當(dāng)前函數(shù)調(diào)用棧

在C/C++程序中打印當(dāng)前函數(shù)調(diào)用棧

      前幾天幫同事跟蹤的一個(gè)程序莫名退出,沒(méi)有core dump(當(dāng)然ulimit是打開(kāi)的)的問(wèn)題。我們知道,正常情況下,如果程序因?yàn)槟撤N異常條件退出的話,應(yīng)該會(huì)產(chǎn)生core dump,而如果程序正常退出的話,應(yīng)該是直接或者間接的調(diào)用了exit()相關(guān)的函數(shù)?;谶@個(gè)事實(shí),我想到了這樣一個(gè)辦法,在程序開(kāi)始時(shí),通過(guò)系統(tǒng)提供的atexit(),向系統(tǒng)注冊(cè)一個(gè)回調(diào)函數(shù),在程序調(diào)用exit()退出的時(shí)候,這個(gè)回調(diào)函數(shù)就會(huì)被調(diào)用,然后我們?cè)诨卣{(diào)函數(shù)中打印出當(dāng)前的函數(shù)調(diào)用棧,由此便可以知道exit()是在哪里調(diào)用,從而上述問(wèn)題便迎刃而解了。上述方法用來(lái)解決類似問(wèn)題是非常行之有效的。在上面,我提到了在“回調(diào)函數(shù)中打印出當(dāng)前的函數(shù)調(diào)用?!?,相信細(xì)心的朋友應(yīng)該注意到這個(gè)了,本文的主要內(nèi)容就是詳細(xì)介紹,如何在程序中打印中當(dāng)前的函數(shù)調(diào)用棧。
      我之前寫(xiě)過(guò)一篇題目為《介紹幾個(gè)關(guān)于C/C++程序調(diào)試的函數(shù)》的文章,看到這里,請(qǐng)讀者朋友先看一下前面這篇,因?yàn)楸疚氖且郧懊孢@篇文章為基礎(chǔ)的。我正是用了backtrace()和backtrace_symbols()這兩個(gè)函數(shù)實(shí)現(xiàn)的,下面是一個(gè)簡(jiǎn)單的例子,通過(guò)這個(gè)例子我們來(lái)介紹具體的方法:

12345678910111213141516171819202122232425262728293031323334353637383940414243
#include <execinfo .h>#include <stdio .h>#include <stdlib .h> void fun1();void fun2();void fun3(); void print_stacktrace(); int main(){    fun3();} void fun1(){    printf("stackstrace begin:\n");    print_stacktrace();} void fun2(){    fun1();} void fun3(){    fun2();} void print_stacktrace(){    int size = 16;    void * array[16];    int stack_num = backtrace(array, size);    char ** stacktrace = backtrace_symbols(array, stack_num);    for (int i = 0; i < stack_num; ++i)    {        printf("%s\n", stacktrace[i]);    }    free(stacktrace);}

(說(shuō)明:下面的介紹采用的環(huán)境是ubuntu 11.04, x86_64, gcc-4.5.2)

  • 1. 通過(guò)下面的方式編譯運(yùn)行:
  • 12345678910
    wuzesheng@ubuntu:~/work/test$ gcc test.cc -o test1wuzesheng@ubuntu:~/work/test$ ./test1stackstrace begin:./test1() [0x400645]./test1() [0x400607]./test1() [0x400612]./test1() [0x40061d]./test1() [0x4005ed]/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xff) [0x7f5c59a91eff]./test1() [0x400529]

          從上面的運(yùn)行結(jié)果中,我們的確看到了函數(shù)的調(diào)用棧,但是都是16進(jìn)制的地址,會(huì)有點(diǎn)小小的不爽。當(dāng)然我們可以通過(guò)反匯編得到每個(gè)地址對(duì)應(yīng)的函數(shù),但這個(gè)還是有點(diǎn)麻煩了。不急,且聽(tīng)我慢慢道來(lái),看第2步。

  • 2. 通過(guò)下面的方式編譯運(yùn)行:
  • 12345678910
    wuzesheng@ubuntu:~/work/test$ gcc test.cc -rdynamic -o test2wuzesheng@ubuntu:~/work/test$ ./test2stackstrace begin:./test2(_Z16print_stacktracev+0x26) [0x4008e5]./test2(_Z4fun1v+0x13) [0x4008a7]./test2(_Z4fun2v+0x9) [0x4008b2]./test2(_Z4fun3v+0x9) [0x4008bd]./test2(main+0x9) [0x40088d]/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xff) [0x7f9370186eff]./test2() [0x4007c9]

          這下終于可以看到函數(shù)的名字了,對(duì)比一下2和1的編譯過(guò)程,2比1多了一個(gè)-rdynamic的選項(xiàng),讓我們來(lái)看看這個(gè)選項(xiàng)是干什么的(來(lái)自gcc mannual的說(shuō)明):

    12
    -rdynamic           Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of "dlopen" or to allow obtaining backtraces from within a program.

          從上面的說(shuō)明可以看出,它的主要作用是讓鏈接器把所有的符號(hào)都加入到動(dòng)態(tài)符號(hào)表中,這下明白了吧。不過(guò)這里還有一個(gè)問(wèn)題,這里的函數(shù)名都是mangle過(guò)的,需要demangle才能看到原始的函數(shù)。關(guān)于c++的mangle/demangle機(jī)制,不了解的朋友可以在搜索引擎上搜一下,我這里就不多就介紹了。這里介紹如何用命令來(lái)demangle,通過(guò)c++filt命令便可以:

    12
    wuzesheng@ubuntu:~/work/test$ c++filt < << "_Z16print_stacktracev"print_stacktrace()

          寫(xiě)到這里,大部分工作就ok了。不過(guò)不知道大家有沒(méi)有想過(guò)這樣一個(gè)問(wèn)題,同一個(gè)函數(shù)可以在代碼中多個(gè)地方調(diào)用,如果我們只是知道函數(shù),而不知道在哪里調(diào)用的,有時(shí)候還是不夠方便,bingo,這個(gè)也是有辦法的,可以通過(guò)address2line命令來(lái)完成,我們用第2步中編譯出來(lái)的test2來(lái)做實(shí)驗(yàn)(address2line的-f選項(xiàng)可以打出函數(shù)名, -C選項(xiàng)也可以demangle):

    1234
    wuzesheng@ubuntu:~/work/test$ addr2line -a 0x4008a7 -e test2 -f0x00000000004008a7_Z4fun1v??:0

          Oh no,怎么打出來(lái)的位置信息是亂碼呢?不急,且看我們的第3步。

  • 3. 通過(guò)下面的方式編譯運(yùn)行:
  • 1234567891011121314
    wuzesheng@ubuntu:~/work/test$ gcc test.cc -rdynamic -g -o test3wuzesheng@ubuntu:~/work/test$ ./test3stackstrace begin:./test3(_Z16print_stacktracev+0x26) [0x4008e5]./test3(_Z4fun1v+0x13) [0x4008a7]./test3(_Z4fun2v+0x9) [0x4008b2]./test3(_Z4fun3v+0x9) [0x4008bd]./test3(main+0x9) [0x40088d]/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xff) [0x7fa9558c1eff]./test3() [0x4007c9]wuzesheng@ubuntu:~/work/test$ addr2line -a 0x4008a7 -e test3 -f -C0x00000000004008a7fun1()/home/wuzesheng/work/test/test.cc:20

          看上面的結(jié)果,我們不僅得到了調(diào)用棧,而且可以得到每個(gè)函數(shù)的名字,以及被調(diào)用的位置,大功告成。在這里需要說(shuō)明一下的是,第3步比第2步多了一個(gè)-g選項(xiàng),-g選項(xiàng)的主要作用是生成調(diào)試信息,位置信息就屬于調(diào)試信息的范疇,經(jīng)常用gdb的朋友相信不會(huì)對(duì)這個(gè)選項(xiàng)感到陌生。

    本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
    打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
    猜你喜歡
    類似文章
    UC頭條:c 23中的新功能之五堆棧信息庫(kù)
    Linux性能評(píng)測(cè)工具之一:gprof篇
    用mtrace定位內(nèi)存泄漏
    巧用backtrace系列函數(shù),在不具備gdb環(huán)境的Linux系統(tǒng)上大致定位...
    test_virtualfun.cpp
    C++成員函數(shù)實(shí)現(xiàn)在類定義中與在類定義外的區(qū)別
    更多類似文章 >>
    生活服務(wù)
    分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
    綁定賬號(hào)成功
    后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
    如果VIP功能使用有故障,
    可點(diǎn)擊這里聯(lián)系客服!

    聯(lián)系客服