簡體   English   中英

如何使用 GDB 創建測試腳本

[英]How can I create a testing script with GDB

我有一組輸入,我想用它們來測試我的程序,以便查看哪些輸入會遇到斷點。 我想創建一個腳本來一一測試這些輸入,如果它達到斷點,則將結果打印或保存到文件中。 請讓我知道是否可能,如果是,我該怎么做。 謝謝你。

我不確定我是否完全理解你的要求。 但是如果我理解正確的話,你想編寫一個程序:

  • 啟動另一個程序
  • 將一些預定義的輸入傳遞給另一個程序
  • 檢查是否命中了另一個程序中的某個斷點

我不知道這是否可以使用gdb ,但可以編寫自己的調試器:

  • 使用forkexec函數之一(例如execlp )啟動要測試的程序
  • exec函數調用ptrace(PTRACE_TRACEME,0,0,0)
  • 調用waitpid 如果exec成功,程序將立即停止。 waitpid返回的“狀態代碼”(第二個參數)將為 0x57F(假設為 x86 CPU)。
  • 如果waitpid返回另一個退出代碼,則exec失敗並且您無法繼續。
  • 使用ptrace(PTRACE_PEEKTEXT,...)ptrace(PTRACE_POKETEXT,...)修改程序:通過用“斷點”指令替換該地址處的指令(在 x86 CPU 上: int3這是字節0xCC
    這意味着:
    您必須知道斷點的地址(而不是行號)並使用ptrace()0xCC寫入每個地址。 因為PTRACE_POKETEXT一次只能修改 4 個字節 (x86_32) 或 8 個字節 (x86_64),所以您首先必須使用PTRACE_PEEKTEXT讀取這 4 個或 8 個字節的舊值,修改 4 個或 8 個字節中的 1 個並寫入所有 4 個或 8 個字節背部。
  • 如果您的程序並不總是加載到相同的地址(由於 ASLR 等),您可以讀取程序計數器(使用PTRACE_PEEKUSER ):它應該是程序入口點的(實際)地址。
  • 調用ptrace(PTRACE_CONT,pid,0,0)啟動被測程序
  • 調用waitpid等待程序停止或退出
  • 如果waitpid返回 0x57F 作為“狀態代碼”,則您處於斷點處。 您現在可以使用kill(pid, SIGKILL)來停止您的程序。
  • 您可以使用PTRACE_PEEKUSER檢查程序計數器的值(x86-64 上的rip ),以便您知道哪個斷點被命中。 請注意,程序計數器可能是斷點的地址加 1 ,因此如果在地址 0x12340000 處的斷點被命中,則rip可能是 0x12340001。
  • 如果waitpid返回低字節 0x7F 的任何其他值,則程序導致異常。 您應該使用kill(pid,SIGKILL)來最終停止它。
  • 否則(如果waitpid返回的低字節不是0x7F),程序就結束了,不會引發異常,也不會碰到任何斷點。

這里有一些示例代碼:

int pid, code;
long tmpLong;

pid=fork();

if(!pid)
{
    ptrace(PTRACE_TRACEME,0,0,0);
    execlp("program_to_be_tested","program_to_be_tested",NULL);
    exit(123);
}

waitpid(pid,&code,0);

if(code!=0x57F)
{
    /* Starting the program failed ... */
}
else
{
    /* Set breakpoints - here assuming x86-64 */
    tmpLong=ptrace(PTRACE_PEEKDATA,pid,(void *)(address&~7),0);
    ((char *)&tmpLong)[address&7]=0xCC;
    ptrace(PTRACE_POKEDATA,pid,(void *)(address&~7),(void *)tmpLong);

    /* Continue the program */
    ptrace(PTRACE_CONT,pid,0,0);
    waitpid(pid,&code,0);
    if((code&0xFF)!=0x7F)
    {
        /* Program did not hit a breakpoint
         * and did not cause an exception */
    }
    else if(code==0x57F)
    {
        /* Breakpoint hit */
        kill(pid,SIGKILL);
    }
    else
    {
        /* Program caused an exception */
        kill(pid,SIGKILL);
    }
}

要將輸入傳遞給您的程序,您有兩種可能的選擇:

  • 多次運行調試器:

     echo "Input to be tested" | ./myDebugger

    因為您的調試器不從 STDIN 讀取,所以輸入將傳遞給要測試的程序。

  • 創建子進程時使用pipedup2

     ... pipe(pipes); pid=fork(); if(!pid) { dup2(pipes[0],0); close(pipes[0]); close(pipes[1]); ... } close(pipes[0]); write(pipes[1],"Input to be sent to program", ...); ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM