[RFC][patch 0/9] Python support in GDB

Thiago Jung Bauermann
2008-04-29T15:58:31Z

Hi everybody,

This patch series adds Python scripting support to GDB, and exposes
some of its subsystems hopefully in a "pythonic" way. These patches
correspond to the contents of the git repository at gitorious.org,
rebased to apply cleanly on top of CVS HEAD as of 04/27.

Unfortunately I wasn't able to resolve the conflicts on the MI code
when I did the rebase, so I had to leave the MI part out. Sorry about
this, Vladimir. I pushed to gitorious the branch containig the HEAD
version I used as base for the patches (it is the patches-base branch),
so I believe it will be easy for you to generate the missing patch.
Let me know if you would like me to help with this.

Regarding the ChangeLogs, I tried to put the right authors for each
patch. If I didn't attribute blame correctly, please let me know.

We now would like your opinion and input, especially regarding what
is/should be exposed to Python and how. We implemented what we thought
was useful, and covered the use cases we had in mind. Please point out
if the current implementation doesn't cover your use case, or a use
case that would be useful to support.

And, of course, if you think this is all well and good and the greatest
thing since sliced bread, consider this an RFA. :-)

By the way, here is a Python implementation of the backtrace command
which shows its output in reverse (correct, actually!) order. It is
relatively complex so it shows well how Python scripting currently
looks like in GDB (but it doesn't use all of what is exposed):

python
import sys

def argument_symbol (sym):
sym_class = sym.get_class ()
if (sym_class == gdb.SYMBOL_LOC_ARG or
sym_class == gdb.SYMBOL_LOC_REF_ARG or
sym_class == gdb.SYMBOL_LOC_REGPARM or
sym_class == gdb.SYMBOL_LOC_REGPARM_ADDR or
sym_class == gdb.SYMBOL_LOC_LOCAL_ARG or
sym_class == gdb.SYMBOL_LOC_BASEREG_ARG or
sym_class == gdb.SYMBOL_LOC_COMPUTED_ARG):
return True

return False

def print_frame_args (func, frame):
if not func:
return

first = True
block = func.get_value ()
for sym in block:
if not argument_symbol (sym):
continue;

if len(sym.get_linkage_name ()):
nsym, is_field_of_this, symtab = gdb.lookup_symbol (sym.get_linkage_name (), block, gdb.SYMBOL_VAR_DOMAIN)
if nsym.get_class () != gdb.SYMBOL_LOC_REGISTER:
sym = nsym

if not first:
sys.stdout.write (", ")

sys.stdout.write (sym.get_print_name () + "=")
val = frame.read_var_value (sym)
if val:
val.common_print (None, False, 2, 0)
else:
sys.stdout.write ("???")

first = False

def gdb_rbacktrace ():
frames = gdb.get_frames ()
num_frames = len (frames)

if num_frames > 0 and frames[num_frames - 1].get_unwind_stop_reason() > gdb.FRAME_UNWIND_FIRST_ERROR:
print "Backtrace stopped: " + gdb.frame_stop_reason_string (frames[num_frames - 1].get_unwind_stop_reason())

for i in reversed (range (len (frames))):
sys.stdout.write ("#%-2d" % i)

if frames[i].get_type () == gdb.DUMMY_FRAME:
sys.stdout.write (" <function called from gdb>\n")
continue
elif frames[i].get_type () == gdb.SIGTRAMP_FRAME:
sys.stdout.write (" <signal handler called>\n")
continue

sal = frames[i].find_sal ()
pc = frames[i].get_pc ()
name = frames[i].get_name ()
if not name:
name = "??"

if pc != sal.get_pc () or not sal.symtab:
sys.stdout.write (" 0x%08x in" % pc)

sys.stdout.write (" " + name + " (")

func = gdb.find_pc_function (frames[i].get_address_in_block ())
print_frame_args (func, frames[i])
sys.stdout.write (")")

if sal.symtab and sal.symtab.get_filename ():
sys.stdout.write (" at " + sal.symtab.get_filename ())
sys.stdout.write (":" + str (sal.get_line ()))

if not frames[i].get_name () or (not sal.symtab or not sal.symtab.get_filename ()):
lib = gdb.solib_address (pc)
if lib:
sys.stdout.write (" from " + lib)

sys.stdout.write ("\n")
end

define rbt
python gdb_rbacktrace ()
end

--
[]'s
Thiago Jung Bauermann
Software Engineer
IBM Linux Technology Center