青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

興海北路

---男兒仗劍自橫行
<2008年3月>
2425262728291
2345678
9101112131415
16171819202122
23242526272829
303112345

統計

  • 隨筆 - 85
  • 文章 - 0
  • 評論 - 17
  • 引用 - 0

常用鏈接

留言簿(6)

隨筆分類

隨筆檔案

收藏夾

全是知識啊

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

代碼測試、調試與優化的小結
by falcon<zhangjinw@gmail.com>
2008-02-29

    代碼寫完以后往往要做測試(或驗證)、調試,可能還要優化。
    關于測試(或驗證),通常對應著兩個英文單詞verification和validation,在資料[1]中有關于這個的定義和一些深入的討論,在資料[2]中,很多人給出了自己的看法。但是我想正如資料[2]提到的:
    “The differences between verification and validation are unimportant except to the theorist; practitioners use the term V&V to refer to all ofthe activities that are aimed at making sure the software will function as required.”
    所以,無論測試(或驗證)目的都是為了讓軟件的功能能夠達到需求。測試和驗證通常會通過一些形式化(貌似可以簡單地認為有數學根據的)或者非形式化的方法去驗證程序的功能是否達到要求。
    而調試對應英文debug,debug叫“驅除害蟲”,也許一個軟件的功能達到了要求,但是可能會在測試或者是正常運行時出現異常,因此需要處理它們。
    關于優化:debug是為了保證程序的正確性,之后就需要考慮程序的執行效率,對于存儲資源受限的嵌入式系統,程序的大小也可能是優化的對象。
    很多理論性的東西是在沒有研究過,暫且不說吧。這里只是想把一些需要動手實踐的東西先且記錄和總結一下,另外很多工具在這里都有提到和羅列,包括Linux內核調試相關的方法和工具。關于更詳細更深入的內容還是建議直接看后面的參考資料為妙。

    下面的所有演示在如下環境下進行:
Quote:

$ uname -a
Linux falcon 2.6.22-14-generic #1 SMP Tue Feb 12 07:42:25 UTC 2008 i686 GNU/Linux
$ echo $SHELL
/bin/bash
$ /bin/bash --version | grep bash
GNU bash, version 3.2.25(1)-release (i486-pc-linux-gnu)
$ gcc --version | grep gcc
gcc (GCC) 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)
$ cat /proc/cpuinfo | grep "model name"
model name      : Intel(R) Pentium(R) 4 CPU 2.80GHz



1、代碼測試

代 碼測試有很多方面呢,例如運行時間、函數調用關系圖、代碼覆蓋度、性能測試(profiling)、內存訪問越界(segmentation fault)、緩沖區溢出(stack smashing合法地進行非法的內存訪問?所以很危險)、內存泄露(memory leak)等。

1.1 測試程序的運行時間 time

shell提供了內置命令time用于測試程序的執行時間,默認顯示結果包括三部分:實際花費時間(real time)、用戶空間花費時間(user time)和內核空間花費時間(kernel time)。

Quote:

$ time pstree 2>&1 >/dev/null

real    0m0.024s
user    0m0.008s
sys     0m0.004s



time 命令給出了程序本身的運行時間。這個測試原理非常簡單,就是在程序運行(通過system函數執行)前后記錄了系統時間(用times函數),然后進行求 差就可以。如果程序運行時間很短,運行一次看不到效果,可以考慮采用測試紙片厚度的方法進行測試,類似把很多紙張跌倒一起來測試紙張厚度一樣,我們可以讓 程序運行很多次。

