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:
I don't know if this is possible using gdb
, but it would be possible to write your own debugger:
fork
and one of the exec
functions (such as execlp
)exec
function call ptrace(PTRACE_TRACEME,0,0,0)
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). waitpid
returns another exit code, exec
failed and you cannot continue.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
)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.PTRACE_PEEKUSER
): It should be the (actual) address of the entry point of the program.ptrace(PTRACE_CONT,pid,0,0)
to start the program being testedwaitpid
to wait for the program to be stopped or to exitwaitpid
returns 0x57F as "status code", you are in the breakpoint. You may now use kill(pid, SIGKILL)
to stop your program.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.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.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.