I want to run GDB with a Python script that also drives the debug target's input, say through a pipe. I cannot seem to get the ordering of the target execution and pipe setup lined up to avoid blocking or an error. I've tried solutions with both blocking and non-blocking opens of the named pipes; a non-blocking example is shared below.
What doesn't help is that GDB doesn't seem to allow for background execution combined with input/output redirection, I try to circumvent that using starti and continue&.
import os
# create input/output pipes
in_pipe = "in"
out_pipe = "out"
try:
os.unlink(in_pipe)
except FileNotFoundError:
pass
try:
os.unlink(out_pipe)
except FileNotFoundError:
pass
os.mkfifo(in_pipe)
os.system(f"sleep infinity > {in_pipe} &")
print("in pipe:", in_pipe)
os.mkfifo(out_pipe)
os.system(f"sleep infinity > {out_pipe} &")
print("out pipe:", out_pipe)
# open in/out pipes to prevent starti command from blocking
# open a tmp read-only FD for the input pipe to prevent it's write-only open from blocking
out_fd = os.open(out_pipe, os.O_RDONLY | os.O_NONBLOCK)
tmp_fd = os.open(in_pipe, os.O_RDONLY | os.O_NONBLOCK) # prevent blocking
in_fd = os.open(in_pipe, os.O_WRONLY | os.O_NONBLOCK)
gdb.execute(f"set target-async on")
gdb.execute(f"starti < {in_pipe} > {out_pipe}")
gdb.execute(f"c&")
print(os.read(out_fd, 8)) # causes BlockingIOError for some reason, even if I ensure enough time for the target to print
print("--- DONE ---")
Is there a way to make this work?
EDIT: I've also tried a pty solution:
import os
import pty
master, slave = pty.openpty()
tty_name = os.ttyname(slave)
gdb.execute(f"set inferior-tty {tty_name}")
gdb.execute(f"set target-async on")
gdb.execute(f"r&")
print("1")
#os.write(master, b"1\n")
print(os.read(master, 8)) # blocks???
print("2")
print("--- DONE ---")
Both of these work when working with gdb manually, neither seem to work when using the GDB Python API; ps indicates that the target is stopped by the debugger ('t' status).