pythonmultithreadinggdbgdb-python

gdb.execute blocks all the threads in python scripts


I am scripting GDB with Python 2.7.

I am simply stepping instructions with gdb.execute("stepi"). If the debugged program is idling and waiting for user interaction, gdb.execute("stepi") doesn't return. If there is such a situation, I want to stop the debugging session without terminating gdb.

To do so, I create a thread that will kill the debugged process if the current instruction ran for more than x seconds:

from ctypes import c_ulonglong, c_bool
from os import kill
from threading import Thread
from time import sleep
import signal

# We need mutable primitives in order to update them in the thread
it = c_ulonglong(0) # Instructions counter
program_exited = c_bool(False)
t = Thread(target=check_for_idle, args=(pid,it,program_exited))
t.start()

while not program_exited.value:
    gdb.execute("si") # Step instruction
    it.value += 1

# Threaded function that will kill the loaded program if it's idling
def check_for_idle(pid, it, program_exited):
    delta_max = 0.1 # Max delay between 2 instructions, seconds
    while not program_exited.value:
        it_prev = c_ulonglong(it.value) # Previous value of instructions counter
        sleep(delta_max)
        # If previous instruction lasted for more than 'delta_max', kill debugged process
        if (it_prev.value == it.value):
            # Process pid has been retrieved before
            kill(pid, signal.SIGTERM)       
            program_exited.value = True
    print("idle_process_end")

However, gdb.execute is pausing my thread... Is there another way to kill the debugged process if it is idling?


Solution

  • However, gdb.execute is pausing my thread

    What is happening here is that gdb.execute does not release Python's global lock when calling into gdb. So, while the gdb command executes, other Python threads are stuck.

    This is just an oversight in gdb. I've filed a bug for it.

    Is there another way to kill the debugged process if it is idling?

    There is one other technique you can try -- I am not certain it will work. Unfortunately this part of gdb is not fully fleshed out (at the present moment); so also feel free to file bug reports.

    The main idea is to run gdb commands on the main thread -- but not from Python. So, try writing your stepping loop using the gdb CLI, maybe like:

    (gdb) while 1
    > stepi
    > end
    

    Then your thread should be able to kill the inferior. Another approach might be for your thread to inject a gdb command into the main loop using gdb.post_event.