While trying to answer another question, I tried to set-up a Python script to automatize the extraction of an assembly execution trace. But, I am really not satisfied of this script and I would like to know how to improve it.

First, here is the script:

import gdb

gdb.execute('break main')

while (True):
    gdb.write (gdb.execute('x /i $pc', to_string=True).rstrip('\n'), gdb.STDOUT)
    gdb.execute('stepi', to_string=False)
    gdb.flush ()

Then, just execute:

$> gdb -x ./script.py ./main 1> log.txt

The problems that I would like to solve are as follow:

  • First, the while(True) is definitely not satisfactory. I would like to stop or suspend the loop when a breakpoint or an exit is reached.

  • Also, the way we export the list of instructions outside of gdb is not really satisfactory. Saving it to a file would be much better than having to redirect stdout to a file.

  • Finally, be able to interact with the software, feeding it through stdin would also be something we want.

So, if you know how to improve this script in any manner, I would be interested.

  • Why don't you use PIN, valgrind, or DynamoRio? – gogo_gorilla Dec 19 '15 at 18:29
  • 1
    Why not use gdb if it is enough ? Moreover, PIN is for Intel architectures only, DynamoRio is not packaged for Debian, and Valgrind execution is emulated and may be biaised. – perror Dec 19 '15 at 22:05
  • Do you see an easy way how your script could not only log the instructions but also the memory accesses (read and write) including the accessed values? – gogo_gorilla Mar 20 '16 at 20:35

Your question really seems to be "How to get an instruction trace with GDB". The use of Python appears to be incidental, except that you're using Python inside of GDB.

GDB has native support for instruction tracing, via the record command. Using the command record full will record all changes to the process's state, and even allow reverse debugging (i.e. backward-stepping and replay).

You can find more information here: https://sourceware.org/gdb/onlinedocs/gdb/Process-Record-and-Replay.html

Separately, if you would like to perform single-stepping and instruction tracing with Python-inside-GDB, your best bet is to use the Breakpoint class and use internal breakpoints which do not halt the UI. On architectures with variable-width instructions (i386, amd64) you will need to calculate the size of the current instruction. You will also need to resolve all jump and calls targets.

If you look at the GDB source code you'll see how this all works in the event loop, and it is not exposed to the Python API. Search for STEP_OVER_NONE which is used for the stepi instruction (step exactly one machine instruction).

If you're so inclined, you can do this in GDB with the gdb.Breakpoint and gdb.FinishBreakpoint types. However, you end up needing to parse instruction widths (on variable-width instruction ISAs like x86), and extract jump and call targets. GDB's Python API does not have any support for a single-step breakpoint, or resolving what the next instruction address will be. You can do both of those things pretty easily with Capstone and Unicorn.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.