0

I'm issuing the following commands to extract symbol information from an elf file:

p = subprocess.Popen(["gdb", "-q", "my.elf", "-ex", symbol, "-ex", "q"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)

output = p.stdout.peek().decode('utf-8').splitlines()

If I run the code then the only thing I get back from the command is: 'Reading symbols from /home/user/my.elf...done.'

If I step through the code with a debugger or put in a time.sleep(1) call between the Popen and the peek() commands, then I get a list with the structure elements as members. So it looks like Popen doesn't wait for gdb to finish processing the command.

Can someone explain why this is the case and offer a workaround? Putting in a 1 second sleep between each call is going to take way too long for something that contains hundreds if not thousands of symbols. Thanks.

codester_09
  • 5,622
  • 2
  • 5
  • 27
KernelSanders
  • 23
  • 1
  • 6
  • 1
    `Popen()` isn't _expected_ to wait on its own. You can call `communicate()` if you want to wait and also read all output (if you just call `wait()`, it'll wait for the process to finish but _not_ consume stdout, which can get you into a deadlock if the program is trying to write output before it exits). – Charles Duffy May 09 '22 at 14:44
  • You have to use something like [`Popen.communicate`](https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate) to make it block and wait for completion. – 0x5453 May 09 '22 at 14:45
  • BTW, is gdb expected to read from stdin in this usage mode? If not, why are you using `stdin=subprocess.PIPE`? And if so, why aren't you providing it with some input? – Charles Duffy May 09 '22 at 14:48
  • stdin=subprocess.PIPE is left over from when I was trying to send commands to gdb. You are right, I no longer need that. – KernelSanders May 09 '22 at 15:11

2 Answers2

0

It's non-blocking - you get back a stream you can keep reading from. Why? Because that's what it's supposed to do ... it's a good way to exchange data between a parent process and a long-running child process.

If you want a blocking one-shot invocation, it's easier to use subprocess.run() rather than raw Popen.

solidpixel
  • 10,688
  • 1
  • 20
  • 33
0

Add .communicate() for waiting like this :

p = subprocess.Popen(["gdb", "-q", "my.elf", "-ex", symbol, "-ex", "q"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p.communicate()
ACHRAF
  • 341
  • 1
  • 7
  • `p.wait()` will cause a deadlock if gdb doesn't exit until after successfully writing output to stdout. `communicate()` is the only correct choice if there isn't some other way of handling output. – Charles Duffy May 09 '22 at 14:51
  • Yes you are right, i have doubts about the second solution – ACHRAF May 09 '22 at 14:52
  • That solved the problem. Thanks. I thought I had tried that but I probably didn't realize at the time that the entire structure follows the 'Reading symbols from /home/user/my.elf...done.' text. Looking at the return in the debugger now shows that the struct is there after that part and it works as I wanted it to. Thanks everyone! – KernelSanders May 09 '22 at 15:15