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().