2017-05-31 100 views
6

評價C++表達式調試時,我最近注意到,有GDB調試程序時,以評估「複雜」表述的能力,我想知道它是如何做到這一點。例如,用下面的代碼:如何GDB在運行時

int main() { 
    std::vector<int> v = {1, 2, 3}; 
    int k = 0; 
    std::cin >> k; 
    v.push_back(k); 
    return v.at(0); 
} 

我能夠編譯程序g++ -g myprogram.cpp和調試它GDB,讓我鍵入像print v.at(4);事情(後k動態進入其打印正確的值)和print v.at(2) == 3評估爲真。

我想知道GDB是如何做到這一點的。 This SO question暗示它是「內存中編譯」的東西,但沒有進一步詳細說明,所以我想知道它是否使用某種JIT來使這一切工作或別的東西?他們是在我編寫並運行它時編譯內聯代碼嗎?他們是否有一個框架來在調試環境中實時評估C++?實質上,我想在調試器中重現這一點,我正在寫這些調試器來評估斷點處的表達式,這就是爲什麼我很好奇GDB如何執行它。

+1

目前還不清楚你希望得到什麼樣的答案。 Gdb能夠在被調試程序的上下文中分析C和C++表達式,並且可以在二進制文件中包含調試信息的幫助下,也可以在可用時使用源代碼。但是你已經知道了,而且這個場地的細節會很長。 –

+0

@JohnBollinger我想我將不得不「使用源」,但我想知道的是他們如何評估表達式。他們是在我編寫並運行它時編譯內聯代碼嗎?他們是否有一個框架來在調試環境中實時評估C++?實質上,我想在調試器中重現這一點,我正在寫這些調試器來評估斷點處的表達式,這就是爲什麼我很好奇GDB如何執行它。謝謝! – llk

+0

你的問題似乎更關注於C++。我建議你刪除C標籤。 – tambre

回答

5

簡短回答:它不編譯代碼。

龍答案:

  1. 你打電話print命令和在printcmd.c
  2. 它調用evaluate_expression,在eval.c定義,其通過讀取目標存儲器和計算它裏面的gdb用於計算表達式發生程序標準操作員,否則使用call_function_by_hand
  3. call_function_by_hand定義於infcall.c。在調用時,該過程會暫停目標執行(有時不會,因此可能會使用此功能使多線程程序崩潰)。
  4. 將代碼注入到正在調試的程序中。
  5. 通過讀取內存來檢索結果並在必要時取消暫停。

爲了更好地理解,您可能會將注意力集中在call_function_by_hand的代碼上。

注意:compile是與print/call不同的東西。

完整的答案:

在幾天內,我可以寫的GDB如何實現這個功能,進一步閱讀了詳細的分析。

6

,讓我型喜歡的東西打印v.at(4);

GDB可以調用編譯成二進制功能。這正是這裏發生的事情。 gdb調用std::vector成員函數at()並打印結果給您,請參閱documentation

另外請注意,這是可能的,因爲你在你的代碼中使用v.at(0)。如果你刪除了這部分代碼,v.at()將不會被實例化,並且在結果二進制文件中將不可用,因此gdb無法調用它。

+0

因此,GDB不會編譯任何東西,而是運行現有代碼的各個部分來評估表達式? GDB是否有一個庫用來做這件事,或者它是以獨立的方式完全編碼的? – llk

+1

是的,在你發佈的例子中。但它也可以編譯和注入代碼,請參閱https://sourceware.org/gdb/onlinedocs/gdb/Compiling-and-Injecting-Code.html#Compiling-and-Injecting-Code,但我沒有使用過這個功能。 – ks1322