<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>
  • 網站首頁 > 物聯資訊 > 技術分享

    在C/C++程序里打印調用棧信息

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    我們知道,GDB的backtrace命令可以查看堆棧信息。但很多時候,GDB根本用不上。比如說,在線上環境中可能沒有GDB,即使有,也不太可能讓我們直接在上面調試。如果能讓程序自己輸出調用棧,那是最好不過了。本文介紹和調用椎棧相關的幾個函數。

     

    NAME
           backtrace, backtrace_symbols, backtrace_symbols_fd - support for application self-debugging

    SYNOPSIS
           #include <execinfo.h>

           int backtrace(void **buffer, int size);

           char **backtrace_symbols(void *const *buffer, int size);

           void backtrace_symbols_fd(void *const *buffer, int size, int fd);

     

    以上內容源自這幾個函數的man手冊。

     

    先簡單介紹一下這幾個函數的功能:

    l backtrace:獲取當前的調用棧信息,結果存儲在buffer中,返回值為棧的深度,參數size限制棧的最大深度,即最大取size步的棧信息。

    l backtrace_symbols:把backtrace獲取的棧信息轉化為字符串,以字符指針數組的形式返回,參數size限定轉換的深度,一般用backtrace調用的返回值。

    l backtrace_symbols_fd:它的功能和backtrace_symbols差不多,只不過它不把轉換結果返回給調用方,而是寫入fd指定的文件描述符。

     

     

    Man手冊里,給出了一個簡單的實例,我們看一下:

    #include<execinfo.h>

    #include<stdio.h>

    #include<stdlib.h>

    #include<unistd.h>

    void

    myfunc3(void)

    {

       int j, nptrs;

       #define SIZE 100

       void *buffer[100];

       char **strings;

       nptrs = backtrace(buffer, SIZE);

       printf("backtrace() returned %d addresses\n", nptrs);

       /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)

        *  would produce similar output to the following: */

     

       strings = backtrace_symbols(buffer, nptrs);

       if (strings == NULL) {

           perror("backtrace_symbols");

           exit(EXIT_FAILURE);

       }

     

       for (j = 0; j < nptrs; j++)

           printf("%s\n", strings[j]);

       free(strings);

    }

     

    staticvoid  /* "static" means don't export the symbol... */

    myfunc2(void)

    {

       myfunc3();

    }

     

    void

    myfunc(int ncalls)

    {

       if (ncalls > 1)

           myfunc(ncalls - 1);

       else

           myfunc2();

    }

     

    int

    main(int argc,char *argv[])

    {

       if (argc != 2) {

           fprintf(stderr,"%s num-calls\n", argv[0]);

           exit(EXIT_FAILURE);

       }

       myfunc(atoi(argv[1]));

       exit(EXIT_SUCCESS);

    }

     

    編譯:

    # cc prog.c -o prog

     

    運行:

    # ./prog 0
    backtrace() returned 6 addresses
    ./prog() [0x80485a3]
    ./prog() [0x8048630]
    ./prog() [0x8048653]
    ./prog() [0x80486a7]

     

    這樣,是輸出了調用棧,不過只是以十六進制輸出函數地址而已,可讀性很差。仔細看下man手冊,原來很簡單,編譯時加上個參數:

     

    重新編譯:

    # cc -rdynamic  prog.c -o prog

    通過gcc手冊,我們可以也解下參數的說明:

    -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.

     

    再執行:

    # ./prog 0

    backtrace() returned 6 addresses
    ./prog(myfunc3+0x1f) [0x8048763]
    ./prog() [0x80487f0]
    ./prog(myfunc+0x21) [0x8048813]
    ./prog(main+0x52) [0x8048867]
    /lib/libc.so.6(__libc_start_main+0xe6) [0xaf9cc6]
    ./prog() [0x80486b1]

     

    這回,可以看到函數名了。是不是很酷呢?把它封裝到你的調試代碼中吧。

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全