python: add set/show variable vdb-autodebug
When set to 'on', a Python debugger is automatically started
upon error in Python code. This helps debugging Python scripts.
--- a/python/vdb/__init__.py Wed May 25 17:02:01 2022 +0100
+++ b/python/vdb/__init__.py Wed May 25 17:03:30 2022 +0100
@@ -108,3 +108,28 @@
gdb.prompt_hook = lambda x: "%s > " % prompt
sys.ps1 = "%s pi > " % prompt
sys.ps2 = "%s > " % (" " * len(prompt))
+
+
+autodebug = gdb.Parameter('vdb-autodebug', gdb.COMMAND_DATA, gdb.PARAM_AUTO_BOOLEAN)
+autodebug.value = False
+
+# Install automatic debugging hook
+def __autodebug_excepthook(typ, value, tb):
+ if autodebug.value == False: # hasattr(sys, 'ps1') or not sys.stderr.isatty():
+ sys.__excepthook__(typ, value, tb)
+ return
+ if autodebug.value == None: # set to 'auto'
+ pass
+
+ import traceback, pdb
+ if tb is None:
+ print("EXECEPTION IN PYTHON CODE:")
+ traceback.print_last()
+ else:
+ print("EXECEPTION IN PYTHON CODE, ENTERING DEBUGGER:")
+ traceback.print_exception(typ, value, tb)
+ # ...then start the debugger in post-mortem mode.
+ # pdb.pm() # deprecated
+ pdb.post_mortem(tb) # more "modern"
+
+sys.excepthook = __autodebug_excepthook
--- a/python/vdb/cli.py Wed May 25 17:02:01 2022 +0100
+++ b/python/vdb/cli.py Wed May 25 17:03:30 2022 +0100
@@ -16,7 +16,6 @@
import gdb
-
class __PythonReload(gdb.Command):
"""
Reload Python code
@@ -116,20 +115,78 @@
# So, we have to "reload" it manually by re-evaluating the source in
# context of __main__ module.
#
- # TODO: Is there a better way? Following code looks a wee bit too
+ # TODO: Is there a betpiter way? Following code looks a wee bit too
# fragile
- if module.__name__ == "__main__":
- if hasattr(module.__loader__, "path"):
- source_path = module.__loader__.path
- if os.path.exists(source_path):
- with open(source_path) as source_file:
- source = source_file.read()
- exec(source, module.__dict__)
- else:
- importlib.reload(module)
+ try:
+ if module.__name__ == "__main__":
+ if hasattr(module.__loader__, "path"):
+ source_path = module.__loader__.path
+ if os.path.exists(source_path):
+ with open(source_path) as source_file:
+ source = source_file.read()
+ exec(source, module.__dict__)
+ else:
+ importlib.reload(module)
+ except Exception as ex:
+ print("Failed to reload module '%s': %s" % (module.__name__, ex))
reload()
print("Done!")
pr = __PythonReload("pr", gdb.COMMAND_MAINTENANCE)
+
+class __DumpObjectCmd(gdb.Command):
+ """
+ Dump contents or expression EXP
+ Usage: do EXP [EXP...]
+
+ An expression EXP can be either OOP as numerical constant
+ (for example '0x1ff10028') or C/C++ expression which is
+ evaluated in current frame (for example, 'kernel->header.module')
+ """
+ def invoke (self, args, from_tty):
+ self(*gdb.string_to_argv(args))
+
+ def __call__(self, *exprs):
+ for expr in exprs:
+ self.dump(expr)
+
+ def complete(self, text, word):
+ return gdb.COMPLETE_EXPRESSION
+
+ def dump(self, expr):
+ import vdb
+ value = None
+ if isinstance(expr, gdb.Value):
+ value = expr
+ else:
+ try:
+ value = vdb.parse_and_eval(expr)
+ except:
+ print("Failed to evaluate '%s'" % expr)
+ return
+
+ printer = gdb.default_visualizer(value)
+ if not printer:
+ ty = value.dynamic_type
+ if ty.code == gdb.TYPE_CODE_STRUCT or (ty.code == gdb.TYPE_CODE_PTR and ty.target().code == gdb.TYPE_CODE_STRUCT):
+ from vdb.printing import CxxPrettyPrinter
+ printer = CxxPrettyPrinter(value)
+
+ if not printer:
+ print("%s (%s)" % ( value, value.dynamic_type))
+ else:
+ print("%s (%s)" % ( printer.to_string(), value.dynamic_type))
+ for name, child in printer.children():
+ pp = gdb.default_visualizer(child)
+ if pp == None:
+ print(" %-20s: %s (%s)" % ( name , child, child.dynamic_type ))
+ else:
+ try:
+ print(" %-20s: %s (%s)" % ( name , pp.to_string(), child.dynamic_type ))
+ except Exception as e:
+ print(" %-20s: %s (%s) <error: %s>" % ( name , child, child.dynamic_type, e ))
+
+
+do = __DumpObjectCmd('do', gdb.COMMAND_DATA)
--- a/python/vdb/printing.py Wed May 25 17:02:01 2022 +0100
+++ b/python/vdb/printing.py Wed May 25 17:03:30 2022 +0100
@@ -58,7 +58,10 @@
self._val = val.cast(self._type)
def to_string(self):
- return self._val.format_string(raw = True)
+ if self._val.type.code == gdb.TYPE_CODE_PTR:
+ return "(%s) 0x%x" % ( self._type, int(self._val) )
+ else:
+ return "(%s) ... " % ( self._type )
def fields_of(self, ty):
return filter(lambda f : f.is_base_class == False and f.artificial == False, ty.fields())
@@ -83,6 +86,19 @@
return map(lambda f : (f.name , val[f.name] ), self.fields())
+class CxxPtrPrettyPrinter():
+ """
+ A custom pretty printer for printing pointers (to C++ types)
+ """
+ def __init__(self, val, contents_visualizer):
+ assert val.type.code == gdb.TYPE_CODE_PTR
+ self._val = val
+ self.contents_visualizer = contents_visualizer
+
+ def to_string(self):
+ return self.contents_visualizer(self._val).to_string()
+
+
class CxxNullptrPrettyPrinter():
"""
A custom pretty printer for NULL / nullptr values.
@@ -141,8 +157,11 @@
# is NULL or not.
#
# Note, that C++ defines nullptr having value of 0
- if val.dynamic_type.code == gdb.TYPE_CODE_PTR and int(val) == 0x0:
- return CxxNullptrPrettyPrinter(val)
+ if val.dynamic_type.code == gdb.TYPE_CODE_PTR:
+ if int(val) == 0x0:
+ return CxxNullptrPrettyPrinter(val)
+ else:
+ return CxxPtrPrettyPrinter(val, self.printer)
if self.printer is not None:
return self.printer(val)
--- a/vdbinit.st Wed May 25 17:02:01 2022 +0100
+++ b/vdbinit.st Wed May 25 17:03:30 2022 +0100
@@ -6,14 +6,27 @@
"/ Load plugins.
"/
-"/ Smalltalk loadPackage: 'jv:vdb/plugins/bee'
+"/ Smalltalk loadPackage: 'jv:vdb/plugins/xyz'
"/ Set console prompt
"/
"/ vdb debugger send: 'set prompt vdb > '.
+"/ Set light mode (theme)
+"/
+"/ View defaultStyle:#'Adwaita'.
+"/ UserPreferences current codeViewTheme: Solarized new. "/ choose one...
+"/ UserPreferences current codeViewTheme: nil. "/ ...or the other
+"/
+"/ Set dark mode
+"/
+"/ View defaultStyle:#'Adwaita_dark'.
+"/ UserPreferences current codeViewTheme: SolarizedDark new. "/ choose one...
+"/ UserPreferences current codeViewTheme: Monokai new. "/ ...or the other
+
+
"/ Set default text font for all text and list views
-"/
+"/
"/ VDBAbstractApplication defaultTextFont: (FontDescription family:#'DejaVu Sans Mono' face:#normal size:12).
"/ VDBAbstractApplication defaultTextFont: (CodeView defaultFont asSize: 16).