This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] visualizing locals and backtrace in debug session
- From: Serge Voilokov <voilokov at gmail dot com>
- To: gdb-patches at sourceware dot org
- Date: Wed, 24 Apr 2013 16:37:18 -0400
- Subject: [PATCH] visualizing locals and backtrace in debug session
Hi,
This patch adds new post hooks which dump registers, stack, local
variables on each
step, next, run, finish command. Output goes to ~/gdbout.txt file where can be
watched by 'tail -f ~/gdbout.txt' command in the separate terminal.
Hooks are disabled by default.
auto_enable command enables the hooks.
Implemented using Python API.
Regards,
Serge Voilokov
ChangeLog:
2013-04-24 Serge Voilokov <voilokov@gmail.com>
New command 'auto_enable' which sets post hooks on run, step, next
and finish commands. Hooks dump registers, stack, local variables into
~/gdbout.txt file which can be watched by 'tail -f ~/gdbout.txt'.
* NEWS: New 'auto_enable' command for visualizing runtime info.
* data-directory/Makefile.in: Add gdb/command/auto_info.py
* data-directory/Makefile.in: Add gdb/command/auto_info.cmd
* python/lib/gdb/command/auto_info.py: Implemention of the 'auto_print'
command using the GDB Python API.
* python/lib/gdb/command/auto_info.cmd: Register post hooks for run,
step, next and finish commands which calls auto_print.
Patch:
==================================
diff -urN gdb-7.6.50.20130424/gdb/data-directory/Makefile.in
gdb/gdb/data-directory/Makefile.in
--- gdb-7.6.50.20130424/gdb/data-directory/Makefile.in 2013-01-01
01:32:56.000000000 -0500
+++ gdb/gdb/data-directory/Makefile.in 2013-04-24 15:54:16.000000000 -0400
@@ -61,6 +61,8 @@
gdb/command/pretty_printers.py \
gdb/command/prompt.py \
gdb/command/explore.py \
+ gdb/command/auto_info.py \
+ gdb/command/auto_info.cmd \
gdb/function/__init__.py \
gdb/function/strfns.py
diff -urN gdb-7.6.50.20130424/gdb/python/lib/gdb/command/auto_info.cmd
gdb/gdb/python/lib/gdb/command/auto_info.cmd
--- gdb-7.6.50.20130424/gdb/python/lib/gdb/command/auto_info.cmd
1969-12-31 19:00:00.000000000 -0500
+++ gdb/gdb/python/lib/gdb/command/auto_info.cmd 2013-04-24
13:58:47.000000000 -0400
@@ -0,0 +1,15 @@
+define hookpost-step
+auto_print
+end
+
+define hookpost-next
+auto_print
+end
+
+define hookpost-run
+auto_print
+end
+
+define hookpost-finish
+auto_print
+end
diff -urN gdb-7.6.50.20130424/gdb/python/lib/gdb/command/auto_info.py
gdb/gdb/python/lib/gdb/command/auto_info.py
--- gdb-7.6.50.20130424/gdb/python/lib/gdb/command/auto_info.py
1969-12-31 19:00:00.000000000 -0500
+++ gdb/gdb/python/lib/gdb/command/auto_info.py 2013-04-24
14:44:49.000000000 -0400
@@ -0,0 +1,149 @@
+"""GDB hooks for run, step, next, finish commands.
+Hooks print registers, locals and stack to the ~/gdbout.txt file
+at the end of executing each command.
+~/gdbout.txt can be viewed in second terminal tail -f ~/gdbout.txt
+
+run auto_enable at gdb prompt to define hooks or
+put auto_enable into .gdbinit file
+"""
+
+import gdb, os, re, time
+
+out_file = open(os.environ['HOME'] + '/gdbout.txt', 'wt')
+
+def dump_registers(file):
+ print >> file, '\033[1;31m=== registers ===\033[0;0m'
+ v = gdb.parse_and_eval('$rax')
+ print >> file, '$rax: 0x%x (%d)' % (v, v)
+ print >> file, '\n'
+ file.flush()
+
+def dump_stack(file):
+ frame = gdb.selected_frame()
+ print >> file, '\033[1;31m=== stack ' + frame.function().name +
':' + str(frame.function().line) + ' ===\033[0;0m'
+ cnt = 0
+ while frame is not None:
+ fn = frame.function()
+ if fn is None:
+ if frame.name() is None:
+ break
+ print >> file, str(cnt).ljust(3) + str(frame.name()).ljust(60),
+ else:
+ fname = fn.name
+
+ # shorten long boost names
+ fname = fname.replace('boost::asio::', 'bas::')
+ n = fname.rfind('(')
+ if n > 0:
+ fname = fname[:n]
+ if fname.startswith('boost::_bi::bind_t'):
+ fname = 'bbind'
+
+ # compact long names
+ if len(fname) > 60:
+ fname = fname[:29] + '...' + fname[-28:]
+ fname = fname.ljust(60)
+
+ # hilight frame unless system lib
+ if not fn.symtab.filename.startswith('libs/'):
+ fname = '\033[32m' + fname + '\033[0m'
+ print >> file, str(cnt).ljust(3) + fname + ' ' \
+ + os.path.basename(fn.symtab.filename),
+ print >> file, ''
+ cnt += 1
+ frame = frame.older()
+ if cnt < 12:
+ print >> file, ''.ljust(12 - cnt, '\n')
+ file.flush()
+
+def dump_locals(file):
+ print >> file, "\033[1;31m=== locals ===\033[0;0m"
+ f = gdb.selected_frame()
+ r = re.compile('\s+')
+ cnt = 0
+ for x in gdb.selected_frame().block():
+ kind = ''
+ value = ''
+ ctype = ''
+ ccode = ''
+
+ if x.type.code == gdb.TYPE_CODE_STRUCT:
+ ccode = 'S'
+ elif x.type.code == gdb.TYPE_CODE_UNION:
+ ccode = 'U'
+ elif x.type.code == gdb.TYPE_CODE_ENUM:
+ ccode = 'E'
+
+ if x.addr_class == gdb.SYMBOL_LOC_LABEL:
+ kind = 'l'
+ ccode = ' '
+ elif x.is_argument:
+ kind = 'a'
+ value = str(x.value(f))
+ ctype = str(x.type.tag)
+ elif x.is_variable:
+ kind = 'v'
+ value = str(x.value(f))
+ elif x.is_constant:
+ kind = 'c'
+ value = str(x.value(f))
+
+ if ccode == '':
+ ctype = str(x.type)
+ else:
+ ctype = str(x.type.tag)
+
+ value = value.replace('\n', ' ')
+ value = r.sub(' ', value)
+ print >> file, kind, x.print_name.ljust(10)[:10], \
+ ccode.ljust(2), ctype.ljust(20)[:20], \
+ value.rjust(10).ljust(60)[:60]
+ cnt += 1
+
+ if cnt < 12:
+ print >> file, ''.ljust(12 - cnt, '\n')
+ file.flush()
+
+def dump_vars(file, arg):
+ print >> file, "\033[1;31m=== vars ===\033[0;0m"
+ v = gdb.parse_and_eval(arg)
+ print >> file, '%s[%s] = %s' % (arg, v.type, v)
+
+ print >> file, "\033[1;31m===\033[0;0m"
+ file.flush()
+
+
+class print_all_info(gdb.Command):
+ """
+ print registers, stack and locals to the gdbout.txt
+ """
+
+ file = None
+
+ def __init__(self):
+ gdb.Command.__init__(self, "auto_print", gdb.COMMAND_DATA)
+
+ def invoke(self, arg, from_tty):
+ print >> out_file, ''.ljust(100, '\n')
+ dump_registers(out_file)
+ dump_stack(out_file)
+ dump_locals(out_file)
+
+print_all_info()
+
+class enable_auto_commands(gdb.Command):
+ """
+ enable auto_info hooks
+ """
+
+ file = None
+
+ def __init__(self):
+ gdb.Command.__init__(self, "auto_enable", gdb.COMMAND_DATA)
+
+ def invoke(self, arg, from_tty):
+ cmd_path = __file__.replace('.pyc', '.cmd').replace('.py', '.cmd')
+ gdb.execute('source ' + cmd_path)
+ print 'auto_info hooks loaded'
+
+enable_auto_commands()