Difference between revisions of "Python pretty-printer for gdb"
Line 58: | Line 58: | ||
Breakpoint 1, main (argc=1, argv=0x7fffffffe0b8) at test.cpp:62 | Breakpoint 1, main (argc=1, argv=0x7fffffffe0b8) at test.cpp:62 | ||
62 Message::PrintLine(" initial value: ", Strings::itoa(int_val)) ; | 62 Message::PrintLine(" initial value: ", Strings::itoa(int_val)) ; | ||
− | (gdb) | + | (gdb) p *module_item |
$1 = {<Verific::VeriTreeNode> = {<Verific::VeriNode> = { | $1 = {<Verific::VeriTreeNode> = {<Verific::VeriNode> = { | ||
_vptr.VeriNode = 0x5555565bcd18 <vtable for Verific::VeriDataDecl+16>, static _present_scope = 0x0, | _vptr.VeriNode = 0x5555565bcd18 <vtable for Verific::VeriDataDecl+16>, static _present_scope = 0x0, | ||
Line 80: | Line 80: | ||
static _unnamedscope_vs_decl_ids = 0x0, static _check_linefile_of_import = 1}, _linefile = 8589934594}, | static _unnamedscope_vs_decl_ids = 0x0, static _check_linefile_of_import = 1}, _linefile = 8589934594}, | ||
_qualifiers = 0} | _qualifiers = 0} | ||
− | (gdb) | + | (gdb) p *val |
$2 = {_vptr.VeriBaseValue = 0x55555654b280 <vtable for Verific::VeriInteger+16>} | $2 = {_vptr.VeriBaseValue = 0x55555654b280 <vtable for Verific::VeriInteger+16>} | ||
− | (gdb) | + | (gdb) source verific_pp.py |
− | (gdb) | + | (gdb) p *module_item |
$3 = parameter P1 = 8 ; | $3 = parameter P1 = 8 ; | ||
− | (gdb) | + | (gdb) p *val |
$4 = 8 | $4 = 8 | ||
(gdb) | (gdb) | ||
</nowiki> | </nowiki> | ||
Notice how before activating the Python pretty-printer, gdb prints out a lot of information when calling 'p *module_item' or 'p *val' . With the pretty-printer, it now prints only the value from GetPrettyPrintedString(). | Notice how before activating the Python pretty-printer, gdb prints out a lot of information when calling 'p *module_item' or 'p *val' . With the pretty-printer, it now prints only the value from GetPrettyPrintedString(). |
Latest revision as of 10:28, 13 September 2022
If gdb (GNU debugger) was compiled with Python support, it is possible to run Python scripts from within gdb. Below is an example of how to create a custom pretty-printer for Verific's VeriTreeNode using gdb's Python interface.
The Python script itself looks like this
import gdb import re class VeriVhdlTreeNodePrinter: def __init__(self, val): self.val = val def to_string(self): eval_string = f"(({self.val.type.name}*){self.val.address})->GetPrettyPrintedString()" return gdb.parse_and_eval(eval_string).string() def verific_pp_func(val): lookup_tag = val.type.tag if lookup_tag is None: return None regex = re.compile("^(Verific::)?(Veri|Vhdl)(\w)+$") if regex.match(lookup_tag): return VeriVhdlTreeNodePrinter(val) return None gdb.pretty_printers.append(verific_pp_func)
To automate sourcing of the Python script on gdb startup, add the following line to your ~/.gdbinit :
source ~/verific_pp.py
The script calls Verific's GetPrettyPrintedString() API which essentially pretty prints the VeriTreeNode. It takes an object and not a pointer. Printing the pointer will still print the value of the pointer as per usual gdb behavior.
Note that if a class has a name starting with Veri but is not derived from VeriTreeNode, gdb produces the following message :
(gdb) print *pointer_to_VeriLibrary_which_is_not_derived_from_VeriTreeNode $2 = Python Exception <class 'gdb.error'> Couldn't find method VeriLibrary::GetPrettyPrintedString: (gdb)
The same will happen for VeriValue/VhdlValue/VeriBaseValue, etc, because these classes do not have the GetPrettyPrintedString() API. The pretty printer can be customized to exclude such classes, or modified to handle these other cases. This is just a regular regex rule.
Here is the output from an example run :
gdb ./test-linux-g Reading symbols from test-linux-g... (gdb) break 62 Breakpoint 1 at 0x306b50: file test.cpp, line 62. (gdb) run Starting program: test-linux-g [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". -- Analyzing Verilog file 'test.v' (VERI-1482) test.v(1): INFO: compiling module 'top' (VERI-1018) -- module: top -- param: P1 -- initial expression: 8 Breakpoint 1, main (argc=1, argv=0x7fffffffe0b8) at test.cpp:62 62 Message::PrintLine(" initial value: ", Strings::itoa(int_val)) ; (gdb) p *module_item $1 = {<Verific::VeriTreeNode> = {<Verific::VeriNode> = { _vptr.VeriNode = 0x5555565bcd18 <vtable for Verific::VeriDataDecl+16>, static _present_scope = 0x0, static _container_scope_arr = 0x0, static _sva_clock_expr = 0x0, static _default_clock = 0x0, static _default_disable_iff_cond = 0x0, static _has_disable_iff = 0, static _id_ref = 0x0, static _name_list = 0x0, static _inside_clocked_sequence = 0, static _contains_event_control = 0, static _contains_delay_control = 0, static _contains_even_id_in_body = 0, static _multiple_inferred_clock = 0, static _in_property_expr = 0, static _in_checker = 0, static _in_fork_join_none_or_any = 0, static _in_bind_directive = 0, static _hier_name_to_allow_mod_name = 0, static _do_not_recurse_packed_dims = 0, static _processing_param = 0x0, static _processing_expr = 0x0, static _msgs = 0x55555666b870, static _relaxed_msgs = 0x0, static _udp_edge_chars = 0x0, static _verilog_keywords = 0x0, static _verilog_tokens = 0x0, static _system_tasks = 0x0, static _ref_count_map = 0x0, static _attribute_map = 0x0, static _map_of_comment_arr = 0x0, static _global_clocking = 0x0, static _var_usage_running = 0, static _is_static_elab = 0, static _is_rtl_elab = 0, static _func_pointer_stack = 0x0, static _func_stack = 0x0, static _mutual_recursion_count = 0, static _max_mutual_recursion_count = 0, static _within_seq_area = 0, static _within_generate_endgenerate = 0, static _under_default_clock = 0, static _default_disable_defined = 0, static _has_delay_or_event_control = 0, static _processing_operand = 0, static _potential_always_loop = 0, static _reresolve_idrefs = 0, static _ignore_ams_in_rtl_elab = 0, static _follow_lrm_for_constant_func = 0, static _evaluated_vals = 0x0, static _evaluated_constraints = 0x0, static _p_evaluated_vals = 0x0, static _p_evaluated_constraints = 0x0, static _unnamedscope_vs_decl_ids = 0x0, static _check_linefile_of_import = 1}, _linefile = 8589934594}, _qualifiers = 0} (gdb) p *val $2 = {_vptr.VeriBaseValue = 0x55555654b280 <vtable for Verific::VeriInteger+16>} (gdb) source verific_pp.py (gdb) p *module_item $3 = parameter P1 = 8 ; (gdb) p *val $4 = 8 (gdb)
Notice how before activating the Python pretty-printer, gdb prints out a lot of information when calling 'p *module_item' or 'p *val' . With the pretty-printer, it now prints only the value from GetPrettyPrintedString().