久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

如何快速定位Linux Panic出錯(cuò)的代碼行 | 泰曉科技

 寫意人生 2015-09-16

如何快速定位Linux Panic出錯(cuò)的代碼行

  • 問題描述

    內(nèi)核調(diào)試中最常見的一個(gè)問題是:內(nèi)核Panic后,,如何快速定位到出錯(cuò)的代碼行,?

    就是這樣一個(gè)常見的問題,面試過的大部分同學(xué)都未能很好地回答,,這里希望能夠做很徹底地解答,。

  • 問題分析

    內(nèi)核Panic時(shí),,一般會(huì)打印回調(diào),并打印出當(dāng)前出錯(cuò)的地址:

    kernel/panic.c:panic():

    1
    2
    3
    4
    5
    6
    7
    #ifdef CONFIG_DEBUG_BUGVERBOSE
        /*
         * Avoid nested stack-dumping if a panic occurs during oops processing
         */
        if (!test_taint(TAINT_DIE) && oops_in_progress <= 1)
            dump_stack();
    #endif

    dump_stack()調(diào)用關(guān)系如下:

    1
    dump_stack() --> __dump_stack() --> show_stack() --> dump_backtrace()

    dump_backtrace()會(huì)打印整個(gè)回調(diào),,例如:

    1
    2
    3
    4
    [<001360ac>] (unwind_backtrace+0x0/0xf8) from [<00147b7c>] (warn_slowpath_common+0x50/0x60)
    [<00147b7c>] (warn_slowpath_common+0x50/0x60) from [<00147c40>] (warn_slowpath_null+0x1c/0x24)
    [<00147c40>] (warn_slowpath_null+0x1c/0x24) from [<0014de44>] (local_bh_enable_ip+0xa0/0xac)
    [<0014de44>] (local_bh_enable_ip+0xa0/0xac) from [<0019594c>] (bdi_register+0xec/0x150)

    通常,,上面的回調(diào)會(huì)打印出出錯(cuò)的地址。

  • 解決方案

    通過分析,,要快速定位出錯(cuò)的代碼行,,其實(shí)就是快速查找到出錯(cuò)的地址對(duì)應(yīng)的代碼?

    • 情況一

      在代碼編譯連接時(shí),,每個(gè)函數(shù)都有起始地址和長(zhǎng)度,,這個(gè)地址是程序運(yùn)行時(shí)的地址,而函數(shù)內(nèi)部,,每條指令相對(duì)于函數(shù)開始地址會(huì)有偏移,。那么有了地址以后,就可以定位到該地址落在哪個(gè)函數(shù)的區(qū)間內(nèi),,然后找到該函數(shù),,進(jìn)而通過計(jì)算偏移,定位到代碼行,。

    • 情況二

      但是,,如果拿到的日志文件所在的系統(tǒng)版本跟當(dāng)前的代碼版本不一致,那么編譯后的地址就會(huì)有差異,。那么簡(jiǎn)單地直接通過地址就可能找不到原來的位置,,這個(gè)就可能需要回調(diào)里頭的函數(shù)名信息。先通過函數(shù)名定位到所在函數(shù),,然后通過偏移定位到代碼行,。

    相應(yīng)的工具有addr2line, gdb, objdump等,這幾個(gè)工具在How to read a Linux kernel panic?都有介紹,,我們將針對(duì)上面的實(shí)例做更具體的分析,。

    需要提到的是,代碼的實(shí)際運(yùn)行是不需要符號(hào)的,,只需要地址就行,。所以如果要調(diào)試代碼,,必須確保調(diào)試符號(hào)已經(jīng)編譯到內(nèi)核中,,不然,回調(diào)里頭打印的是一堆地址,,根本看不到符號(hào),,那么對(duì)于上面提到的情況二而言,將無法準(zhǔn)確定位問題,。

    如果要獲取到足夠多的調(diào)試信息,,請(qǐng)根據(jù)需要打開如下選項(xiàng):

    1
    2
    3
    4
    CONFIG_KALLSYMS=y
    CONFIG_KALLSYMS_ALL=y
    CONFIG_DEBUG_BUGVERBOSE=y
    CONFIG_STACKTRACE=y

    下面分別介紹各種用法。

    • addr2line

      如果出錯(cuò)的內(nèi)核跟當(dāng)前需要調(diào)試的內(nèi)核一致,而且編譯器等都一致,,那么可以通過addr2line直接獲取到出錯(cuò)的代碼行,,假設(shè)出錯(cuò)地址為0019594c:

      1
      2
      $ addr2line -e vmlinux_with_debug_info 0x0019594c
      mm/backing-dev.c:335

      然后用vim就可以直接找到代碼出錯(cuò)的位置:

      1
      $ vim mm/backing-dev.c +335

      如果是情況二,可以先通過nm獲取到當(dāng)前的vmlinux中bdi_register函數(shù)的真實(shí)位置,。

      1
      2
      $ nm vmlinux | grep bdi_register
      0x00195860 T bdi_register

      然后,,加上0xec的偏移,即可算出真實(shí)地址:

      1
      2
      $ echo "obase=16;ibase=10;$((0x00195860+0xec))" | bc -l
      19594C
    • gdb

      這個(gè)也適用情況二,,因?yàn)榭梢灾苯佑?符號(hào)+偏移 的方式,,因此,即使其他地方有改動(dòng),,這個(gè)相對(duì)的位置是不變的,。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      $ gdb vmlinux_with_debug_info
      $ list *(bdi_register+0xec)
      0x0019594c is in bdi_register (/path/to/mm/backing-dev.c:335).
      330     bdi->dev = dev;
      331
      332     bdi_debug_register(bdi, dev_name(dev));
      333     set_bit(BDI_registered, &bdi->state);
      334
      335     spin_lock_bh(&bdi_lock);
      336     list_add_tail_rcu(&bdi->bdi_list, &bdi_list);
      337     spin_unlock_bh(&bdi_lock);
      338
      339     trace_writeback_bdi_register(bdi);

      如果是情況一,則可以直接用地址:list *0x0019594c,。

    • objdump

      如果是情況一,,直接用地址dump出來。咱們回頭看一下Backtrace信息:bdi_register+0xec/0x150,,這里的0xec是偏移,,而0×150是該函數(shù)的大小。用objdump默認(rèn)可以獲取整個(gè)vmlinux的代碼,,但是咱們其實(shí)只獲取一部分,,這個(gè)可以通過--start-address--stop-address來指定。另外-d可以匯編代碼,,-S則可以并入源代碼,。

      1
      $ objdump -dS vmlinux_with_debug_info --start-address=0x0019594c --end-address=$((0x0019594c+0x150))

      如果是情況二,也可以跟addr2line一樣先算出真實(shí)地址,,然后再通過上面的方法導(dǎo)出,。

    總地來看,gdb還是來得簡(jiǎn)單方便,,無論是情況下和情況二都適用,,而且很快捷地就顯示出了出錯(cuò)的代碼位置,并且能夠顯示代碼的內(nèi)容,。

    對(duì)于用戶態(tài)來說,,分析的方式類似。如果要在應(yīng)用中獲取Backtrace,,可以參考Generating backtraces,。其例子如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <execinfo.h>
    #define BACKTRACE_SIZ 64
    void show_backtrace (void)
    {
            void    *array[BACKTRACE_SIZ];
            size_t   size, i;
            char   **strings;
            size = backtrace(array, BACKTRACE_SIZ);
            strings = backtrace_symbols(array, size);
            for (i = 0; i < size; i++) {
                printf("%p : %s\n", array[i], strings[i]);
            }
            free(strings);  // malloced by backtrace_symbols
    }

    編譯代碼時(shí)需要加上:-funwind-tables-g-rdynamic,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多