程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 調試技巧總結,調試技巧

調試技巧總結,調試技巧

編輯:關於C語言

調試技巧總結,調試技巧


  以下內容總結自debug hacks一書的高手們的調試技術一章

  1.strace的使用技巧

    strace name,以這樣的方式運行程序,可以查看到程序運行時的系統調用,僅僅是系統調用。可以看到系統調用失敗時的傳參,或者卡在哪個函數位置等等。

    -i選項可以看到每個系統調用的地址,那樣在使用gdb調試時可以加斷點。

    -p選項可以attach上已經正在運行的程序

    -o可以指定輸出文件

    -t和-tt可以指定系統調用時間,分別以秒和毫秒為單位。

  2.objdump的使用技巧

    objdump反匯編之後的文件往往很難看出來對應於c程序中的哪一行代碼,這個時候可以指定-S和-l選項分別顯示出源文件中的代碼和行號,程序需要包含有調試信息,最好是沒有優化選項的文件,但不一定完全對應,可以作為參考。

  3.valgrind的使用技巧

    valgrind可以對緩存,堆進行評測,檢測POSIX線程沖突等。

    最常用的內存檢測,--tool=memcheck這個工具是valgrind的默認工具,可以不指定。

    可以檢測的內容有,內存洩露,非法內存訪問,讀取未初始化區域,訪問已釋放區域,內存雙重釋放,非法棧操作等等。但是valgrind對於棧上的空間檢測不是很好。

  4.kprobe的使用

    這個屬於內核調試技術,可以在不重新編譯內核的基礎上,在任何一個函數內加打印,或者做其他任何處理,當然需要有內核源碼,做一個合適的操作。

    比較好的一點是可以顯示棧跟蹤。這在調試中屬於很好的技術。

  5.jprobe的使用

    與kprobe相同,可以檢測任何一個內核函數的使用情況,但是jprobe的優點在於偵測函數的參數和被偵測函數的參數一樣,可以很方便的打印出傳參,而不像kprobe需要通過堆棧或者寄存器推理。

    其實我覺得以上兩個工具對應於gdb就是斷點。

  6.kprobe的強大之處

    kproble強大他可以插入內核任意位置,而不像jprobe只能插入在函數的開頭處,包括他還在可以插在某條指令執行後還是某條指令執行前。

  7.kprobe替換內核函數

    kprobe可以替換內核中的某個函數,這樣就可以在內核不重新編譯的情況下,調試某個函數的情況。

  8.KAHO替換應用程序函數

    類似於上一個kprobe的功能,這樣可以省的再次編譯大型的應用程序。

  9.systemtap的使用

    這個工具是利用kprobe實現的一個工具,但是他是類似於腳本語言的方式來使用的,更加方便。功能有,查看堆棧,內部數據,等等。在應用程序的調試中就是gdb工具。

  10./proc/meminfo中的寶藏

    這個可以用作內存檢測,他與valgrind相比,valgrind必須在程序運行結束時才給出測試結果,但這個可以直接實時看到。

  11./proc/<pid>/mem快速讀取進程的內容

    和gdb或者ptrace一樣,是查看內存的功能,但是速度上要快。

  12.oom killer

    當內存不足時,系統會對每個應用進程進行評分,評分最高者被關閉。

  13.錯誤注入

    一般來講,malloc都會是成功的,但是這樣就很難檢測一些如果分配失敗時導致的錯誤。那麼這個功能就是提高分配失敗的概率,或者說指定分配失敗。

    需要連接一個failmalloc的庫。方便測試失敗情況。

    這個的使用非常方便,首先到failmalloc的官網下載他的代碼,並編譯和安裝他,

    在每次運行時指定env的LD_PRELOAD參數為庫所在目錄及庫名稱,

    另外一個這個庫支持指定選項,有四個

    FAILMALLOC_PROBABILITY

      specifies how often it should fail between 0.0 and 1.0.

      這個選項為失敗的概率

    FAILMALLOC_INTERVAL

      specifies the interval of failures.

      這個選項為每幾次malloc出現一次失敗。

    FAILMALLOC_TIMES

      specifies how many times failures may happen at most.

      指定失敗次數的上限

    FAILMALLOC_SPACE

      specifies the size of free space where memory can be allocated safely in bytes.

      指定申請內存失敗的上限,即低於或者等於該值才會申請失敗,超過該值必定成功。

  14.oprofile的使用

    這個工具可以查看一個程序的性能,比如l2級緩存的命中,各個函數的運行時間等等,並且這個工具可以生成圖表。

    最常用的是各個函數的運行時間。

    類似的工具還有gprof,但是功能上差很多

    另外一個要注意的是,oprofile在虛擬機下不支持按事件計數。比較明顯的是各個函數的運行時間檢測不支持。

    下面詳細描述一次oprofile的使用過程:

    源碼:

    

