1163953Srrs# Python hooks for gdb for debugging GCC 2169382Srrs# Copyright (C) 2013-2022 Free Software Foundation, Inc. 3163953Srrs 4163953Srrs# Contributed by David Malcolm <dmalcolm@redhat.com> 5163953Srrs 6163953Srrs# This file is part of GCC. 7163953Srrs 8163953Srrs# GCC is free software; you can redistribute it and/or modify it under 9163953Srrs# the terms of the GNU General Public License as published by the Free 10163953Srrs# Software Foundation; either version 3, or (at your option) any later 11163953Srrs# version. 12163953Srrs 13163953Srrs# GCC is distributed in the hope that it will be useful, but WITHOUT 14163953Srrs# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15163953Srrs# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16163953Srrs# for more details. 17163953Srrs 18163953Srrs# You should have received a copy of the GNU General Public License 19163953Srrs# along with GCC; see the file COPYING3. If not see 20163953Srrs# <http://www.gnu.org/licenses/>. 21163953Srrs 22163953Srrs""" 23163953SrrsEnabling the debugging hooks 24163953Srrs---------------------------- 25163953Srrsgcc/configure (from configure.ac) generates a .gdbinit within the "gcc" 26163953Srrssubdirectory of the build directory, and when run by gdb, this imports 27163953Srrsgcc/gdbhooks.py from the source directory, injecting useful Python code 28163953Srrsinto gdb. 29163953Srrs 30163953SrrsYou may see a message from gdb of the form: 31163954Srrs "path-to-build/gcc/.gdbinit" auto-loading has been declined by your `auto-load safe-path' 32163953Srrsas a protection against untrustworthy python scripts. See 33163953Srrs http://sourceware.org/gdb/onlinedocs/gdb/Auto_002dloading-safe-path.html 34168709Srrs 35166086SrrsThe fix is to mark the paths of the build/gcc directory as trustworthy. 36163953SrrsAn easy way to do so is by adding the following to your ~/.gdbinit script: 37163953Srrs add-auto-load-safe-path /absolute/path/to/build/gcc 38163953Srrsfor the build directories for your various checkouts of gcc. 39163953Srrs 40168709SrrsIf it's working, you should see the message: 41168709Srrs Successfully loaded GDB hooks for GCC 42168709Srrsas gdb starts up. 43167598Srrs 44163953SrrsDuring development, I've been manually invoking the code in this way, as a 45166086Srrsprecanned way of printing a variety of different kinds of value: 46163953Srrs 47166086Srrs gdb \ 48166086Srrs -ex "break expand_gimple_stmt" \ 49166086Srrs -ex "run" \ 50166086Srrs -ex "bt" \ 51168709Srrs --args \ 52168709Srrs ./cc1 foo.c -O3 53170091Srrs 54163953SrrsExamples of output using the pretty-printers 55171167Sgnn-------------------------------------------- 56171133SgnnPointer values are generally shown in the form: 57171133Sgnn <type address extra_info> 58171133Sgnn 59171133SgnnFor example, an opt_pass* might appear as: 60171167Sgnn (gdb) p pass 61163953Srrs $2 = <opt_pass* 0x188b600 "expand"(170)> 62163953Srrs 63163953SrrsThe name of the pass is given ("expand"), together with the 64163953Srrsstatic_pass_number. 65171259Sdelphij 66163953SrrsNote that you can dereference the pointer in the normal way: 67165647Srrs (gdb) p *pass 68163953Srrs $4 = {type = RTL_PASS, name = 0x120a312 "expand", 69163953Srrs [etc, ...snipped...] 70163953Srrs 71163953Srrsand you can suppress pretty-printers using /r (for "raw"): 72163953Srrs (gdb) p /r pass 73169352Srrs $3 = (opt_pass *) 0x188b600 74170181Srrs 75163953SrrsBasic blocks are shown with their index in parentheses, apart from the 76163953SrrsCFG's entry and exit blocks, which are given as "ENTRY" and "EXIT": 77163953Srrs (gdb) p bb 78168299Srrs $9 = <basic_block 0x7ffff041f1a0 (2)> 79163953Srrs (gdb) p cfun->cfg->x_entry_block_ptr 80170056Srrs $10 = <basic_block 0x7ffff041f0d0 (ENTRY)> 81163953Srrs (gdb) p cfun->cfg->x_exit_block_ptr 82163953Srrs $11 = <basic_block 0x7ffff041f138 (EXIT)> 83169352Srrs 84169352SrrsCFG edges are shown with the src and dest blocks given in parentheses: 85169352Srrs (gdb) p e 86169352Srrs $1 = <edge 0x7ffff043f118 (ENTRY -> 6)> 87169352Srrs 88168709SrrsTree nodes are printed using Python code that emulates print_node_brief, 89170056Srrsrunning in gdb, rather than in the inferior: 90165647Srrs (gdb) p cfun->decl 91170091Srrs $1 = <function_decl 0x7ffff0420b00 foo> 92170091SrrsFor usability, the type is printed first (e.g. "function_decl"), rather 93170091Srrsthan just "tree". 94163953Srrs 95163953SrrsRTL expressions use a kludge: they are pretty-printed by injecting 96170056Srrscalls into print-rtl.c into the inferior: 97170056Srrs Value returned is $1 = (note 9 8 10 [bb 3] NOTE_INSN_BASIC_BLOCK) 98163953Srrs (gdb) p $1 99163953Srrs $2 = (note 9 8 10 [bb 3] NOTE_INSN_BASIC_BLOCK) 100163953Srrs (gdb) p /r $1 101163953Srrs $3 = (rtx_def *) 0x7ffff043e140 102163953SrrsThis won't work for coredumps, and probably in other circumstances, but 103163953Srrsit's a quick way of getting lots of debuggability quickly. 104163953Srrs 105170859SrrsCallgraph nodes are printed with the name of the function decl, if 106170859Srrsavailable: 107163953Srrs (gdb) frame 5 108170859Srrs #5 0x00000000006c288a in expand_function (node=<cgraph_node* 0x7ffff0312720 "foo"/12345>) at ../../src/gcc/cgraphunit.c:1594 109163953Srrs 1594 execute_pass_list (g->get_passes ()->all_passes); 110163953Srrs (gdb) p node 111163953Srrs $1 = <cgraph_node* 0x7ffff0312720 "foo"/12345> 112163953Srrs 113163953SrrsSimilarly for symtab_node and varpool_node classes. 114163953Srrs 115163953SrrsCgraph edges are printed with the name of caller and callee: 116163953Srrs (gdb) p this->callees 117163953Srrs $4 = <cgraph_edge* 0x7fffe25aa000 (<cgraph_node * 0x7fffe62b22e0 "_GLOBAL__sub_I__ZN5Pooma5pinfoE"/19660> -> <cgraph_node * 0x7fffe620f730 "__static_initialization_and_destruction_1"/19575>)> 118169420Srrs 119170056SrrsIPA reference follow very similar format: 120163953Srrs (gdb) Value returned is $5 = <ipa_ref* 0x7fffefcb80c8 (<symtab_node * 0x7ffff562f000 "__dt_base "/875> -> <symtab_node * 0x7fffe795f000 "_ZTVN6Smarts8RunnableE"/16056>:IPA_REF_ADDR)> 121163953Srrs 122163953Srrsvec<> pointers are printed as the address followed by the elements in 123163953Srrsbraces. Here's a length 2 vec: 124163953Srrs (gdb) p bb->preds 125163953Srrs $18 = 0x7ffff0428b68 = {<edge 0x7ffff044d380 (3 -> 5)>, <edge 0x7ffff044d3b8 (4 -> 5)>} 126163953Srrs 127163953Srrsand here's a length 1 vec: 128165647Srrs (gdb) p bb->succs 129163953Srrs $19 = 0x7ffff0428bb8 = {<edge 0x7ffff044d3f0 (5 -> EXIT)>} 130163953Srrs 131163953SrrsYou cannot yet use array notation [] to access the elements within the 132163953Srrsvector: attempting to do so instead gives you the vec itself (for vec[0]), 133163953Srrsor a (probably) invalid cast to vec<> for the memory after the vec (for 134163953Srrsvec[1] onwards). 135163953Srrs 136163953SrrsInstead (for now) you must access m_vecdata: 137163953Srrs (gdb) p bb->preds->m_vecdata[0] 138163953Srrs $20 = <edge 0x7ffff044d380 (3 -> 5)> 139163953Srrs (gdb) p bb->preds->m_vecdata[1] 140163953Srrs $21 = <edge 0x7ffff044d3b8 (4 -> 5)> 141163953Srrs""" 142163953Srrsimport os.path 143163953Srrsimport re 144163953Srrsimport sys 145163953Srrsimport tempfile 146169420Srrs 147169420Srrsimport gdb 148163953Srrsimport gdb.printing 149168299Srrsimport gdb.types 150163953Srrs 151163953Srrs# Convert "enum tree_code" (tree.def and tree.h) to a dict: 152163953Srrstree_code_dict = gdb.types.make_enum_dict(gdb.lookup_type('enum tree_code')) 153163953Srrs 154163953Srrs# ...and look up specific values for use later: 155163953SrrsIDENTIFIER_NODE = tree_code_dict['IDENTIFIER_NODE'] 156163953SrrsTYPE_DECL = tree_code_dict['TYPE_DECL'] 157163953SrrsSSA_NAME = tree_code_dict['SSA_NAME'] 158163953Srrs 159163953Srrs# Similarly for "enum tree_code_class" (tree.h): 160163953Srrstree_code_class_dict = gdb.types.make_enum_dict(gdb.lookup_type('enum tree_code_class')) 161163953Srrstcc_type = tree_code_class_dict['tcc_type'] 162165647Srrstcc_declaration = tree_code_class_dict['tcc_declaration'] 163163953Srrs 164163953Srrs# Python3 has int() with arbitrary precision (bignum). Python2 int() is 32-bit 165163953Srrs# on 32-bit hosts but remote targets may have 64-bit pointers there; Python2 166163953Srrs# long() is always 64-bit but Python3 no longer has anything named long. 167163953Srrsdef intptr(gdbval): 168163953Srrs return long(gdbval) if sys.version_info.major == 2 else int(gdbval) 169163953Srrs 170168299Srrsclass Tree: 171163953Srrs """ 172163953Srrs Wrapper around a gdb.Value for a tree, with various methods 173163953Srrs corresponding to macros in gcc/tree.h 174163953Srrs """ 175163953Srrs def __init__(self, gdbval): 176163953Srrs self.gdbval = gdbval 177163953Srrs 178163953Srrs def is_nonnull(self): 179163953Srrs return intptr(self.gdbval) 180163953Srrs 181163953Srrs def TREE_CODE(self): 182163953Srrs """ 183163953Srrs Get gdb.Value corresponding to TREE_CODE (self) 184168299Srrs as per: 185169420Srrs #define TREE_CODE(NODE) ((enum tree_code) (NODE)->base.code) 186169420Srrs """ 187169420Srrs return self.gdbval['base']['code'] 188169420Srrs 189163953Srrs def DECL_NAME(self): 190165220Srrs """ 191170181Srrs Get Tree instance corresponding to DECL_NAME (self) 192165220Srrs """ 193165220Srrs return Tree(self.gdbval['decl_minimal']['name']) 194165220Srrs 195165220Srrs def TYPE_NAME(self): 196165220Srrs """ 197165220Srrs Get Tree instance corresponding to result of TYPE_NAME (self) 198170181Srrs """ 199163953Srrs return Tree(self.gdbval['type_common']['name']) 200163953Srrs 201163953Srrs def IDENTIFIER_POINTER(self): 202163953Srrs """ 203163953Srrs Get str correspoinding to result of IDENTIFIER_NODE (self) 204171167Sgnn """ 205163953Srrs return self.gdbval['identifier']['id']['str'].string() 206163953Srrs 207163953Srrsclass TreePrinter: 208163996Srrs "Prints a tree" 209163953Srrs 210163953Srrs def __init__ (self, gdbval): 211163953Srrs self.gdbval = gdbval 212163996Srrs self.node = Tree(gdbval) 213171167Sgnn 214163953Srrs def to_string (self): 215163953Srrs # like gcc/print-tree.c:print_node_brief 216163953Srrs # #define TREE_CODE(NODE) ((enum tree_code) (NODE)->base.code) 217163953Srrs # tree_code_name[(int) TREE_CODE (node)]) 218163953Srrs if intptr(self.gdbval) == 0: 219163953Srrs return '<tree 0x0>' 220165647Srrs 221165647Srrs val_TREE_CODE = self.node.TREE_CODE() 222165647Srrs 223165647Srrs # extern const enum tree_code_class tree_code_type[]; 224169655Srrs # #define TREE_CODE_CLASS(CODE) tree_code_type[(int) (CODE)] 225169378Srrs 226170181Srrs if val_TREE_CODE == 0xa5a5: 227163953Srrs return '<ggc_freed 0x%x>' % intptr(self.gdbval) 228163953Srrs 229163953Srrs val_tree_code_type = gdb.parse_and_eval('tree_code_type') 230169352Srrs val_tclass = val_tree_code_type[val_TREE_CODE] 231163953Srrs 232163953Srrs val_tree_code_name = gdb.parse_and_eval('tree_code_name') 233163953Srrs val_code_name = val_tree_code_name[intptr(val_TREE_CODE)] 234163953Srrs #print(val_code_name.string()) 235163953Srrs 236163953Srrs try: 237163953Srrs result = '<%s 0x%x' % (val_code_name.string(), intptr(self.gdbval)) 238163953Srrs except: 239163953Srrs return '<tree 0x%x>' % intptr(self.gdbval) 240169420Srrs if intptr(val_tclass) == tcc_declaration: 241163953Srrs tree_DECL_NAME = self.node.DECL_NAME() 242169420Srrs if tree_DECL_NAME.is_nonnull(): 243163953Srrs result += ' %s' % tree_DECL_NAME.IDENTIFIER_POINTER() 244163953Srrs else: 245163953Srrs pass # TODO: labels etc 246163953Srrs elif intptr(val_tclass) == tcc_type: 247163953Srrs tree_TYPE_NAME = Tree(self.gdbval['type_common']['name']) 248163953Srrs if tree_TYPE_NAME.is_nonnull(): 249163953Srrs if tree_TYPE_NAME.TREE_CODE() == IDENTIFIER_NODE: 250169352Srrs result += ' %s' % tree_TYPE_NAME.IDENTIFIER_POINTER() 251163953Srrs elif tree_TYPE_NAME.TREE_CODE() == TYPE_DECL: 252163953Srrs if tree_TYPE_NAME.DECL_NAME().is_nonnull(): 253163953Srrs result += ' %s' % tree_TYPE_NAME.DECL_NAME().IDENTIFIER_POINTER() 254163953Srrs if self.node.TREE_CODE() == IDENTIFIER_NODE: 255163953Srrs result += ' %s' % self.node.IDENTIFIER_POINTER() 256171259Sdelphij elif self.node.TREE_CODE() == SSA_NAME: 257171259Sdelphij result += ' %u' % self.gdbval['base']['u']['version'] 258163953Srrs # etc 259168299Srrs result += '>' 260163953Srrs return result 261163953Srrs 262163953Srrs###################################################################### 263163953Srrs# Callgraph pretty-printers 264163953Srrs###################################################################### 265163953Srrs 266163953Srrsclass SymtabNodePrinter: 267163953Srrs def __init__(self, gdbval): 268163953Srrs self.gdbval = gdbval 269163953Srrs 270163953Srrs def to_string (self): 271163953Srrs t = str(self.gdbval.type) 272163953Srrs result = '<%s 0x%x' % (t, intptr(self.gdbval)) 273163953Srrs if intptr(self.gdbval): 274163953Srrs # symtab_node::name calls lang_hooks.decl_printable_name 275163953Srrs # default implementation (lhd_decl_printable_name) is: 276163953Srrs # return IDENTIFIER_POINTER (DECL_NAME (decl)); 277163953Srrs tree_decl = Tree(self.gdbval['decl']) 278163953Srrs result += ' "%s"/%d' % (tree_decl.DECL_NAME().IDENTIFIER_POINTER(), self.gdbval['order']) 279163953Srrs result += '>' 280163953Srrs return result 281165220Srrs 282163953Srrsclass CgraphEdgePrinter: 283163953Srrs def __init__(self, gdbval): 284163953Srrs self.gdbval = gdbval 285163953Srrs 286163953Srrs def to_string (self): 287163953Srrs result = '<cgraph_edge* 0x%x' % intptr(self.gdbval) 288163953Srrs if intptr(self.gdbval): 289163953Srrs src = SymtabNodePrinter(self.gdbval['caller']).to_string() 290163953Srrs dest = SymtabNodePrinter(self.gdbval['callee']).to_string() 291163953Srrs result += ' (%s -> %s)' % (src, dest) 292163953Srrs result += '>' 293163953Srrs return result 294163953Srrs 295163953Srrsclass IpaReferencePrinter: 296168299Srrs def __init__(self, gdbval): 297163953Srrs self.gdbval = gdbval 298163953Srrs 299163953Srrs def to_string (self): 300163953Srrs result = '<ipa_ref* 0x%x' % intptr(self.gdbval) 301168299Srrs if intptr(self.gdbval): 302163953Srrs src = SymtabNodePrinter(self.gdbval['referring']).to_string() 303163953Srrs dest = SymtabNodePrinter(self.gdbval['referred']).to_string() 304163953Srrs result += ' (%s -> %s:%s)' % (src, dest, str(self.gdbval['use'])) 305163953Srrs result += '>' 306163953Srrs return result 307163953Srrs 308163953Srrs###################################################################### 309163953Srrs# Dwarf DIE pretty-printers 310163953Srrs###################################################################### 311163953Srrs 312163953Srrsclass DWDieRefPrinter: 313163953Srrs def __init__(self, gdbval): 314163953Srrs self.gdbval = gdbval 315163953Srrs 316163953Srrs def to_string (self): 317163953Srrs if intptr(self.gdbval) == 0: 318163953Srrs return '<dw_die_ref 0x0>' 319163953Srrs result = '<dw_die_ref 0x%x' % intptr(self.gdbval) 320163953Srrs result += ' %s' % self.gdbval['die_tag'] 321163953Srrs if intptr(self.gdbval['die_parent']) != 0: 322163953Srrs result += ' <parent=0x%x %s>' % (intptr(self.gdbval['die_parent']), 323169420Srrs self.gdbval['die_parent']['die_tag']) 324163953Srrs 325169420Srrs result += '>' 326163953Srrs return result 327163953Srrs 328163953Srrs###################################################################### 329163953Srrs 330171259Sdelphijclass GimplePrinter: 331163953Srrs def __init__(self, gdbval): 332163953Srrs self.gdbval = gdbval 333163953Srrs 334167598Srrs def to_string (self): 335166086Srrs if intptr(self.gdbval) == 0: 336163953Srrs return '<gimple 0x0>' 337167598Srrs val_gimple_code = self.gdbval['code'] 338167598Srrs val_gimple_code_name = gdb.parse_and_eval('gimple_code_name') 339163953Srrs val_code_name = val_gimple_code_name[intptr(val_gimple_code)] 340163953Srrs result = '<%s 0x%x' % (val_code_name.string(), 341163953Srrs intptr(self.gdbval)) 342163953Srrs result += '>' 343163953Srrs return result 344163953Srrs 345163953Srrs###################################################################### 346163953Srrs# CFG pretty-printers 347163953Srrs###################################################################### 348163953Srrs 349163953Srrsdef bb_index_to_str(index): 350163953Srrs if index == 0: 351163953Srrs return 'ENTRY' 352163953Srrs elif index == 1: 353163953Srrs return 'EXIT' 354163953Srrs else: 355163953Srrs return '%i' % index 356163953Srrs 357163953Srrsclass BasicBlockPrinter: 358163953Srrs def __init__(self, gdbval): 359163953Srrs self.gdbval = gdbval 360163953Srrs 361163953Srrs def to_string (self): 362163953Srrs result = '<basic_block 0x%x' % intptr(self.gdbval) 363163953Srrs if intptr(self.gdbval): 364163953Srrs result += ' (%s)' % bb_index_to_str(intptr(self.gdbval['index'])) 365163953Srrs result += '>' 366163953Srrs return result 367163953Srrs 368165647Srrsclass CfgEdgePrinter: 369163953Srrs def __init__(self, gdbval): 370163953Srrs self.gdbval = gdbval 371163953Srrs 372163953Srrs def to_string (self): 373163953Srrs result = '<edge 0x%x' % intptr(self.gdbval) 374163953Srrs if intptr(self.gdbval): 375163953Srrs src = bb_index_to_str(intptr(self.gdbval['src']['index'])) 376163953Srrs dest = bb_index_to_str(intptr(self.gdbval['dest']['index'])) 377163953Srrs result += ' (%s -> %s)' % (src, dest) 378163953Srrs result += '>' 379163953Srrs return result 380163953Srrs 381163953Srrs###################################################################### 382163953Srrs 383163953Srrsclass Rtx: 384167598Srrs def __init__(self, gdbval): 385163953Srrs self.gdbval = gdbval 386163953Srrs 387163953Srrs def GET_CODE(self): 388163953Srrs return self.gdbval['code'] 389163953Srrs 390163953Srrsdef GET_RTX_LENGTH(code): 391163953Srrs val_rtx_length = gdb.parse_and_eval('rtx_length') 392163953Srrs return intptr(val_rtx_length[code]) 393163953Srrs 394163953Srrsdef GET_RTX_NAME(code): 395163953Srrs val_rtx_name = gdb.parse_and_eval('rtx_name') 396163953Srrs return val_rtx_name[code].string() 397163953Srrs 398163953Srrsdef GET_RTX_FORMAT(code): 399163953Srrs val_rtx_format = gdb.parse_and_eval('rtx_format') 400163953Srrs return val_rtx_format[code].string() 401163953Srrs 402163953Srrsclass RtxPrinter: 403163953Srrs def __init__(self, gdbval): 404163953Srrs self.gdbval = gdbval 405163953Srrs self.rtx = Rtx(gdbval) 406163953Srrs 407163953Srrs def to_string (self): 408163953Srrs """ 409163953Srrs For now, a cheap kludge: invoke the inferior's print 410163953Srrs function to get a string to use the user, and return an empty 411163953Srrs string for gdb 412163953Srrs """ 413163953Srrs # We use print_inline_rtx to avoid a trailing newline 414163953Srrs gdb.execute('call print_inline_rtx (stderr, (const_rtx) %s, 0)' 415163953Srrs % intptr(self.gdbval)) 416163953Srrs return '' 417163953Srrs 418163953Srrs # or by hand; based on gcc/print-rtl.c:print_rtx 419163953Srrs result = ('<rtx_def 0x%x' 420163953Srrs % (intptr(self.gdbval))) 421163953Srrs code = self.rtx.GET_CODE() 422163953Srrs result += ' (%s' % GET_RTX_NAME(code) 423163953Srrs format_ = GET_RTX_FORMAT(code) 424163953Srrs for i in range(GET_RTX_LENGTH(code)): 425163953Srrs print(format_[i]) 426163953Srrs result += ')>' 427163953Srrs return result 428163953Srrs 429164085Srrs###################################################################### 430163953Srrs 431163953Srrsclass PassPrinter: 432163953Srrs def __init__(self, gdbval): 433163953Srrs self.gdbval = gdbval 434164085Srrs 435167598Srrs def to_string (self): 436163953Srrs result = '<opt_pass* 0x%x' % intptr(self.gdbval) 437167598Srrs if intptr(self.gdbval): 438167598Srrs result += (' "%s"(%i)' 439170587Srwatson % (self.gdbval['name'].string(), 440163953Srrs intptr(self.gdbval['static_pass_number']))) 441163953Srrs result += '>' 442163953Srrs return result 443163953Srrs 444163953Srrs###################################################################### 445163953Srrs 446163953Srrsclass VecPrinter: 447163953Srrs # -ex "up" -ex "p bb->preds" 448163953Srrs def __init__(self, gdbval): 449163953Srrs self.gdbval = gdbval 450163953Srrs 451163953Srrs def display_hint (self): 452163953Srrs return 'array' 453167598Srrs 454163953Srrs def to_string (self): 455164085Srrs # A trivial implementation; prettyprinting the contents is done 456164085Srrs # by gdb calling the "children" method below. 457163953Srrs return '0x%x' % intptr(self.gdbval) 458163953Srrs 459164085Srrs def children (self): 460163953Srrs if intptr(self.gdbval) == 0: 461164085Srrs return 462163953Srrs m_vecpfx = self.gdbval['m_vecpfx'] 463163953Srrs m_num = m_vecpfx['m_num'] 464163953Srrs m_vecdata = self.gdbval['m_vecdata'] 465164085Srrs for i in range(m_num): 466164085Srrs yield ('[%d]' % i, m_vecdata[i]) 467164085Srrs 468164085Srrs###################################################################### 469164085Srrs 470164085Srrsclass MachineModePrinter: 471164085Srrs def __init__(self, gdbval): 472164085Srrs self.gdbval = gdbval 473164085Srrs 474164085Srrs def to_string (self): 475164085Srrs name = str(self.gdbval['m_mode']) 476164085Srrs return name[2:] if name.startswith('E_') else name 477164085Srrs 478164085Srrs###################################################################### 479164085Srrs 480164085Srrsclass OptMachineModePrinter: 481163953Srrs def __init__(self, gdbval): 482163953Srrs self.gdbval = gdbval 483163953Srrs 484163953Srrs def to_string (self): 485163953Srrs name = str(self.gdbval['m_mode']) 486163953Srrs if name == 'E_VOIDmode': 487163953Srrs return '<None>' 488163953Srrs return name[2:] if name.startswith('E_') else name 489163953Srrs 490163953Srrs###################################################################### 491163953Srrs 492163953Srrs# TODO: 493163953Srrs# * hashtab 494163953Srrs# * location_t 495163953Srrs 496163953Srrsclass GdbSubprinter(gdb.printing.SubPrettyPrinter): 497163953Srrs def __init__(self, name, class_): 498163953Srrs super(GdbSubprinter, self).__init__(name) 499163953Srrs self.class_ = class_ 500163953Srrs 501163953Srrs def handles_type(self, str_type): 502163953Srrs raise NotImplementedError 503163953Srrs 504163953Srrsclass GdbSubprinterTypeList(GdbSubprinter): 505163953Srrs """ 506163953Srrs A GdbSubprinter that handles a specific set of types 507163953Srrs """ 508163953Srrs def __init__(self, str_types, name, class_): 509163953Srrs super(GdbSubprinterTypeList, self).__init__(name, class_) 510169380Srrs self.str_types = frozenset(str_types) 511169380Srrs 512163953Srrs def handles_type(self, str_type): 513167695Srrs return str_type in self.str_types 514163953Srrs 515163953Srrsclass GdbSubprinterRegex(GdbSubprinter): 516163953Srrs """ 517163953Srrs A GdbSubprinter that handles types that match a regex 518167695Srrs """ 519167695Srrs def __init__(self, regex, name, class_): 520163953Srrs super(GdbSubprinterRegex, self).__init__(name, class_) 521163953Srrs self.regex = re.compile(regex) 522163953Srrs 523163953Srrs def handles_type(self, str_type): 524163953Srrs return self.regex.match(str_type) 525163953Srrs 526163953Srrsclass GdbPrettyPrinters(gdb.printing.PrettyPrinter): 527163953Srrs def __init__(self, name): 528163953Srrs super(GdbPrettyPrinters, self).__init__(name, []) 529163953Srrs 530163953Srrs def add_printer_for_types(self, types, name, class_): 531163953Srrs self.subprinters.append(GdbSubprinterTypeList(types, name, class_)) 532163953Srrs 533163953Srrs def add_printer_for_regex(self, regex, name, class_): 534163953Srrs self.subprinters.append(GdbSubprinterRegex(regex, name, class_)) 535166086Srrs 536163953Srrs def __call__(self, gdbval): 537170205Srrs type_ = gdbval.type.unqualified() 538163953Srrs str_type = str(type_) 539163953Srrs for printer in self.subprinters: 540163953Srrs if printer.enabled and printer.handles_type(str_type): 541163953Srrs return printer.class_(gdbval) 542163953Srrs 543163953Srrs # Couldn't find a pretty printer (or it was disabled): 544167695Srrs return None 545163953Srrs 546163953Srrs 547163953Srrsdef build_pretty_printer(): 548170205Srrs pp = GdbPrettyPrinters('gcc') 549163953Srrs pp.add_printer_for_types(['tree', 'const_tree'], 550163953Srrs 'tree', TreePrinter) 551163953Srrs pp.add_printer_for_types(['cgraph_node *', 'varpool_node *', 'symtab_node *'], 552170205Srrs 'symtab_node', SymtabNodePrinter) 553163953Srrs pp.add_printer_for_types(['cgraph_edge *'], 554163953Srrs 'cgraph_edge', CgraphEdgePrinter) 555163953Srrs pp.add_printer_for_types(['ipa_ref *'], 556163953Srrs 'ipa_ref', IpaReferencePrinter) 557163953Srrs pp.add_printer_for_types(['dw_die_ref'], 558163953Srrs 'dw_die_ref', DWDieRefPrinter) 559163953Srrs pp.add_printer_for_types(['gimple', 'gimple *', 560163953Srrs 561163953Srrs # Keep this in the same order as gimple.def: 562163953Srrs 'gimple_cond', 'const_gimple_cond', 563163953Srrs 'gimple_statement_cond *', 564163953Srrs 'gimple_debug', 'const_gimple_debug', 565163953Srrs 'gimple_statement_debug *', 566163953Srrs 'gimple_label', 'const_gimple_label', 567163953Srrs 'gimple_statement_label *', 568163953Srrs 'gimple_switch', 'const_gimple_switch', 569163953Srrs 'gimple_statement_switch *', 570163953Srrs 'gimple_assign', 'const_gimple_assign', 571170205Srrs 'gimple_statement_assign *', 572163953Srrs 'gimple_bind', 'const_gimple_bind', 573163953Srrs 'gimple_statement_bind *', 574163953Srrs 'gimple_phi', 'const_gimple_phi', 575163953Srrs 'gimple_statement_phi *'], 576163953Srrs 577163953Srrs 'gimple', 578163953Srrs GimplePrinter) 579163953Srrs pp.add_printer_for_types(['basic_block', 'basic_block_def *'], 580166086Srrs 'basic_block', 581163953Srrs BasicBlockPrinter) 582163953Srrs pp.add_printer_for_types(['edge', 'edge_def *'], 583163953Srrs 'edge', 584163953Srrs CfgEdgePrinter) 585163953Srrs pp.add_printer_for_types(['rtx_def *'], 'rtx_def', RtxPrinter) 586170056Srrs pp.add_printer_for_types(['opt_pass *'], 'opt_pass', PassPrinter) 587170056Srrs 588170056Srrs pp.add_printer_for_regex(r'vec<(\S+), (\S+), (\S+)> \*', 589170056Srrs 'vec', 590170056Srrs VecPrinter) 591170056Srrs 592170056Srrs pp.add_printer_for_regex(r'opt_mode<(\S+)>', 593170056Srrs 'opt_mode', OptMachineModePrinter) 594170056Srrs pp.add_printer_for_types(['opt_scalar_int_mode', 595170056Srrs 'opt_scalar_float_mode', 596163953Srrs 'opt_scalar_mode'], 597163953Srrs 'opt_mode', OptMachineModePrinter) 598163953Srrs pp.add_printer_for_regex(r'pod_mode<(\S+)>', 599166023Srrs 'pod_mode', MachineModePrinter) 600163953Srrs pp.add_printer_for_types(['scalar_int_mode_pod', 601163953Srrs 'scalar_mode_pod'], 602163953Srrs 'pod_mode', MachineModePrinter) 603163953Srrs for mode in ('scalar_mode', 'scalar_int_mode', 'scalar_float_mode', 604163953Srrs 'complex_mode'): 605163953Srrs pp.add_printer_for_types([mode], mode, MachineModePrinter) 606163953Srrs 607163953Srrs return pp 608163953Srrs 609163953Srrsgdb.printing.register_pretty_printer( 610163953Srrs gdb.current_objfile(), 611163953Srrs build_pretty_printer(), 612163953Srrs replace=True) 613163953Srrs 614163953Srrsdef find_gcc_source_dir(): 615163953Srrs # Use location of global "g" to locate the source tree 616163953Srrs sym_g = gdb.lookup_global_symbol('g') 617170744Srrs path = sym_g.symtab.filename # e.g. '../../src/gcc/context.h' 618163953Srrs srcdir = os.path.split(path)[0] # e.g. '../../src/gcc' 619163953Srrs return srcdir 620163953Srrs 621163953Srrsclass PassNames: 622163953Srrs """Parse passes.def, gathering a list of pass class names""" 623163953Srrs def __init__(self): 624163953Srrs srcdir = find_gcc_source_dir() 625163953Srrs self.names = [] 626163953Srrs with open(os.path.join(srcdir, 'passes.def')) as f: 627163953Srrs for line in f: 628163953Srrs m = re.match('\s*NEXT_PASS \(([^,]+).*\);', line) 629163953Srrs if m: 630163953Srrs self.names.append(m.group(1)) 631163953Srrs 632163953Srrsclass BreakOnPass(gdb.Command): 633163953Srrs """ 634163953Srrs A custom command for putting breakpoints on the execute hook of passes. 635163953Srrs This is largely a workaround for issues with tab-completion in gdb when 636163953Srrs setting breakpoints on methods on classes within anonymous namespaces. 637170744Srrs 638163953Srrs Example of use: putting a breakpoint on "final" 639163953Srrs (gdb) break-on-pass 640163953Srrs Press <TAB>; it autocompletes to "pass_": 641163953Srrs (gdb) break-on-pass pass_ 642163953Srrs Press <TAB>: 643163953Srrs Display all 219 possibilities? (y or n) 644163953Srrs Press "n"; then type "f": 645163953Srrs (gdb) break-on-pass pass_f 646163953Srrs Press <TAB> to autocomplete to pass classnames beginning with "pass_f": 647163953Srrs pass_fast_rtl_dce pass_fold_builtins 648163953Srrs pass_feedback_split_functions pass_forwprop 649163953Srrs pass_final pass_fre 650163953Srrs pass_fixup_cfg pass_free_cfg 651163953Srrs Type "in<TAB>" to complete to "pass_final": 652163953Srrs (gdb) break-on-pass pass_final 653163953Srrs ...and hit <RETURN>: 654163953Srrs Breakpoint 6 at 0x8396ba: file ../../src/gcc/final.c, line 4526. 655163953Srrs ...and we have a breakpoint set; continue execution: 656163953Srrs (gdb) cont 657163953Srrs Continuing. 658163953Srrs Breakpoint 6, (anonymous namespace)::pass_final::execute (this=0x17fb990) at ../../src/gcc/final.c:4526 659163953Srrs 4526 virtual unsigned int execute (function *) { return rest_of_handle_final (); } 660163953Srrs """ 661163953Srrs def __init__(self): 662163953Srrs gdb.Command.__init__(self, 'break-on-pass', gdb.COMMAND_BREAKPOINTS) 663163953Srrs self.pass_names = None 664163953Srrs 665163953Srrs def complete(self, text, word): 666163953Srrs # Lazily load pass names: 667169380Srrs if not self.pass_names: 668169380Srrs self.pass_names = PassNames() 669163953Srrs 670163953Srrs return [name 671163953Srrs for name in sorted(self.pass_names.names) 672163953Srrs if name.startswith(text)] 673169380Srrs 674169380Srrs def invoke(self, arg, from_tty): 675163953Srrs sym = '(anonymous namespace)::%s::execute' % arg 676163953Srrs breakpoint = gdb.Breakpoint(sym) 677163953Srrs 678163953SrrsBreakOnPass() 679163953Srrs 680163953Srrsclass DumpFn(gdb.Command): 681167695Srrs """ 682163953Srrs A custom command to dump a gimple/rtl function to file. By default, it 683163953Srrs dumps the current function using 0 as dump_flags, but the function and flags 684163953Srrs can also be specified. If /f <file> are passed as the first two arguments, 685163953Srrs the dump is written to that file. Otherwise, a temporary file is created 686167695Srrs and opened in the text editor specified in the EDITOR environment variable. 687167695Srrs 688163953Srrs Examples of use: 689163953Srrs (gdb) dump-fn 690163953Srrs (gdb) dump-fn /f foo.1.txt 691163953Srrs (gdb) dump-fn cfun->decl 692163953Srrs (gdb) dump-fn /f foo.1.txt cfun->decl 693163953Srrs (gdb) dump-fn cfun->decl 0 694163953Srrs (gdb) dump-fn cfun->decl dump_flags 695163953Srrs """ 696163953Srrs 697163953Srrs def __init__(self): 698163953Srrs gdb.Command.__init__(self, 'dump-fn', gdb.COMMAND_USER) 699163953Srrs 700167598Srrs def invoke(self, arg, from_tty): 701163953Srrs # Parse args, check number of args 702168709Srrs args = gdb.string_to_argv(arg) 703168709Srrs if len(args) >= 1 and args[0] == "/f": 704163953Srrs if len(args) == 1: 705163953Srrs print ("Missing file argument") 706163953Srrs return 707163953Srrs filename = args[1] 708163953Srrs editor_mode = False 709163953Srrs base_arg = 2 710163953Srrs else: 711163953Srrs editor = os.getenv("EDITOR", "") 712163953Srrs if editor == "": 713163953Srrs print ("EDITOR environment variable not defined") 714166675Srrs return 715163953Srrs editor_mode = True 716163953Srrs base_arg = 0 717163953Srrs if len(args) - base_arg > 2: 718163953Srrs print ("Too many arguments") 719163953Srrs return 720163953Srrs 721163953Srrs # Set func 722163953Srrs if len(args) - base_arg >= 1: 723163953Srrs funcname = args[base_arg] 724163953Srrs printfuncname = "function %s" % funcname 725163953Srrs else: 726163953Srrs funcname = "cfun ? cfun->decl : current_function_decl" 727163953Srrs printfuncname = "current function" 728163953Srrs func = gdb.parse_and_eval(funcname) 729163953Srrs if func == 0: 730163953Srrs print ("Could not find %s" % printfuncname) 731163953Srrs return 732163953Srrs func = "(tree)%u" % func 733163953Srrs 734163953Srrs # Set flags 735163953Srrs if len(args) - base_arg >= 2: 736168709Srrs flags = gdb.parse_and_eval(args[base_arg + 1]) 737163953Srrs else: 738168709Srrs flags = 0 739168709Srrs 740163953Srrs # Get tempory file, if necessary 741163953Srrs if editor_mode: 742163953Srrs f = tempfile.NamedTemporaryFile(delete=False, suffix=".txt") 743163953Srrs filename = f.name 744163953Srrs f.close() 745163953Srrs 746163953Srrs # Open file 747165220Srrs fp = gdb.parse_and_eval("(FILE *) fopen (\"%s\", \"w\")" % filename) 748165220Srrs if fp == 0: 749163953Srrs print ("Could not open file: %s" % filename) 750163953Srrs return 751163953Srrs 752163953Srrs # Dump function to file 753163953Srrs _ = gdb.parse_and_eval("dump_function_to_file (%s, %s, %u)" % 754163953Srrs (func, fp, flags)) 755163953Srrs 756163953Srrs # Close file 757163953Srrs ret = gdb.parse_and_eval("(int) fclose (%s)" % fp) 758163953Srrs if ret != 0: 759163953Srrs print ("Could not close file: %s" % filename) 760163953Srrs return 761163953Srrs 762163953Srrs # Open file in editor, if necessary 763163953Srrs if editor_mode: 764163953Srrs os.system("( %s \"%s\"; rm \"%s\" ) &" % 765163953Srrs (editor, filename, filename)) 766163953Srrs 767163953SrrsDumpFn() 768163953Srrs 769163953Srrsclass DotFn(gdb.Command): 770163953Srrs """ 771163953Srrs A custom command to show a gimple/rtl function control flow graph. 772163953Srrs By default, it show the current function, but the function can also be 773163953Srrs specified. 774163953Srrs 775166675Srrs Examples of use: 776166675Srrs (gdb) dot-fn 777166675Srrs (gdb) dot-fn cfun 778166675Srrs (gdb) dot-fn cfun 0 779163953Srrs (gdb) dot-fn cfun dump_flags 780163953Srrs """ 781163953Srrs def __init__(self): 782163953Srrs gdb.Command.__init__(self, 'dot-fn', gdb.COMMAND_USER) 783163953Srrs 784163953Srrs def invoke(self, arg, from_tty): 785163953Srrs # Parse args, check number of args 786163953Srrs args = gdb.string_to_argv(arg) 787163953Srrs if len(args) > 2: 788163953Srrs print("Too many arguments") 789163953Srrs return 790163953Srrs 791163953Srrs # Set func 792163953Srrs if len(args) >= 1: 793163953Srrs funcname = args[0] 794163953Srrs printfuncname = "function %s" % funcname 795163953Srrs else: 796163953Srrs funcname = "cfun" 797163953Srrs printfuncname = "current function" 798163953Srrs func = gdb.parse_and_eval(funcname) 799163953Srrs if func == 0: 800163953Srrs print("Could not find %s" % printfuncname) 801163953Srrs return 802163953Srrs func = "(struct function *)%s" % func 803163953Srrs 804163953Srrs # Set flags 805163953Srrs if len(args) >= 2: 806163953Srrs flags = gdb.parse_and_eval(args[1]) 807163953Srrs else: 808163953Srrs flags = 0 809163953Srrs 810163953Srrs # Get temp file 811168709Srrs f = tempfile.NamedTemporaryFile(delete=False) 812163953Srrs filename = f.name 813163953Srrs 814163953Srrs # Close and reopen temp file to get C FILE* 815163953Srrs f.close() 816163953Srrs fp = gdb.parse_and_eval("(FILE *) fopen (\"%s\", \"w\")" % filename) 817163953Srrs if fp == 0: 818163953Srrs print("Cannot open temp file") 819163953Srrs return 820163953Srrs 821163953Srrs # Write graph to temp file 822163953Srrs _ = gdb.parse_and_eval("start_graph_dump (%s, \"<debug>\")" % fp) 823163953Srrs _ = gdb.parse_and_eval("print_graph_cfg (%s, %s, %u)" 824163953Srrs % (fp, func, flags)) 825163953Srrs _ = gdb.parse_and_eval("end_graph_dump (%s)" % fp) 826163953Srrs 827163953Srrs # Close temp file 828163953Srrs ret = gdb.parse_and_eval("(int) fclose (%s)" % fp) 829163953Srrs if ret != 0: 830163953Srrs print("Could not close temp file: %s" % filename) 831163953Srrs return 832163953Srrs 833163953Srrs # Show graph in temp file 834169352Srrs os.system("( dot -Tx11 \"%s\"; rm \"%s\" ) &" % (filename, filename)) 835163953Srrs 836163953SrrsDotFn() 837169352Srrs 838163953Srrsprint('Successfully loaded GDB hooks for GCC') 839163953Srrs