2016-04-25 114 views
2

摘要:我想用GDB提取存儲在存儲器中,我的嵌入式目標覆蓋範圍執行計數,並用它們來創建.gcda文件(餵養的gcov/lcov)。通過QEMU/GDB生成.gcda覆蓋文件

的設置

  • 我可以成功交叉編譯的二進制我,我的目標特定的嵌入式目標 - 然後執行它QEMU下。
  • 我也可以使用QEMU的GDB支持來調試二進制文件(即使用tar extended-remote localhost:...附加到正在運行的QEMU GDB服務器,並完全控制我的二進制文件的執行)。

範圍: 現在, 「關於目標」 覆蓋分析執行,我 -fprofile-arcs -ftest-coverage交叉編譯。然後GCC發出64位計數器來跟蹤特定代碼塊的執行計數。

在正常(即基於主機,非交叉編譯)執行下,應用程序結束時__gcov_exit被調用 - 並將所有這些執行計數收集到.gcda文件中(gcov然後用於報告覆蓋細節)。

但是,在我的嵌入式目標中,沒有文件系統可言 - 而libgcov基本上包含所有__gcov_...函數的空存根。通過QEMU/GDB

解決方法:爲了解決這個問題,並做一個GCC版本無關的方式,我可以通過MYPLATFORM-readelf列出我的二進制覆蓋相關的符號,並grep退房手續相關的人(例如__gcov0.Task1_EntryPoint__gcov0.worker等):

$ MYPLATFORM-readelf -s binary | grep __gcov 
... 
46: 40021498 48 OBJECT LOCAL DEFAULT 4 __gcov0.Task1_EntryPoint 
... 

我可以然後使用報告給自動創建GDB腳本的偏移量/大小 - 即通過簡單的存儲器中提取的計數器數據轉儲的腳本(從偏移,轉儲長度字節t o本地文件)。

我不知道什麼(並未能找到任何相關信息/工具)是如何產生的的雙(內存偏移,內存中的數據).gcda文件轉換。如果存在這樣的工具/腳本,我會有一種可移植的(與平臺無關的)方式來覆蓋任何QEMU支持的平臺。

有沒有這樣的工具/腳本?

任何建議/指針將不勝感激。

UPDATE:我自己解決了這個問題,你可以在下面閱讀 - 並寫了一個blog post about it

回答

1

原來有一個(很多)更好的方式來做我想要的。

Linux內核includes portable GCOV related functionality,通過提供該端點抽象了GCC的特定版本的詳細信息:所以基本上

size_t convert_to_gcda(char *buffer, struct gcov_info *info) 

,我能夠通過以下步驟來做到對目標覆蓋:

步驟1

我加入了Linux gcov的文件到我的項目三個稍微修改版本:base.cgcc_4_7.cgcov.h。我必須替換它們內部的一些linux-isms,如vmalloc,kfree等,以使代碼可移植(因此,可在我的嵌入式平臺上編譯,而這與Linux無關)。

步驟2

然後我提供我自己的__gcov_init ...

typedef struct tagGcovInfo { 
    struct gcov_info *info; 
    struct tagGcovInfo *next; 
} GcovInfo; 
GcovInfo *headGcov = NULL; 

void __gcov_init(struct gcov_info *info) 
{ 
    printf(
     "__gcov_init called for %s!\n", 
     gcov_info_filename(info)); 
    fflush(stdout); 
    GcovInfo *newHead = malloc(sizeof(GcovInfo)); 
    if (!newHead) { 
     puts("Out of memory!"); 
     exit(1); 
    } 
    newHead->info = info; 
    newHead->next = headGcov; 
    headGcov = newHead; 
} 

...和__gcov_exit

void __gcov_exit() 
{ 
    GcovInfo *tmp = headGcov; 
    while(tmp) { 
     char *buffer; 
     int bytesNeeded = convert_to_gcda(NULL, tmp->info); 
     buffer = malloc(bytesNeeded); 
     if (!buffer) { 
      puts("Out of memory!"); 
      exit(1); 
     } 
     convert_to_gcda(buffer, tmp->info); 
     printf("Emitting %6d bytes for %s\n", bytesNeeded, gcov_info_filename(tmp->info)); 
     free(buffer); 
     tmp = tmp->next; 
    } 
} 

步驟3

最後,我通過這個腳本我GDB(驅動QEMU遠程):

$ cat coverage.gdb 
tar extended-remote :9976 
file bin.debug/fputest 
b base.c:88 <================= This breaks on the "Emitting" printf in __gcov_exit 
commands 1 
    silent 
    set $filename = tmp->info->filename 
    set $dataBegin = buffer 
    set $dataEnd = buffer + bytesNeeded 
    eval "dump binary memory %s 0x%lx 0x%lx", $filename, $dataBegin, $dataEnd 
    c 
end 
c 
quit 

最後,執行既QEMU和GDB - 這樣的:

$ # In terminal 1: 
qemu-system-MYPLATFORM ... -kernel bin.debug/fputest -gdb tcp::9976 -S 

$ # In terminal 2: 
MYPLATFORM-gdb -x coverage.gdb 

...這就是它 - 我能夠在我的本地文件系統中生成.gcda文件,然後通過gcovlcov查看覆蓋率結果。

UPDATE:我寫了blog post showing the process in detail