如果程序運行時間太長,執行效率很低,那么得考慮程序內部各個部分的執行情況,從而對代碼進行可能的優化。具體可能會考慮到這兩點:

  • 對于C語言程序而言,一個比較宏觀的層次性的輪廓(profile)是函數調用圖、函數內部的條件分支構成的語句塊,然后就是具體的語句。把握好這樣一個 輪廓后,就可以有針對性地去關注程序的各個部分,包括哪些函數、哪些分支、哪些語句最值得關注(執行次數越多越值得優化,術語叫hotspots)。

  • 對于Linux下的程序而言,程序運行時涉及到的代碼會涵蓋兩個空間,即用戶空間和內核空間。由于這兩個空間涉及到地址空間的隔離,在測試或調試時,可能 涉及到兩個空間的工具。前者絕大多數是基于gcc的特定參數和系統的ptrace調用,而后者往往實現為內核的補丁,它們在原理上可能類似,但實際操作時 后者顯然會更麻煩,不過如果你不去hack內核,那么往往無須關心后者。

    1.2 函數調用關系圖 calltree

    calltree可以非常簡單方便地反應一個項目的函數調用關系圖,雖然諸如gprof這樣的工具也能做到,不過如果僅僅要得到函數調用圖,calltree應該是更好的選擇。如果要產生圖形化的輸出可以使用它的-dot參數也可以參考資料[12]。從這里可以下載到它,ftp://ftp.berlios.de/pub/calltree/calltree-2.3.tar.bz2
    關于calltree的實現原理,可以參考資料[13],關于它的詳細用法請參考資料[14]或者它的-h參數獲取幫助。

    這里是一份演示結果,
    Quote:

    $ calltree -b -np -m *.c
    main:
    |   close
    |   commitchanges
    |   |   err
    |   |   |   fprintf
    |   |   ferr
    |   |   ftruncate
    |   |   lseek
    |   |   write
    |   ferr
    |   getmemorysize
    |   modifyheaders
    |   open
    |   printf
    |   readelfheader
    |   |   err
    |   |   |   fprintf
    |   |   ferr
    |   |   read
    |   readphdrtable
    |   |   err
    |   |   |   fprintf
    |   |   ferr
    |   |   malloc
    |   |   read
    |   truncatezeros
    |   |   err
    |   |   |   fprintf
    |   |   ferr
    |   |   lseek
    |   |   read$



    這 樣一份結果對于“反向工程”應該會很有幫助,它能夠呈現一個程序的大體結構,對于閱讀和分析源代碼來說是一個非常好的選擇。雖然cscope和ctags 也能夠提供一個函數調用的“即時”(在編輯vim的過程中進行調用)視圖(view),但是calltree卻給了我們一個宏觀的視圖。

    不過這樣一個視圖只涉及到用戶空間的函數,如果想進一步給出內核空間的宏觀視圖,那么strace和KFT就可以發揮它們的作用。關于這兩個工具請參考條目[11]列出的相關資料。另外,該視圖也沒有給出庫中的函數,如果要跟蹤呢?需要ltrace工具。

    另外,我們發現,calltree僅僅給出了一個程序的函數調用視圖,而沒有告訴我們各個函數的執行次數等情況。如果要關注這些呢?我們有gprof。

    1.3 性能測試工具 gprof & kprof

    參考資料[3]詳細介紹了這個工具的用法,這里僅挑選其中一個例子來演示。gprof是一個命令行的工具,而KDE桌面環境下的kprof則給出了圖形化的輸出,這里僅演示前者。

    首先來看一段代碼(來自資料[3]),算Fibonacci數列的,


    Code:

    [Ctrl+A Select All]



    通過calltree看看這段代碼的視圖,
    Quote:

    $ calltree -b -np -m *.c
    main:
    |   fibonacci
    |   |   fibonacci ....
    |   printf



    可以看出程序主要涉及到一個fibonacci函數,這個函數遞歸調用自己。為了能夠使用gprof,需要編譯時加上-pg選項,讓gcc加入相應的調試信息以便gprof能夠產生函數執行情況的報告。
    Quote:

    $ gcc -pg -o fib fib.c
    $ ls
    fib  fib.c



    運行程序并查看執行時間,
    Quote:

    $  time ./fib
    fibonnaci(0) = 0
    fibonnaci(1) = 1
    fibonnaci(2) = 1
    fibonnaci(3) = 2
    ...
    fibonnaci(41) = 165580141
    fibonnaci(42) = 267914296

    real    1m25.746s
    user    1m9.952s
    sys     0m0.072s
    $ ls
    fib  fib.c  gmon.out


    上面僅僅選取了部分執行結果,程序運行了1分多鐘,代碼運行以后產生了一個gmon.out文件,這個文件可以用于gprof產生一個相關的性能報告。
    Quote:

    $ gprof  -b ./fib gmon.out
    Flat profile:

    Each sample counts as 0.01 seconds.
      %   cumulative   self              self     total          
     time   seconds   seconds    calls  ms/call  ms/call  name   
     96.04     14.31    14.31       43   332.80   332.80  fibonacci
      4.59     14.99     0.68                             main


                            Call graph


    granularity: each sample hit covers 2 byte(s) for 0.07% of 14.99 seconds

    index % time    self  children    called     name
                                                     <spontaneous>
    [1]    100.0    0.68   14.31                 main [1]
                   14.31    0.00      43/43          fibonacci [2]
    -----------------------------------------------
                                 2269806252             fibonacci [2]
                   14.31    0.00      43/43          main [1]
    [2]     95.4   14.31    0.00      43+2269806252 fibonacci [2]
                                 2269806252             fibonacci [2]
    -----------------------------------------------


    Index by function name

       [2] fibonacci               [1] main


    從 這份結果中可觀察到程序中每個函數的執行次數等情況,從而找出值得修改的函數。在對某些部分修改之后,可以再次比較程序運行時間,查看優化結果。另外,這 份結果還包含一個特別有用的東西,那就是程序的動態函數調用情況,即程序運行過程中實際執行過的函數,這和calltree產生的靜態調用樹有所不同,它 能夠反應程序在該次執行過程中的函數調用情況。而如果想反應程序運行的某一時刻調用過的函數,可以考慮采用gdb的backtrace命令。

    類似測試紙片厚度的方法,gprof也提供了一個統計選項,用于對程序的多次運行結果進行統計。另外,gprof有一個KDE下圖形化接口kprof,這兩部分請參考資料[3]。

    gprof雖然給出了函數級別的執行情況,但是如果想關心具體哪些條件分支被執行到,哪些語句沒有被執行,該怎么辦?

    1.4 代碼覆蓋率測試 gcov & ggcov

    如果要使用gcov,在編譯時需要加上這兩個選項 -fprofile-arcs -ftest-coverage,這里直接用之前的fib.c做演示。

    Quote:

    $ ls
    fib.c
    $ gcc -fprofile-arcs -ftest-coverage -o fib fib.c
    $ ls
    fib  fib.c  fib.gcno



    運行程序,并通過gcov分析代碼的覆蓋度
    Quote:

    $ ./fib
    $ gcov fib.c
    File 'fib.c'
    Lines executed:100.00% of 12
    fib.c:creating 'fib.c.gcov'



    12行代碼100%被執行到,再查看分支情況,
    Quote:

    $ gcov -b fib.c
    File 'fib.c'
    Lines executed:100.00% of 12
    Branches executed:100.00% of 6
    Taken at least once:100.00% of 6
    Calls executed:100.00% of 4
    fib.c:creating 'fib.c.gcov'



    發 現所有函數,條件分支和語句都被執行到,說明代碼的覆蓋率很高,不過資料[3]gprof的演示顯示代碼的覆蓋率高并不一定說明代碼的性能就好,因為那些 被覆蓋到的代碼可能能夠被優化成性能更高的代碼。那到底那些代碼值得被優化呢?執行次數最多的,另外,有些分支雖然都覆蓋到了,但是這個分支的位置可能并 不是理想的,如果一個分支的內容被執行的次數很多,那么把它作為最后一個分支的話就會浪費很多不必要的比較時間。因此,通過覆蓋率測試,可以嘗試著剔除那 些從未執行過的代碼,通過性能測試,可以找出那些值得優化的函數、分支或者是語句。

    如果使用-fprofile-arcs -ftest-coverage參數編譯完代碼,可以接著用-fbranch-probabilities參數對代碼進行編譯,這樣,編譯器就可以對根據代碼的分支測試情況進行優化。

    Quote:

    $ wc -c fib
    16333 fib
    $ ls fib.gcda  #確保fib.gcda已經生成,這個是運行fib后的結果,-fbranch-probabilities一來它
    fib.gcda
    $ gcc -fbranch-probabilities -o fib fib.c #再次運行
    $ wc -c fib
    6604 fib
    $ time ./fib
    ...
    real    0m21.686s
    user    0m18.477s
    sys     0m0.008s



    可見代碼量減少了,而且執行效率會有所提高,當然,這個代碼效率的提高可能還跟其他因素有關,比如gcc還優化了一些很平臺相關的指令。

    如 果想看看代碼中各行被執行的情況,可以直接看fib.c.gcov文件。這個文件的各列依次表示執行次數、行號和該行的源代碼。次數有三種情況,如果一直 沒有執行,那么用####表示;如果該行注釋、函數聲明等,用-表示;如果是純粹的代碼行,那么用執行次數表示。這樣我們就可以直接分析每一行的執行情 況。

    gprof也有一個圖形化接口ggprof,是基于gtk+的,適合Gnome桌面的用戶。

    現在都已經關注到代碼行 了,實際上優化代碼的前提是保證代碼的正確性,如果代碼還有很多bug,那么先要debug。不過下面的這些"bug"用普通的工具確實不太方便,雖然可 能,不過這里還是把它們歸結為測試的內容,并且這里剛好承接上gcov部分,gcov能夠測試到每一行的代碼覆蓋情況,而無論是內存訪問越界、緩沖區溢出 還是內存泄露,實際上是發生在具體的代碼行上的。

    1.5 內存訪問越界 catchesegv, libSegFault.so

    "segmentation fault"是很頭痛的一個問題,估計“糾纏”過很多人。這里僅僅演示通過catchsegv腳本測試段錯誤的方法,其他方法見資料[15]。

    catchsegv利用系統動態鏈接的PRELOAD機制(請參考man ld-linux),把庫/lib/libSegFault.so提前load到內存中,然后通過它檢查程序運行過程中的段錯誤。

    Quote:

    $ cat test.c
    #include <stdio.h>

    int main(void)
    {
            char str[10];

            sprintf(str, "%s", 111);

            printf("str = %s\n", str);
            return 0;
    }
    $ make test
    $ LD_PRELOAD=/lib/libSegFault.so ./test  #等同于catchsegv ./test
    *** Segmentation fault
    Register dump:

     EAX: 0000006f   EBX: b7eecff4   ECX: 00000003   EDX: 0000006f
     ESI: 0000006f   EDI: 0804851c   EBP: bff9a8a4   ESP: bff9a27c

     EIP: b7e1755b   EFLAGS: 00010206

     CS: 0073   DS: 007b   ES: 007b   FS: 0000   GS: 0033   SS: 007b

     Trap: 0000000e   Error: 00000004   OldMask: 00000000
     ESP/signal: bff9a27c   CR2: 0000006f

    Backtrace:
    /lib/libSegFault.so[0xb7f0604f]
    [0xffffe420]
    /lib/tls/i686/cmov/libc.so.6(vsprintf+0x8c)[0xb7e0233c]
    /lib/tls/i686/cmov/libc.so.6(sprintf+0x2e)[0xb7ded9be]
    ./test[0x804842b]
    /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0)[0xb7dbd050]
    ./test[0x8048391]
    ...



    從 結果中可以看出,代碼的sprintf有問題。經過檢查發現它把整數當字符串輸出,對于字符串的輸出,需要字符串的地址作為參數,而這里的111則剛好被 解釋成了字符串的地址,因此sprintf試圖訪問111這個地址,從而發生了非法訪問內存的情況,出現"segmentation fault"。

    1.6 緩沖區溢出 libsafe.so

    緩 沖區溢出是指棧溢出(stack smashing),通常發生在對函數內的局部變量進行賦值操作時,超出了該變量的字節長度而引起對棧內原有數據(比如eip,ebp等)的覆蓋,從而引 發內存訪問越界,甚至執行非法代碼,導致系統崩潰。關于緩沖區的詳細原理和實例分析見資料[16]。這里僅僅演示該資料中提到的一種用于檢查緩沖區溢出的 方法,它同樣采用動態鏈接的PRELOAD機制提前裝載一個名叫libsafe.so的庫,你可以從這里獲取它,http://www.sfr-fresh.com/linux/misc/libsafe-2.0-16.tgz,下載下來以后,再解壓,編譯,得到libsafe.so,

    下面,演示一個非常簡單的,但可能存在緩沖區溢出的代碼,并演示libsafe.so的用法。
    Quote:

    $ cat test.c
    $ make test
    $ LD_PRELOAD=/path/to/libsafe.so ./test ABCDEFGHIJKLMN
    ABCDEFGHIJKLMN
    *** stack smashing detected ***: ./test terminated
    Aborted (core dumped)



    資 料[6]分析到,如果不能夠對緩沖區溢出進行有效的處理,可能會存在很多潛在的危險。雖然libsafe.so采用函數替換的方法能夠進行對這類 stack smashing進行一定的保護,但是無法根本解決問題,alert7大蝦在資料[17]中提出了突破它的辦法,資料[18]提出了另外一種保護機制。

    1.7 內存泄露 Memwatch, Valgrind, mtrace

    堆 棧通常會被弄在一起叫,不過這兩個名詞卻是指進程的內存映像中的兩個不同的部分,棧(stack)用于函數的參數傳遞、局部變量的存儲等,是系統自動分配 和回收的;而堆(heap)則是用戶通過malloc等方式申請而且需要用戶自己通過free釋放的,如果申請的內存沒有釋放,那么將導致內存泄露,進而 可能導致堆的空間被用盡;而如果已經釋放的內存再次被釋放(double-free)則也會出現非法操作。(如果要真正理解堆和棧的區別,需要理解進程的 內存映像,請參考資料[22])

    這里演示通過Memwatch來檢測程序中可能存在內存泄露,你可以從這里下載到這個工具,http://www.linkdata.se/sourcecode.html
    使用這個工具的方式很簡單,只要把它鏈接(ld)到你的可執行文件中去,并在編譯時加上兩個宏開關-DMEMWATCH -DMW_STDIO。這里演示一個簡單的例子。

    Quote:

    $ cat test.c
    #include <stdlib.h>
    #include <stdio.h>
    #include "memwatch.h"

    int main(void)
    {
      char *ptr1;
      char *ptr2;

      ptr1 = malloc(512);
      ptr2 = malloc(512);

      ptr2 = ptr1;
      free(ptr2);
      free(ptr1);
    }
    $ gcc -DMEMWATCH -DMW_STDIO test.c memwatch.c -o test
    $ cat memwatch.log
    ============= MEMWATCH 2.71 Copyright (C) 1992-1999 Johan Lindh =============

    Started at Sat Mar  1 07:34:33 2008

    Modes: __STDC__ 32-bit mwDWORD==(unsigned long)
    mwROUNDALLOC==4 sizeof(mwData)==32 mwDataSize==32

    double-free: <4> test.c(15), 0x80517e4 was freed from test.c(14)

    Stopped at Sat Mar  1 07:34:33 2008

    unfreed: <2> test.c(11), 512 bytes at 0x8051a14         {FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE ................}

    Memory usage statistics (global):
     N)umber of allocations made: 2
     L)argest memory usage      : 1024
     T)otal of all alloc() calls: 1024
     U)nfreed bytes totals      : 512



    通過測試,可以看到有一個512字節的空間沒有被釋放,而另外512字節空間卻被連續釋放兩次(double-free)。valgrind和mtrace也可以做類似的工作,請參考資料[4]和mtrace的手冊。

    2、代碼調試

    調試的方法很多,調試往往要跟蹤代碼的運行狀態,printf是最基本的辦法,然后呢?靜態調試方法有哪些,非交互的呢?非實時的有哪些?實時的呢?用于調試內核的方法有哪些?有哪些可以用來調試匯編代碼呢?

    2.1 靜態調試:printf + gcc -D(打印程序中的變量)

    利 用gcc的宏定義開關(-D)和printf函數可以跟蹤程序中某個位置的狀態,這個狀態包括當前一些變量和寄存器的值。調試時需要用-D開關進行編譯, 在正式發布程序時則可把-D開關去掉。這樣做比單純用printf方便很多,它可以避免清理調試代碼以及由此帶來的誤刪除代碼等問題。

    Quote:

    $ cat test.c
    #include <stdio.h>
    #include <unistd.h>

    int main(void)
    {
            int i = 0;

    #ifdef DEBUG
            printf("i = %d\n", i);

            int t;
            __asm__ __volatile__ ("movl %%ebp, %0;":"=r"(t)::"%ebp");
            printf("ebp = 0x%x\n", t);
    #endif

            _exit(0);
    }
    $ gcc -DDEBUG -g -o test test.c
    $ ./test
    i = 0
    ebp = 0xbfb56d98



    上面演示了如何跟蹤普通變量和寄存器變量的辦法。跟蹤寄存器變量采用了內聯匯編,關于Linux下的匯編語言開發請參考資料[19]。

    不 過,這種方式不夠靈活,我們無法“即時”獲取程序的執行狀態,而gdb等交互式調試工具不僅解決了這樣的問題,而且通過把調試器拆分成調試服務器和調試客 戶端適應了嵌入式系統的調試,另外,通過預先設置斷點以及斷點處需要收集的程序狀態信息解決了交互式調試不適應實時調試的問題。

    2.2 交互式的調試(動態調試):gdb(支持本地和遠程)/ald(匯編指令級別的調試)

    2.2.1 嵌入式系統調試方法 gdbserver/gdb

    估計大家已經非常熟悉GDB(Gnu DeBugger)了,所以這里并不介紹常規的gdb用法,而是介紹它的服務器/客戶(gdbserver/gdb)調試方式。這種方式非常適合嵌入式系統的調試,為什么呢?先來看看這個:

    Quote:

    $ wc -c /usr/bin/gdbserver
    56000 /usr/bin/gdbserver
    $ which gdb
    /usr/bin/gdb
    $ wc -c /usr/bin/gdb
    2557324 /usr/bin/gdb
    $ echo "(2557324-56000)/2557324"  | bc -l
    .97810210986171482377


    gdb 比gdbserver大了將近97%,如果把整個gdb搬到存儲空間受限的嵌入式系統中是很不合適的,不過僅僅5K左右的gdbserver即使在只有 8M Flash卡的嵌入式系統中也都足夠了。所以在嵌入式開發中,我們通常先在本地主機上交叉編譯好gdbserver/gdb。

    如果是初次使用這種方法,可能會遇到麻煩,而麻煩通常發生在交叉編譯gdb和gdbserver時。在編譯gdbserver/gdb前,需要配置(./configure)兩個重要的選項:
  • --host,指定gdb/gdbserver本身的運行平臺,
  • --target,指定gdb/gdbserver調試的代碼所運行的平臺,
    關 于運行平臺,通過$MACHTYPE環境變量就可獲得,對于gdbserver,因為要把它復制到嵌入式目標系統上,并且用它來調試目標平臺上的代碼,因 此需要把--host和--target都設置成目標平臺;而gdb因為還是運行在本地主機上,但是需要用它調試目標系統上的代碼,所以需要把-- target設置成目標平臺。

    編譯完以后就是調試,調試時需要把程序交叉編譯好,并把二進制文件復制一份到目標系統上,并在本地需要保留一份源代碼文件。調試過程大體如下,首先在目標系統上啟動調試服務器:

    Quote:

    $ gdbserver :port /path/to/binary_file
    ...



    然后在本地主機上啟動gdb客戶端鏈接到gdb調試服務器,(gdbserver_ipaddress是目標系統的IP地址,如果目標系統不支持網絡,那么可以采用串口的方式,具體看手冊
    Quote:

    $ gdb
    ...
    (gdb) target remote gdbserver_ipaddress:2345
    ...



    其他調試過程和普通的gdb調試過程類似。

    2.2.2 匯編代碼的調試 ald

    用gdb調試匯編代碼貌似會比較麻煩,不過有人正是因為這個原因而開發了一個專門的匯編代碼調試器,名字就叫做assembly language debugger,簡稱ald,你可以從這里下載到,http://ald.sourceforge.net/

    下載以后,解壓編譯后,我們來調試一個程序看看。

    這里是一段非常簡短的匯編代碼,摘自參考資料[20]



    Code:

    [Ctrl+A Select All]



    演示一下,

    Quote:

    //匯編、鏈接、運行
    $ as -o test.o test.s
    $ ld -o test test.o
    $ ./test "Hello World"
    Hello World
    //查看程序的入口地址
    $ readelf -h test | grep Entry
      Entry point address:               0x8048054
    //調試
    $ ald test
    ald> display
    Address 0x8048054 added to step display list
    ald> n
    eax = 0x00000000 ebx = 0x00000000 ecx = 0x00000001 edx = 0x00000000
    esp = 0xBFBFDEB4 ebp = 0x00000000 esi = 0x00000000 edi = 0x00000000
    ds  = 0x007B es  = 0x007B fs  = 0x0000 gs  = 0x0000
    ss  = 0x007B cs  = 0x0073 eip = 0x08048055 eflags = 0x00200292

    Flags: AF SF IF ID

    Dumping 64 bytes of memory starting at 0x08048054 in hex
    08048054:  59 59 59 C6 41 0C 0A 31 D2 B2 0D 31 C0 B0 04 31    YYY.A..1...1...1
    08048064:  DB CD 80 31 C0 40 CD 80 00 2E 73 79 6D 74 61 62    ...1.@....symtab
    08048074:  00 2E 73 74 72 74 61 62 00 2E 73 68 73 74 72 74    ..strtab..shstrt
    08048084:  61 62 00 2E 74 65 78 74 00 00 00 00 00 00 00 00    ab..text........

    08048055                      59                   pop ecx



    可見ald在啟動時就已經運行了被它調試的test程序,并且進入了程序的入口0x8048054,緊接著單步執行時,就執行了程序的第一條指令popl ecx。

    ald的命令很少,而且跟gdb很類似,比如
  • 這個幾個命令用法和名字都類似 help,next,continue,set args,break,file,quit,disassemble,enable,disable等
  • 名字不太一樣,功能對等的,examine對x, enter 對 set variable {int}地址=數據

    需 要提到的是:linux下的調試器包括上面的gdb和ald,以及strace等都用到了linux系統提供的ptrace()系統調用,這個調用為用戶 訪問內存映像提供了便利,如果想自己寫一個調試器或者想hack一下gdb和ald,那么好好閱讀資料[10]和man ptrace吧。

    2.3 實時調試:gdb tracepoint

    對 于程序狀態受時間影響的程序,用上述普通的設置斷點的交互式調試方法并不合適,因為這種方式將由于交互時產生的通信延遲和用戶輸入命令的時延而完全改變程 序的行為。所以gdb提出了一種方法以便預先設置斷點以及在斷點處需要獲取的程序狀態,從而讓調試器自動執行斷點處的動作,獲取程序的狀態,從而避免在斷 點處出現人機交互產生時延改變程序的行為。

    這種方法叫tracepoints(對應breakpoint),它在gdb的user manual(見資料[21])里頭有詳細的說明,不過在gdb的官方發行版中至今都沒有對它的實現。盡管如此,我們還是可以使用它,因為有其他組織做了 相關的工作,并以補丁的方式發布它。這個補丁你可以從這里獲取ftp://dslab.lzu.edu.cn/pub/gdb_tracepoints

    獲 取這個補丁以后,要做的就是把它patch到對應的gdb版本中,然后就是編譯。因為tracepoints只定義在調試服務器和調試客戶端這種方式中, 因此在這個實現中也是這樣,如果想用它,你同樣需要編譯gdbserver和gdb,并類似嵌入式系統中的調試方法一樣調試它。

    編譯好以后通過ftp://dslab.lzu.edu.cn/pub/gdb_tracepoints/paper/tp.pdf和資料[21]就可以使用它。

    2.4 調試內核

    雖然這里并不會演示如何去hack內核,但是相關的工具還是需要簡單提到的,資料[11]列出了絕大部分用于內核調試的工具,這些對你hack內核應該會有幫助的。

    3、代碼優化

    除了資料[21]中的實踐之外,我想我“應該”沒有做過其他的項目優化工作吧,所以很遺憾,這里無法進行討論了,不過我還是找了很多相關資料的,就讓大家一起分享吧,這些資料都列在條目
  • 里。

    實際上呢?“代碼測試”部分介紹的很多工具是為代碼優化服務的,更多具體的細節請參考后面的資料,自己做實驗吧。有任何相關的感興趣的話題歡迎給我郵件zhangjinw@gmail.com。

    參考資料:

    [1] VERIFICATION AND VALIDATION
    http://satc.gsfc.nasa.gov/assure/agbsec5.txt
    [2] difference between verification and Validation
    http://www.faqs.org/qa/qa-9060.html
    [3] Coverage Measurement and Profiling(覆蓋度測量和性能測試,Gcov and Gprof)
    http://www.linuxjournal.com/article/6758
    [4] Valgrind Usage
    A. Valgrind HOWTO
    http://www.faqs.org/docs/Linux-HOWTO/Valgrind-HOWTO.html
    B. Using Valgrind to Find Memory Leaks and Invalid Memory Use
    http://www.cprogramming.com/debugging/valgrind.html
    [5] MEMWATCH
    http://www.linkdata.se/sourcecode.html
    [6] Mastering Linux debugging techniques
    http://www.ibm.com/developerworks/linux/library/l-debug/
    [7] Software Performance Analysis
    http://arxiv.org/pdf/cs.PF/0507073.pdf
    [8] Runtime debugging in embedded systems
    http://dslab.lzu.edu.cn/docs/publications/runtime_debug.pdf
    [9] Tools Provided by System
    ltrace,mtrace,strace
    [10] Write your own debugger with the support ptrace()
    A.
    Process Tracing Using Ptrace
    http://linuxgazette.net/issue81/sandeep.html
    http://linuxgazette.net/issue83/sandeep.html
    B. Playing with ptrace
    http://www.linuxjournal.com/article/6100
    http://www.linuxjournal.com/node/6210/print
    http://www.ecos.sourceware.org/ml/libc-hacker/1998-05/msg00277.html
    [11] Kernel Debugging Relative Tools
    A. KGDB
    http://dslab.lzu.edu.cn/docs/publications/kernel_gdb.pdf
    B. GCOV
    http://linuxdevices.com/files/article062/der_herr_gcov.pdf
    C. KFI & KFT
    http://dslab.lzu.edu.cn/docs/publications/kfi.pdf
    D. UML(User Mode Linux)
    http://dslab.lzu.edu.cn/docs/publications/uml.pdf
    E. GDB Tracepoint
    http://dslab.lzu.edu.cn/docs/publications/tp.pdf
    F. Tools Collections
    http://dslab.lzu.edu.cn/docs/publications/tools.pdf
    G. Linux系統內核的調試
    http://www.ibm.com/developerworks/cn/linux/l-kdb/
    H. 嵌入式Linux內核調試技術
    http://www.eepw.com.cn/article/73300.htm
    [12] 用Graphviz進行可視化操作──繪制函數調用關系圖
    http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1425.html
    [13] 用 Graphviz 可視化函數調用
    http://www.ibm.com/developerworks/cn/linux/l-graphvis/
    [14]
    介紹一個linux下生成C代碼調用樹的好工具calltree
    http://www.linuxsir.org/bbs/printthread.php?t=246389
    [15] 可惡的"Segmentation faults"之初級總結篇
    http://oss.lzu.edu.cn/blog/article.php?tid_700.html
    [16]
    Linux下緩沖區溢出攻擊的原理及對策
    http://www.ibm.com/developerworks/cn/linux/l-overflow/index.html
    [17] 繞過libsafe的保護--覆蓋_dl_lookup_versioned_symbol技術
    http://www.xfocus.net/articles/200208/423.html
    [18] 介紹Propolice怎樣保護stack-smashing的攻擊
    http://www.xfocus.net/articles/200103/78.html
    [19] Linux 匯編語言開發指南
    http://www.ibm.com/developerworks/cn/linux/l-assembly/index.html
    [20] 為你的可執行文件“減肥”
    http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1547.html
    [21] GDB Tracepoints
    http://sourceware.org/gdb/current/onlinedocs/gdb_11.html#SEC84
    [22] C語言程序緩沖區注入分析(第一部分:進程的內存映像)
    http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1539.html
  • Code Optimize Relatie
    A. Optimizing C Code
    http://www.jukie.net/~bart/slides/c-opt/c-opt.ps
    B. Performance programming for scientific computing
    http://www.research.ibm.com/perfprog/course/course.html
    C. Performance Programming
    http://www-cse.ucsd.edu/users/carter/perfprog.html
    D. Linux Profiling and Optimization
    http://www.cs.princeton.edu/picasso/mats/mats_S07/Lucifredi_Lecture_Feb07.pdf
    E. High-level code optimization
    http://web.abo.fi/~mats/codeopt2007/handouts/High-level-opt.pdf
    F. Code Optimization
    http://library.simugraph.com/articles/opti/optimizing.html
  • posted on 2008-03-14 15:32 隨意門 閱讀(1331) 評論(0)  編輯 收藏 引用


    只有注冊用戶登錄后才能發表評論。
    網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


    青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            国产日产亚洲精品系列| 国语精品一区| 亚洲黄色天堂| 久久成人综合网| 亚洲综合电影| 一本色道久久精品| 亚洲一区二区三区免费视频| 亚洲一区二区精品| 亚洲午夜av在线| 香蕉视频成人在线观看| 久久久久久网址| 欧美顶级艳妇交换群宴| 欧美二区在线播放| 亚洲精品中文字| 亚洲一区二区三区久久| 亚洲婷婷免费| 久久久噜噜噜久久人人看| 久久九九热免费视频| 麻豆精品视频在线| 亚洲黄一区二区三区| 99热这里只有精品8| 亚洲小说欧美另类婷婷| 欧美一级电影久久| 欧美国产另类| 国产精品中文字幕欧美| 日韩一级大片在线| 亚洲小视频在线观看| 每日更新成人在线视频| 久久人91精品久久久久久不卡| 美国十次成人| 91久久精品www人人做人人爽| 另类欧美日韩国产在线| 欧美岛国在线观看| 国产精品久久久久9999| 在线观看久久av| 亚洲视频第一页| 久久亚洲国产成人| 日韩亚洲国产精品| 欧美在线www| 欧美日韩成人网| 在线观看三级视频欧美| 99这里只有久久精品视频| 国产精品伦理| 亚洲国产免费| 亚洲永久免费视频| 久久全国免费视频| 亚洲最新视频在线| 欧美xart系列高清| 国产日韩在线亚洲字幕中文| 日韩视频在线观看| 亚洲国产成人在线| 欧美在线影院| 一区二区三区成人| 欧美激情精品久久久久久蜜臀| 国产欧美日韩综合| 亚洲精品久久久一区二区三区| 国产欧美va欧美va香蕉在| 亚洲精品免费在线| 欧美成人精精品一区二区频| 亚洲欧美激情在线视频| 国产精品xvideos88| 99精品国产高清一区二区| 免费观看国产成人| 午夜精品三级视频福利| 欧美午夜大胆人体| 日韩午夜免费| 亚洲国产精品一区二区第一页| 久久av在线| 欧美色欧美亚洲高清在线视频| 亚洲乱码精品一二三四区日韩在线 | 99热精品在线| 欧美激情精品久久久六区热门| 在线成人激情视频| 久久综合综合久久综合| 久久久久久久91| 国内精品久久久久久| 久久久久九九九| 欧美亚洲日本网站| 国产人久久人人人人爽| 久久精品视频在线观看| 欧美一级理论片| 影音先锋中文字幕一区| 欧美另类极品videosbest最新版本| 一区二区视频在线观看| 欧美高清视频www夜色资源网| 久久久久久久久久久久久9999| 欧美高清视频在线| 一本色道久久精品| 欧美一区二区视频在线| 亚洲精品三级| 亚洲综合色视频| 亚洲视频一起| 99re热精品| 亚洲视频狠狠| 国产日韩精品久久久| 久久激情视频免费观看| 久久亚洲一区二区| 一区二区三区精品在线| 亚洲一区在线播放| 在线观看亚洲精品| 亚洲精品影院在线观看| 国产欧美日韩专区发布| 欧美bbbxxxxx| 国产精品盗摄一区二区三区| 久久国内精品视频| 欧美高潮视频| 欧美一区亚洲二区| 美日韩精品免费| 亚洲一区不卡| 久久中文字幕一区| 亚洲欧美日韩国产中文| 久久久噜噜噜久噜久久 | 亚洲国产精品传媒在线观看| 亚洲日韩欧美视频| 国产麻豆日韩| 亚洲精品美女久久久久| 黄色成人片子| 亚洲视频你懂的| 亚洲精品美女在线观看| 小黄鸭精品aⅴ导航网站入口| 日韩视频二区| 久久免费观看视频| 欧美怡红院视频| 欧美日韩一级片在线观看| 久久漫画官网| 国产精品一区毛片| 日韩一区二区免费看| 亚洲国产99| 久久av在线看| 午夜精品免费在线| 欧美日韩一区二区三区高清| 欧美91精品| 韩日成人av| 午夜欧美大片免费观看| 亚洲男人的天堂在线观看| 欧美日本国产在线| 亚洲国产综合视频在线观看| 精品成人乱色一区二区| 欧美激情一区二区三区成人| 激情校园亚洲| 亚洲成人资源网| 国产精品超碰97尤物18| 亚洲欧美日韩综合国产aⅴ| 麻豆精品网站| 欧美va亚洲va日韩∨a综合色| 香蕉成人伊视频在线观看 | 一区在线免费| 欧美日本韩国一区二区三区| 午夜免费在线观看精品视频| 999在线观看精品免费不卡网站| 欧美午夜三级| 日韩午夜精品| 亚洲特黄一级片| 欧美日韩国产在线一区| 亚洲激情在线播放| 日韩网站在线观看| 欧美日韩三级视频| 亚洲网站视频| 欧美在线观看视频一区二区| 久久亚洲风情| 欧美激情一区二区三区| 一区二区激情| 国产精品日韩一区二区| 性色av一区二区三区| 久久一区中文字幕| 亚洲国产日韩一区| 欧美精品一区二区精品网| 一本色道久久综合狠狠躁篇的优点| 亚洲一级二级| 国产一区二区三区黄视频| 久久手机免费观看| 亚洲日韩欧美视频一区| 亚洲一区精品视频| 国产综合自拍| 欧美成人高清| 亚洲一区自拍| 欧美阿v一级看视频| 99国内精品| 国产日韩欧美亚洲| 欧美高清hd18日本| 欧美一级精品大片| 亚洲精品日韩在线| 久久久精品国产一区二区三区 | 国产精品乱码人人做人人爱| 久久亚洲综合网| 亚洲一级在线观看| 亚洲国产日韩精品| 久久久91精品国产一区二区三区| 亚洲乱码国产乱码精品精天堂| 国产日韩欧美三区| 国产精品国产a级| 欧美成人免费全部| 久久精品人人做人人爽| 亚洲影院在线| 99精品欧美一区二区三区| 欧美成人中文字幕在线| 久久久91精品国产| 欧美在线视频观看免费网站| 亚洲婷婷综合色高清在线| 亚洲精品一线二线三线无人区|