繁体   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