简体   繁体   中英

How can I create a testing script with GDB

I have a set of inputs that I want to use to test my program so see what input will hit a break point. I want to create a script to test these inputs one by one and if it hit the break point, print or save the result to a file. Please let me know if it's possible and if yes, how can I do it. Thank you.

I'm not sure if I have exactly understood what you are asking for. But if I understood correctly, you want to write a program that:

  • Starts another program
  • Passes some pre-defined input to the other program
  • Checks if some breakpoint in the other program is hit

I don't know if this is possible using gdb , but it would be possible to write your own debugger:

  • Start the program to be tested using fork and one of the exec functions (such as execlp )
  • Before the exec function call ptrace(PTRACE_TRACEME,0,0,0)
  • Call waitpid ; if exec succeeded, the program will be stopped immediately. The "status code" (second argument) returned by waitpid will be 0x57F (assuming an x86 CPU).
  • If waitpid returns another exit code, exec failed and you cannot continue.
  • Use ptrace(PTRACE_PEEKTEXT,...) and ptrace(PTRACE_POKETEXT,...) to modify the program: You place a break point to some address by replacing the instruction at that address by a "breakpoint" instruction (on x86 CPUs: int3 which is byte 0xCC )
    This means:
    You have to know the addresses (not the line numbers) of the break points and write 0xCC to each address using ptrace() . Because PTRACE_POKETEXT can only modify 4 bytes (x86_32) or 8 bytes (x86_64) at once, you first have to read the old values of these 4 or 8 bytes using PTRACE_PEEKTEXT , modify 1 of 4 or 8 bytes and write all 4 or 8 bytes back.
  • If your program is not always loading to the same address (due to ASLR etc.) you can read the program counter (using PTRACE_PEEKUSER ): It should be the (actual) address of the entry point of the program.
  • Call ptrace(PTRACE_CONT,pid,0,0) to start the program being tested
  • Call waitpid to wait for the program to be stopped or to exit
  • If waitpid returns 0x57F as "status code", you are in the breakpoint. You may now use kill(pid, SIGKILL) to stop your program.
  • You may use PTRACE_PEEKUSER to check the value of the program counter ( rip on x86-64) so you know which breakpoint has been hit. Note that the program counter may be the address of the breakpoint plus 1 , so if a breakpoint at address 0x12340000 has been hit, rip may be 0x12340001.
  • If waitpid returns any other value with the low byte 0x7F, the program caused an exception. You should use kill(pid,SIGKILL) to finally stop it.
  • Otherwise (if the low byte returned by waitpid is not 0x7F), the program has finished without causing an exception and without hitting any breakpoint.

Here some example code:

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);
    }
}

To pass input to your program, you have two possible choices:

  • Run the debugger multiple times:

     echo "Input to be tested" | ./myDebugger

    Because your debugger does not read from STDIN, the input will be passed to the program to be tested.

  • Use pipe and dup2 when creating the child process:

     ... 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", ...); ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM