2016-11-03 54 views
2

我試圖修復其他人編寫的代碼中的錯誤,並且我試圖通過gdb來確定發生了什麼。但是我碰到的其中一條線是對longjmp()的調用,並且在該行上點擊「next」後,gdb將繼續執行常規執行,而不是斷開正在執行的下一個源代碼行。如果我在longjmp()行上嘗試「step」,會發生類似的情況。是否有任何gdb命令我可以用來打破longjmp()之後執行的下一個源代碼行?如何通過gdb中的longjmp步驟

+0

你可以通過程序來執行'break main',然後'run'並保持'step'ping。然後它會在每一行提示輸入,包括longjmp()之後的一行。 (如果這回答你的問題,我會把它放在一個答案) –

+0

如果你點擊「step」而不是「next」會發生什麼?你可以做的一件事是在處理來自'setjmp()'的非零返回值的代碼上添加一個斷點。 –

+0

@MDXF,清楚的是,您可以使用'step'命令而不是'next'命令? OP說這對他不起作用。我發現你建議特別打破'main',但我不明白爲什麼這會在'longjmp()'之前在別的地方出現差異。 –

回答

1

您需要在setjmp之後的非零返回碼之後的行處設置斷點。

例如:

#include <stdio.h> 
#include <setjmp.h> 

jmp_buf jb; 

void f1() 
{ 
    printf("jumping\n"); 
    longjmp(jb, 1); 
    printf("what???\n"); 
} 

int main() 
{ 
    if (!setjmp(jb)) { 
     printf("calling f1\n"); 
     f1(); 
    } else { 
     printf("jumped!!\n"); // line 19 
    } 
    return 0; 
} 

主叫longjmp後,要執行的下一行是行19(參見注釋)。因此,在這種情況下,在gdb提示符下運行break 19,在撥打longjmp後,您將在該行停止。

GDB輸出:

(gdb) break 19 
Breakpoint 2 at 0x40056d: file /tmp/x1.c, line 19. 
(gdb) start 
Temporary breakpoint 3 at 0x400549: file /tmp/x1.c, line 15. 
Starting program: /tmp/x1 
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x2aaaaaaab000 

Temporary breakpoint 3, main() at /tmp/x1.c:15 
15   if (!setjmp(jb)) { 
(gdb) step 
16    printf("calling f1\n"); 
(gdb) 
calling f1 
17    f1(); 
(gdb) 
f1() at /tmp/x1.c:8 
8   printf("jumping\n"); 
(gdb) 
jumping 
9   longjmp(jb, 1); 
(gdb) 

Breakpoint 2, main() at /tmp/x1.c:19 
19    printf("jumped!!\n"); 
(gdb) 
jumped!! 
21   return 0; 
(gdb) 
22  } 
(gdb) 
0x0000003fa441d9f4 in __libc_start_main() from /lib64/libc.so.6 
(gdb) 
+0

這基本上工作。經過一番搜索,找出setjmp是最後一個setjmp,但是在非零返回足夠的setjmps之後加入了斷點之後,我終於明白了程序的進展情況。 –

1

是否有任何命令的gdb我可以用來對下一個源線折斷後longjmp的正在執行()?

據我所知,沒有。您需要跟蹤jmp_buf的來源備份調用堆棧以查找填充它的setjmp()。如果源中的setjmp()調用很少,則可以考慮在每個調用後設置一個斷點。否則,您可能只是逐步執行該程序,在您通過每個setjmp()後設置一個斷點。

還要注意的是,你的確應該找到的調用堆棧的功能之一相關setjmp()達到相應longjmp()時,否則該jmp_buf無效。

您可以使用bt命令獲取調用堆棧,並使用frame命令切換到並檢查堆棧上的任何幀。

4

值得注意的是gdb的行爲是依賴於系統的。

在Linux上,nextlongjmpthrow工作約你所期望的:如果非本地跳轉的目標是和當前幀以上,執行將停在那裏。

這是在longjmpthrow的實現中使用調試掛鉤實現的。對於throw,這是通過輔助函數(舊方法)和所謂的SystemTap探針(又稱「sdt探針」)完成的。對於longjmp,只能使用glibc中的sdt探針完成此操作。

爲此,必須將探針支持編譯到相關庫中。你可以用readelf -n查詢。至少Fedora正確地做到了這一點。

在理論上可能爲gdb中的其他平臺實現對longjmp的支持。但是,這可能是不平凡的。

您可以嘗試解碼jmp_buf,如其他評論中所述。但請注意,在某些系統(如Linux)中,出於安全原因編碼了jmp_buf中的目標PC。所以你必須弄清楚如何解碼它。

解決此問題的另一種方法是簡單地單步執行longjmp本身。在那裏設置一個斷點,如break longjmp;使用disassemble查看組件;然後執行si,直到完成將執行轉移到目標的指令。