#include <stdio.h>

int fun(int s,int i)
{
printf("s = %d\n , i = %d\n",s,i);
s = s+i;
return s;
}


int main()
{
int i = 0;
int sum = 0;
for(;i<0x10000;i++)
sum = fun(sum,i);
printf("sum = %x\n",sum);
return 0;
}

    接著是初始化oprofile

    [root@localhost oprofile-1.1.0]# opcontrol --init

    指定監聽事件,這裡使用默認事件,在cpu的時鐘下采樣,每10000個時鐘采一次,不記錄內核,只記錄應用程序

    [root@localhost oprofile-1.1.0]# opcontrol --event=CPU_CLK_UNHALTED:10000:0:0:1

    開始分析

    [root@localhost oprofile-1.1.0]# opcontrol --start
    Using 2.6+ OProfile kernel interface.
    Using log file /var/lib/oprofile/samples/oprofiled.log
    Daemon started.
    Profiler running.

    運行程序,結束之後,停止分析

    [root@localhost oprofile-1.1.0]# opcontrol --stop

    查看結果

[root@localhost oprofile-1.1.0]# opreport --merge=cpu -d a.out
CPU: Core 2, speed 2666.13 MHz (estimated)
Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask of 0x00 (Unhalted core cycles) count 10000
Processes with a thread ID of 32720
Processes with a thread ID of all
vma samples % samples % symbol name
004004c4 226 61.9178 756 59.9524 fun
004004c4 12 5.3097 34 4.4974
004004cc 4 1.7699 25 3.3069
004004da 2 0.8850 17 2.2487
004004e7 4 1.7699 20 2.6455
004004ec 23 10.1770 97 12.8307
004004ef 130 57.5221 378 50.0000
004004f2 32 14.1593 96 12.6984
004004f5 19 8.4071 89 11.7725
004004f7 139 38.0822 505 40.0476 main
0040050f 3 2.1583 18 3.5644
00400519 3 2.1583 23 4.5545
0040051e 7 5.0360 25 4.9505
00400521 92 66.1871 299 59.2079
00400525 9 6.4748 33 6.5347
0040052c 25 17.9856 107 21.1881

    這裡的a.out是指定鏡像,只查看該程序的函數。可以看出,main函數和fun函數各占了本次運行的比例。這只是一個簡單的例子,如果對於一個大型的程序,就可以針對這個結果,優化函數,

 

     這裡還可以查看代碼級的分析結果。

          [root@localhost oprofile-1.1.0]# opannotate --merge=cpu -s a.out  

/*
* Command line: opannotate --merge=cpu -s a.out
*
* Interpretation of command line:
* Output annotated source file with samples
* Output all files
*
* CPU: Core 2, speed 2666.13 MHz (estimated)
* Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask of 0x00 (Unhalted core cycles) count 10000
* Processes with a thread ID of 32720
* Processes with a thread ID of all
*/
/*
* Total samples for file : "/root/czh/oprofile-1.1.0/test.c"
*
* 365 100.000 1261 100.000
*/


              :#include <stdio.h>
              :
              :int fun(int s,int i)
16 4.3836 59 4.6788     :{ /* fun total: 226 61.9178 756 59.9524 */
6 1.6438 37 2.9342     : printf("s = %d\n , i = %d\n",s,i);
153 41.9178 475 37.6685  : s = s+i;
32 8.7671 96 7.6130     : return s;
19 5.2055 89 7.0579     :}
              :
              :
              :int main()
              :{ /* main total: 139 38.0822 505 40.0476 */
              : int i = 0;
              : int sum = 0;
126 34.5205 439 34.8136  : for(;i<0x10000;i++)
13 3.5616 66 5.2339      : sum = fun(sum,i);
              : printf("sum = %x\n",sum);
              : return 0;
              :}

    可以清楚的看到哪一行的代碼占用的時間最多。

 

    注意,如果在虛擬機下運行,是不支持基於事件采樣的,只能基於時間采用,但是這個采樣率太低,效果很差。

    加載模塊前先運行modprobe oprofile timer=1

    可以通過dmesg查看是否是以timer運行的

 

  15.vprobe

    找不到相關資料

  16.查看x86機器是否支持64位

    這一點可以通過查看cpu自帶的寄存器內容或者/proc/cpuinfo中的內容

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved