Difference between revisions of "Python pretty-printer for gdb"
(Created page with "If gdb (GNU debugger) was compiled with Python support, it is possible to run Python scripts within gdb. Below is an example of how to create a custom pretty-printer for Veri...") |
|||
Line 1: | Line 1: | ||
− | If gdb (GNU debugger) was compiled with Python support, it is possible to run Python scripts within gdb. Below is an example of how to create a custom pretty-printer for Verific's | + | 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 | The Python script itself looks like this |
Revision as of 10:10, 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().