(root)/
gcc-13.2.0/
gcc/
gdbhooks.py
       1  # Python hooks for gdb for debugging GCC
       2  # Copyright (C) 2013-2023 Free Software Foundation, Inc.
       3  
       4  # Contributed by David Malcolm <dmalcolm@redhat.com>
       5  
       6  # This file is part of GCC.
       7  
       8  # GCC is free software; you can redistribute it and/or modify it under
       9  # the terms of the GNU General Public License as published by the Free
      10  # Software Foundation; either version 3, or (at your option) any later
      11  # version.
      12  
      13  # GCC is distributed in the hope that it will be useful, but WITHOUT
      14  # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      15  # FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      16  # for more details.
      17  
      18  # You should have received a copy of the GNU General Public License
      19  # along with GCC; see the file COPYING3.  If not see
      20  # <http://www.gnu.org/licenses/>.
      21  
      22  """
      23  Enabling the debugging hooks
      24  ----------------------------
      25  gcc/configure (from configure.ac) generates a .gdbinit within the "gcc"
      26  subdirectory of the build directory, and when run by gdb, this imports
      27  gcc/gdbhooks.py from the source directory, injecting useful Python code
      28  into gdb.
      29  
      30  You may see a message from gdb of the form:
      31    "path-to-build/gcc/.gdbinit" auto-loading has been declined by your `auto-load safe-path'
      32  as a protection against untrustworthy python scripts.  See
      33    http://sourceware.org/gdb/onlinedocs/gdb/Auto_002dloading-safe-path.html
      34  
      35  The fix is to mark the paths of the build/gcc directory as trustworthy.
      36  An easy way to do so is by adding the following to your ~/.gdbinit script:
      37    add-auto-load-safe-path /absolute/path/to/build/gcc
      38  for the build directories for your various checkouts of gcc.
      39  
      40  If it's working, you should see the message:
      41    Successfully loaded GDB hooks for GCC
      42  as gdb starts up.
      43  
      44  During development, I've been manually invoking the code in this way, as a
      45  precanned way of printing a variety of different kinds of value:
      46  
      47    gdb \
      48      -ex "break expand_gimple_stmt" \
      49      -ex "run" \
      50      -ex "bt" \
      51      --args \
      52        ./cc1 foo.c -O3
      53  
      54  Examples of output using the pretty-printers
      55  --------------------------------------------
      56  Pointer values are generally shown in the form:
      57    <type address extra_info>
      58  
      59  For example, an opt_pass* might appear as:
      60    (gdb) p pass
      61    $2 = <opt_pass* 0x188b600 "expand"(170)>
      62  
      63  The name of the pass is given ("expand"), together with the
      64  static_pass_number.
      65  
      66  Note that you can dereference the pointer in the normal way:
      67    (gdb) p *pass
      68    $4 = {type = RTL_PASS, name = 0x120a312 "expand",
      69    [etc, ...snipped...]
      70  
      71  and you can suppress pretty-printers using /r (for "raw"):
      72    (gdb) p /r pass
      73    $3 = (opt_pass *) 0x188b600
      74  
      75  Basic blocks are shown with their index in parentheses, apart from the
      76  CFG's entry and exit blocks, which are given as "ENTRY" and "EXIT":
      77    (gdb) p bb
      78    $9 = <basic_block 0x7ffff041f1a0 (2)>
      79    (gdb) p cfun->cfg->x_entry_block_ptr
      80    $10 = <basic_block 0x7ffff041f0d0 (ENTRY)>
      81    (gdb) p cfun->cfg->x_exit_block_ptr
      82    $11 = <basic_block 0x7ffff041f138 (EXIT)>
      83  
      84  CFG edges are shown with the src and dest blocks given in parentheses:
      85    (gdb) p e
      86    $1 = <edge 0x7ffff043f118 (ENTRY -> 6)>
      87  
      88  Tree nodes are printed using Python code that emulates print_node_brief,
      89  running in gdb, rather than in the inferior:
      90    (gdb) p cfun->decl
      91    $1 = <function_decl 0x7ffff0420b00 foo>
      92  For usability, the type is printed first (e.g. "function_decl"), rather
      93  than just "tree".
      94  
      95  RTL expressions use a kludge: they are pretty-printed by injecting
      96  calls into print-rtl.c into the inferior:
      97    Value returned is $1 = (note 9 8 10 [bb 3] NOTE_INSN_BASIC_BLOCK)
      98    (gdb) p $1
      99    $2 = (note 9 8 10 [bb 3] NOTE_INSN_BASIC_BLOCK)
     100    (gdb) p /r $1
     101    $3 = (rtx_def *) 0x7ffff043e140
     102  This won't work for coredumps, and probably in other circumstances, but
     103  it's a quick way of getting lots of debuggability quickly.
     104  
     105  Callgraph nodes are printed with the name of the function decl, if
     106  available:
     107    (gdb) frame 5
     108    #5  0x00000000006c288a in expand_function (node=<cgraph_node* 0x7ffff0312720 "foo"/12345>) at ../../src/gcc/cgraphunit.c:1594
     109    1594	  execute_pass_list (g->get_passes ()->all_passes);
     110    (gdb) p node
     111    $1 = <cgraph_node* 0x7ffff0312720 "foo"/12345>
     112  
     113  Similarly for symtab_node and varpool_node classes.
     114  
     115  Cgraph edges are printed with the name of caller and callee:
     116      (gdb) p this->callees
     117      $4 = <cgraph_edge* 0x7fffe25aa000 (<cgraph_node * 0x7fffe62b22e0 "_GLOBAL__sub_I__ZN5Pooma5pinfoE"/19660> -> <cgraph_node * 0x7fffe620f730 "__static_initialization_and_destruction_1"/19575>)>
     118  
     119  IPA reference follow very similar format:
     120      (gdb) Value returned is $5 = <ipa_ref* 0x7fffefcb80c8 (<symtab_node * 0x7ffff562f000 "__dt_base "/875> -> <symtab_node * 0x7fffe795f000 "_ZTVN6Smarts8RunnableE"/16056>:IPA_REF_ADDR)>
     121  
     122  vec<> pointers are printed as the address followed by the elements in
     123  braces.  Here's a length 2 vec:
     124    (gdb) p bb->preds
     125    $18 = 0x7ffff0428b68 = {<edge 0x7ffff044d380 (3 -> 5)>, <edge 0x7ffff044d3b8 (4 -> 5)>}
     126  
     127  and here's a length 1 vec:
     128    (gdb) p bb->succs
     129    $19 = 0x7ffff0428bb8 = {<edge 0x7ffff044d3f0 (5 -> EXIT)>}
     130  
     131  You cannot yet use array notation [] to access the elements within the
     132  vector: attempting to do so instead gives you the vec itself (for vec[0]),
     133  or a (probably) invalid cast to vec<> for the memory after the vec (for
     134  vec[1] onwards).
     135  
     136  Instead (for now) you must access the payload directly:
     137    (gdb) p ((edge_def**)(bb->preds+1))[0]
     138    $20 = <edge 0x7ffff044d380 (3 -> 5)>
     139    (gdb) p ((edge_def**)(bb->preds+1))[1]
     140    $21 = <edge 0x7ffff044d3b8 (4 -> 5)>
     141  """
     142  import os.path
     143  import re
     144  import sys
     145  import tempfile
     146  
     147  import gdb
     148  import gdb.printing
     149  import gdb.types
     150  
     151  # Convert "enum tree_code" (tree.def and tree.h) to a dict:
     152  tree_code_dict = gdb.types.make_enum_dict(gdb.lookup_type('enum tree_code'))
     153  
     154  # ...and look up specific values for use later:
     155  IDENTIFIER_NODE = tree_code_dict['IDENTIFIER_NODE']
     156  TYPE_DECL = tree_code_dict['TYPE_DECL']
     157  SSA_NAME = tree_code_dict['SSA_NAME']
     158  
     159  # Similarly for "enum tree_code_class" (tree.h):
     160  tree_code_class_dict = gdb.types.make_enum_dict(gdb.lookup_type('enum tree_code_class'))
     161  tcc_type = tree_code_class_dict['tcc_type']
     162  tcc_declaration = tree_code_class_dict['tcc_declaration']
     163  
     164  # Python3 has int() with arbitrary precision (bignum).  Python2 int() is 32-bit
     165  # on 32-bit hosts but remote targets may have 64-bit pointers there; Python2
     166  # long() is always 64-bit but Python3 no longer has anything named long.
     167  def intptr(gdbval):
     168      return long(gdbval) if sys.version_info.major == 2 else int(gdbval)
     169  
     170  class ESC[4;38;5;81mTree:
     171      """
     172      Wrapper around a gdb.Value for a tree, with various methods
     173      corresponding to macros in gcc/tree.h
     174      """
     175      def __init__(self, gdbval):
     176          self.gdbval = gdbval
     177  
     178      def is_nonnull(self):
     179          return intptr(self.gdbval)
     180  
     181      def TREE_CODE(self):
     182          """
     183          Get gdb.Value corresponding to TREE_CODE (self)
     184          as per:
     185            #define TREE_CODE(NODE) ((enum tree_code) (NODE)->base.code)
     186          """
     187          return self.gdbval['base']['code']
     188  
     189      def DECL_NAME(self):
     190          """
     191          Get Tree instance corresponding to DECL_NAME (self)
     192          """
     193          return Tree(self.gdbval['decl_minimal']['name'])
     194  
     195      def TYPE_NAME(self):
     196          """
     197          Get Tree instance corresponding to result of TYPE_NAME (self)
     198          """
     199          return Tree(self.gdbval['type_common']['name'])
     200  
     201      def IDENTIFIER_POINTER(self):
     202          """
     203          Get str correspoinding to result of IDENTIFIER_NODE (self)
     204          """
     205          return self.gdbval['identifier']['id']['str'].string()
     206  
     207  class ESC[4;38;5;81mTreePrinter:
     208      "Prints a tree"
     209  
     210      def __init__ (self, gdbval):
     211          self.gdbval = gdbval
     212          self.node = Tree(gdbval)
     213  
     214      def to_string (self):
     215          # like gcc/print-tree.c:print_node_brief
     216          # #define TREE_CODE(NODE) ((enum tree_code) (NODE)->base.code)
     217          # tree_code_name[(int) TREE_CODE (node)])
     218          if intptr(self.gdbval) == 0:
     219              return '<tree 0x0>'
     220  
     221          val_TREE_CODE = self.node.TREE_CODE()
     222  
     223          # constexpr inline enum tree_code_class tree_code_type[] = { ... };
     224          # #define TREE_CODE_CLASS(CODE)	tree_code_type[(int) (CODE)]
     225          # or
     226          # template <int N>
     227          # struct tree_code_type_tmpl {
     228          # static constexpr enum tree_code_class tree_code_type[] = { ... };
     229          # }; };
     230          # #define TREE_CODE_CLASS(CODE) \
     231          # tree_code_type_tmpl <0>::tree_code_type[(int) (CODE)]
     232  
     233          if val_TREE_CODE == 0xa5a5:
     234              return '<ggc_freed 0x%x>' % intptr(self.gdbval)
     235  
     236          try:
     237              val_tree_code_type = gdb.parse_and_eval('tree_code_type')
     238          except:
     239              val_tree_code_type = gdb.parse_and_eval('tree_code_type_tmpl<0>::tree_code_type')
     240          val_tclass = val_tree_code_type[val_TREE_CODE]
     241  
     242          val_tree_code_name = gdb.parse_and_eval('tree_code_name')
     243          val_code_name = val_tree_code_name[intptr(val_TREE_CODE)]
     244          #print(val_code_name.string())
     245  
     246          try:
     247              result = '<%s 0x%x' % (val_code_name.string(), intptr(self.gdbval))
     248          except:
     249              return '<tree 0x%x>' % intptr(self.gdbval)
     250          if intptr(val_tclass) == tcc_declaration:
     251              tree_DECL_NAME = self.node.DECL_NAME()
     252              if tree_DECL_NAME.is_nonnull():
     253                   result += ' %s' % tree_DECL_NAME.IDENTIFIER_POINTER()
     254              else:
     255                  pass # TODO: labels etc
     256          elif intptr(val_tclass) == tcc_type:
     257              tree_TYPE_NAME = Tree(self.gdbval['type_common']['name'])
     258              if tree_TYPE_NAME.is_nonnull():
     259                  if tree_TYPE_NAME.TREE_CODE() == IDENTIFIER_NODE:
     260                      result += ' %s' % tree_TYPE_NAME.IDENTIFIER_POINTER()
     261                  elif tree_TYPE_NAME.TREE_CODE() == TYPE_DECL:
     262                      if tree_TYPE_NAME.DECL_NAME().is_nonnull():
     263                          result += ' %s' % tree_TYPE_NAME.DECL_NAME().IDENTIFIER_POINTER()
     264          if self.node.TREE_CODE() == IDENTIFIER_NODE:
     265              result += ' %s' % self.node.IDENTIFIER_POINTER()
     266          elif self.node.TREE_CODE() == SSA_NAME:
     267              result += ' %u' % self.gdbval['base']['u']['version']
     268          # etc
     269          result += '>'
     270          return result
     271  
     272  ######################################################################
     273  # Callgraph pretty-printers
     274  ######################################################################
     275  
     276  class ESC[4;38;5;81mSymtabNodePrinter:
     277      def __init__(self, gdbval):
     278          self.gdbval = gdbval
     279  
     280      def to_string (self):
     281          t = str(self.gdbval.type)
     282          result = '<%s 0x%x' % (t, intptr(self.gdbval))
     283          if intptr(self.gdbval):
     284              # symtab_node::name calls lang_hooks.decl_printable_name
     285              # default implementation (lhd_decl_printable_name) is:
     286              #    return IDENTIFIER_POINTER (DECL_NAME (decl));
     287              tree_decl = Tree(self.gdbval['decl'])
     288              result += ' "%s"/%d' % (tree_decl.DECL_NAME().IDENTIFIER_POINTER(), self.gdbval['order'])
     289          result += '>'
     290          return result
     291  
     292  class ESC[4;38;5;81mCgraphEdgePrinter:
     293      def __init__(self, gdbval):
     294          self.gdbval = gdbval
     295  
     296      def to_string (self):
     297          result = '<cgraph_edge* 0x%x' % intptr(self.gdbval)
     298          if intptr(self.gdbval):
     299              src = SymtabNodePrinter(self.gdbval['caller']).to_string()
     300              dest = SymtabNodePrinter(self.gdbval['callee']).to_string()
     301              result += ' (%s -> %s)' % (src, dest)
     302          result += '>'
     303          return result
     304  
     305  class ESC[4;38;5;81mIpaReferencePrinter:
     306      def __init__(self, gdbval):
     307          self.gdbval = gdbval
     308  
     309      def to_string (self):
     310          result = '<ipa_ref* 0x%x' % intptr(self.gdbval)
     311          if intptr(self.gdbval):
     312              src = SymtabNodePrinter(self.gdbval['referring']).to_string()
     313              dest = SymtabNodePrinter(self.gdbval['referred']).to_string()
     314              result += ' (%s -> %s:%s)' % (src, dest, str(self.gdbval['use']))
     315          result += '>'
     316          return result
     317  
     318  ######################################################################
     319  # Dwarf DIE pretty-printers
     320  ######################################################################
     321  
     322  class ESC[4;38;5;81mDWDieRefPrinter:
     323      def __init__(self, gdbval):
     324          self.gdbval = gdbval
     325  
     326      def to_string (self):
     327          if intptr(self.gdbval) == 0:
     328              return '<dw_die_ref 0x0>'
     329          result = '<dw_die_ref 0x%x' % intptr(self.gdbval)
     330          result += ' %s' % self.gdbval['die_tag']
     331          if intptr(self.gdbval['die_parent']) != 0:
     332              result += ' <parent=0x%x %s>' % (intptr(self.gdbval['die_parent']),
     333                                               self.gdbval['die_parent']['die_tag'])
     334                                               
     335          result += '>'
     336          return result
     337  
     338  ######################################################################
     339  
     340  class ESC[4;38;5;81mGimplePrinter:
     341      def __init__(self, gdbval):
     342          self.gdbval = gdbval
     343  
     344      def to_string (self):
     345          if intptr(self.gdbval) == 0:
     346              return '<gimple 0x0>'
     347          val_gimple_code = self.gdbval['code']
     348          val_gimple_code_name = gdb.parse_and_eval('gimple_code_name')
     349          val_code_name = val_gimple_code_name[intptr(val_gimple_code)]
     350          result = '<%s 0x%x' % (val_code_name.string(),
     351                                 intptr(self.gdbval))
     352          result += '>'
     353          return result
     354  
     355  ######################################################################
     356  # CFG pretty-printers
     357  ######################################################################
     358  
     359  def bb_index_to_str(index):
     360      if index == 0:
     361          return 'ENTRY'
     362      elif index == 1:
     363          return 'EXIT'
     364      else:
     365          return '%i' % index
     366  
     367  class ESC[4;38;5;81mBasicBlockPrinter:
     368      def __init__(self, gdbval):
     369          self.gdbval = gdbval
     370  
     371      def to_string (self):
     372          result = '<basic_block 0x%x' % intptr(self.gdbval)
     373          if intptr(self.gdbval):
     374              result += ' (%s)' % bb_index_to_str(intptr(self.gdbval['index']))
     375          result += '>'
     376          return result
     377  
     378  class ESC[4;38;5;81mCfgEdgePrinter:
     379      def __init__(self, gdbval):
     380          self.gdbval = gdbval
     381  
     382      def to_string (self):
     383          result = '<edge 0x%x' % intptr(self.gdbval)
     384          if intptr(self.gdbval):
     385              src = bb_index_to_str(intptr(self.gdbval['src']['index']))
     386              dest = bb_index_to_str(intptr(self.gdbval['dest']['index']))
     387              result += ' (%s -> %s)' % (src, dest)
     388          result += '>'
     389          return result
     390  
     391  ######################################################################
     392  
     393  class ESC[4;38;5;81mRtx:
     394      def __init__(self, gdbval):
     395          self.gdbval = gdbval
     396  
     397      def GET_CODE(self):
     398          return self.gdbval['code']
     399  
     400  def GET_RTX_LENGTH(code):
     401      val_rtx_length = gdb.parse_and_eval('rtx_length')
     402      return intptr(val_rtx_length[code])
     403  
     404  def GET_RTX_NAME(code):
     405      val_rtx_name = gdb.parse_and_eval('rtx_name')
     406      return val_rtx_name[code].string()
     407  
     408  def GET_RTX_FORMAT(code):
     409      val_rtx_format = gdb.parse_and_eval('rtx_format')
     410      return val_rtx_format[code].string()
     411  
     412  class ESC[4;38;5;81mRtxPrinter:
     413      def __init__(self, gdbval):
     414          self.gdbval = gdbval
     415          self.rtx = Rtx(gdbval)
     416  
     417      def to_string (self):
     418          """
     419          For now, a cheap kludge: invoke the inferior's print
     420          function to get a string to use the user, and return an empty
     421          string for gdb
     422          """
     423          # We use print_inline_rtx to avoid a trailing newline
     424          gdb.execute('call print_inline_rtx (stderr, (const_rtx) %s, 0)'
     425                      % intptr(self.gdbval))
     426          return ''
     427  
     428          # or by hand; based on gcc/print-rtl.c:print_rtx
     429          result = ('<rtx_def 0x%x'
     430                    % (intptr(self.gdbval)))
     431          code = self.rtx.GET_CODE()
     432          result += ' (%s' % GET_RTX_NAME(code)
     433          format_ = GET_RTX_FORMAT(code)
     434          for i in range(GET_RTX_LENGTH(code)):
     435              print(format_[i])
     436          result += ')>'
     437          return result
     438  
     439  ######################################################################
     440  
     441  class ESC[4;38;5;81mPassPrinter:
     442      def __init__(self, gdbval):
     443          self.gdbval = gdbval
     444  
     445      def to_string (self):
     446          result = '<opt_pass* 0x%x' % intptr(self.gdbval)
     447          if intptr(self.gdbval):
     448              result += (' "%s"(%i)'
     449                         % (self.gdbval['name'].string(),
     450                            intptr(self.gdbval['static_pass_number'])))
     451          result += '>'
     452          return result
     453  
     454  ######################################################################
     455  
     456  class ESC[4;38;5;81mVecPrinter:
     457      #    -ex "up" -ex "p bb->preds"
     458      def __init__(self, gdbval):
     459          self.gdbval = gdbval
     460  
     461      def display_hint (self):
     462          return 'array'
     463  
     464      def to_string (self):
     465          # A trivial implementation; prettyprinting the contents is done
     466          # by gdb calling the "children" method below.
     467          return '0x%x' % intptr(self.gdbval)
     468  
     469      def children (self):
     470          if intptr(self.gdbval) == 0:
     471              return
     472          m_vecpfx = self.gdbval['m_vecpfx']
     473          m_num = m_vecpfx['m_num']
     474          val = self.gdbval
     475          typ = val.type
     476          if typ.code == gdb.TYPE_CODE_PTR:
     477              typ = typ.target()
     478          else:
     479              val = val.address
     480          typ_T = typ.template_argument(0) # the type T
     481          vecdata = (val + 1).cast(typ_T.pointer())
     482          for i in range(m_num):
     483              yield ('[%d]' % i, vecdata[i])
     484  
     485  ######################################################################
     486  
     487  class ESC[4;38;5;81mMachineModePrinter:
     488      def __init__(self, gdbval):
     489          self.gdbval = gdbval
     490  
     491      def to_string (self):
     492          name = str(self.gdbval['m_mode'])
     493          return name[2:] if name.startswith('E_') else name
     494  
     495  ######################################################################
     496  
     497  class ESC[4;38;5;81mOptMachineModePrinter:
     498      def __init__(self, gdbval):
     499          self.gdbval = gdbval
     500  
     501      def to_string (self):
     502          name = str(self.gdbval['m_mode'])
     503          if name == 'E_VOIDmode':
     504              return '<None>'
     505          return name[2:] if name.startswith('E_') else name
     506  
     507  ######################################################################
     508  
     509  # TODO:
     510  #   * hashtab
     511  #   * location_t
     512  
     513  class ESC[4;38;5;81mGdbSubprinter(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mprintingESC[4;38;5;149m.ESC[4;38;5;149mSubPrettyPrinter):
     514      def __init__(self, name, class_):
     515          super(GdbSubprinter, self).__init__(name)
     516          self.class_ = class_
     517  
     518      def handles_type(self, str_type):
     519          raise NotImplementedError
     520  
     521  class ESC[4;38;5;81mGdbSubprinterTypeList(ESC[4;38;5;149mGdbSubprinter):
     522      """
     523      A GdbSubprinter that handles a specific set of types
     524      """
     525      def __init__(self, str_types, name, class_):
     526          super(GdbSubprinterTypeList, self).__init__(name, class_)
     527          self.str_types = frozenset(str_types)
     528  
     529      def handles_type(self, str_type):
     530          return str_type in self.str_types
     531  
     532  class ESC[4;38;5;81mGdbSubprinterRegex(ESC[4;38;5;149mGdbSubprinter):
     533      """
     534      A GdbSubprinter that handles types that match a regex
     535      """
     536      def __init__(self, regex, name, class_):
     537          super(GdbSubprinterRegex, self).__init__(name, class_)
     538          self.regex = re.compile(regex)
     539  
     540      def handles_type(self, str_type):
     541          return self.regex.match(str_type)
     542  
     543  class ESC[4;38;5;81mGdbPrettyPrinters(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mprintingESC[4;38;5;149m.ESC[4;38;5;149mPrettyPrinter):
     544      def __init__(self, name):
     545          super(GdbPrettyPrinters, self).__init__(name, [])
     546  
     547      def add_printer_for_types(self, types, name, class_):
     548          self.subprinters.append(GdbSubprinterTypeList(types, name, class_))
     549  
     550      def add_printer_for_regex(self, regex, name, class_):
     551          self.subprinters.append(GdbSubprinterRegex(regex, name, class_))
     552  
     553      def __call__(self, gdbval):
     554          type_ = gdbval.type.unqualified()
     555          str_type = str(type_)
     556          for printer in self.subprinters:
     557              if printer.enabled and printer.handles_type(str_type):
     558                  return printer.class_(gdbval)
     559  
     560          # Couldn't find a pretty printer (or it was disabled):
     561          return None
     562  
     563  
     564  def build_pretty_printer():
     565      pp = GdbPrettyPrinters('gcc')
     566      pp.add_printer_for_types(['tree', 'const_tree'],
     567                               'tree', TreePrinter)
     568      pp.add_printer_for_types(['cgraph_node *', 'varpool_node *', 'symtab_node *'],
     569                               'symtab_node', SymtabNodePrinter)
     570      pp.add_printer_for_types(['cgraph_edge *'],
     571                               'cgraph_edge', CgraphEdgePrinter)
     572      pp.add_printer_for_types(['ipa_ref *'],
     573                               'ipa_ref', IpaReferencePrinter)
     574      pp.add_printer_for_types(['dw_die_ref'],
     575                               'dw_die_ref', DWDieRefPrinter)
     576      pp.add_printer_for_types(['gimple', 'gimple *',
     577  
     578                                # Keep this in the same order as gimple.def:
     579                                'gimple_cond', 'const_gimple_cond',
     580                                'gimple_statement_cond *',
     581                                'gimple_debug', 'const_gimple_debug',
     582                                'gimple_statement_debug *',
     583                                'gimple_label', 'const_gimple_label',
     584                                'gimple_statement_label *',
     585                                'gimple_switch', 'const_gimple_switch',
     586                                'gimple_statement_switch *',
     587                                'gimple_assign', 'const_gimple_assign',
     588                                'gimple_statement_assign *',
     589                                'gimple_bind', 'const_gimple_bind',
     590                                'gimple_statement_bind *',
     591                                'gimple_phi', 'const_gimple_phi',
     592                                'gimple_statement_phi *'],
     593  
     594                               'gimple',
     595                               GimplePrinter)
     596      pp.add_printer_for_types(['basic_block', 'basic_block_def *'],
     597                               'basic_block',
     598                               BasicBlockPrinter)
     599      pp.add_printer_for_types(['edge', 'edge_def *'],
     600                               'edge',
     601                               CfgEdgePrinter)
     602      pp.add_printer_for_types(['rtx_def *'], 'rtx_def', RtxPrinter)
     603      pp.add_printer_for_types(['opt_pass *'], 'opt_pass', PassPrinter)
     604  
     605      pp.add_printer_for_regex(r'vec<(\S+), (\S+), (\S+)> \*',
     606                               'vec',
     607                               VecPrinter)
     608  
     609      pp.add_printer_for_regex(r'opt_mode<(\S+)>',
     610                               'opt_mode', OptMachineModePrinter)
     611      pp.add_printer_for_types(['opt_scalar_int_mode',
     612                                'opt_scalar_float_mode',
     613                                'opt_scalar_mode'],
     614                               'opt_mode', OptMachineModePrinter)
     615      pp.add_printer_for_regex(r'pod_mode<(\S+)>',
     616                               'pod_mode', MachineModePrinter)
     617      pp.add_printer_for_types(['scalar_int_mode_pod',
     618                                'scalar_mode_pod'],
     619                               'pod_mode', MachineModePrinter)
     620      for mode in ('scalar_mode', 'scalar_int_mode', 'scalar_float_mode',
     621                   'complex_mode'):
     622          pp.add_printer_for_types([mode], mode, MachineModePrinter)
     623  
     624      return pp
     625  
     626  gdb.printing.register_pretty_printer(
     627      gdb.current_objfile(),
     628      build_pretty_printer(),
     629      replace=True)
     630  
     631  def find_gcc_source_dir():
     632      # Use location of global "g" to locate the source tree
     633      sym_g = gdb.lookup_global_symbol('g')
     634      path = sym_g.symtab.filename # e.g. '../../src/gcc/context.h'
     635      srcdir = os.path.split(path)[0] # e.g. '../../src/gcc'
     636      return srcdir
     637  
     638  class ESC[4;38;5;81mPassNames:
     639      """Parse passes.def, gathering a list of pass class names"""
     640      def __init__(self):
     641          srcdir = find_gcc_source_dir()
     642          self.names = []
     643          with open(os.path.join(srcdir, 'passes.def')) as f:
     644              for line in f:
     645                  m = re.match('\s*NEXT_PASS \(([^,]+).*\);', line)
     646                  if m:
     647                      self.names.append(m.group(1))
     648  
     649  class ESC[4;38;5;81mBreakOnPass(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mCommand):
     650      """
     651      A custom command for putting breakpoints on the execute hook of passes.
     652      This is largely a workaround for issues with tab-completion in gdb when
     653      setting breakpoints on methods on classes within anonymous namespaces.
     654  
     655      Example of use: putting a breakpoint on "final"
     656        (gdb) break-on-pass
     657      Press <TAB>; it autocompletes to "pass_":
     658        (gdb) break-on-pass pass_
     659      Press <TAB>:
     660        Display all 219 possibilities? (y or n)
     661      Press "n"; then type "f":
     662        (gdb) break-on-pass pass_f
     663      Press <TAB> to autocomplete to pass classnames beginning with "pass_f":
     664        pass_fast_rtl_dce              pass_fold_builtins
     665        pass_feedback_split_functions  pass_forwprop
     666        pass_final                     pass_fre
     667        pass_fixup_cfg                 pass_free_cfg
     668      Type "in<TAB>" to complete to "pass_final":
     669        (gdb) break-on-pass pass_final
     670      ...and hit <RETURN>:
     671        Breakpoint 6 at 0x8396ba: file ../../src/gcc/final.c, line 4526.
     672      ...and we have a breakpoint set; continue execution:
     673        (gdb) cont
     674        Continuing.
     675        Breakpoint 6, (anonymous namespace)::pass_final::execute (this=0x17fb990) at ../../src/gcc/final.c:4526
     676        4526	  virtual unsigned int execute (function *) { return rest_of_handle_final (); }
     677      """
     678      def __init__(self):
     679          gdb.Command.__init__(self, 'break-on-pass', gdb.COMMAND_BREAKPOINTS)
     680          self.pass_names = None
     681  
     682      def complete(self, text, word):
     683          # Lazily load pass names:
     684          if not self.pass_names:
     685              self.pass_names = PassNames()
     686  
     687          return [name
     688                  for name in sorted(self.pass_names.names)
     689                  if name.startswith(text)]
     690  
     691      def invoke(self, arg, from_tty):
     692          sym = '(anonymous namespace)::%s::execute' % arg
     693          breakpoint = gdb.Breakpoint(sym)
     694  
     695  BreakOnPass()
     696  
     697  class ESC[4;38;5;81mDumpFn(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mCommand):
     698      """
     699      A custom command to dump a gimple/rtl function to file.  By default, it
     700      dumps the current function using 0 as dump_flags, but the function and flags
     701      can also be specified. If /f <file> are passed as the first two arguments,
     702      the dump is written to that file.  Otherwise, a temporary file is created
     703      and opened in the text editor specified in the EDITOR environment variable.
     704  
     705      Examples of use:
     706        (gdb) dump-fn
     707        (gdb) dump-fn /f foo.1.txt
     708        (gdb) dump-fn cfun->decl
     709        (gdb) dump-fn /f foo.1.txt cfun->decl
     710        (gdb) dump-fn cfun->decl 0
     711        (gdb) dump-fn cfun->decl dump_flags
     712      """
     713  
     714      def __init__(self):
     715          gdb.Command.__init__(self, 'dump-fn', gdb.COMMAND_USER)
     716  
     717      def invoke(self, arg, from_tty):
     718          # Parse args, check number of args
     719          args = gdb.string_to_argv(arg)
     720          if len(args) >= 1 and args[0] == "/f":
     721              if len(args) == 1:
     722                  print ("Missing file argument")
     723                  return
     724              filename = args[1]
     725              editor_mode = False
     726              base_arg = 2
     727          else:
     728              editor = os.getenv("EDITOR", "")
     729              if editor == "":
     730                  print ("EDITOR environment variable not defined")
     731                  return
     732              editor_mode = True
     733              base_arg = 0
     734          if len(args) - base_arg > 2:
     735              print ("Too many arguments")
     736              return
     737  
     738          # Set func
     739          if len(args) - base_arg >= 1:
     740              funcname = args[base_arg]
     741              printfuncname = "function %s" % funcname
     742          else:
     743              funcname = "cfun ? cfun->decl : current_function_decl"
     744              printfuncname = "current function"
     745          func = gdb.parse_and_eval(funcname)
     746          if func == 0:
     747              print ("Could not find %s" % printfuncname)
     748              return
     749          func = "(tree)%u" % func
     750  
     751          # Set flags
     752          if len(args) - base_arg >= 2:
     753              flags = gdb.parse_and_eval(args[base_arg + 1])
     754          else:
     755              flags = 0
     756  
     757          # Get tempory file, if necessary
     758          if editor_mode:
     759              f = tempfile.NamedTemporaryFile(delete=False, suffix=".txt")
     760              filename = f.name
     761              f.close()
     762  
     763          # Open file
     764          fp = gdb.parse_and_eval("(FILE *) fopen (\"%s\", \"w\")" % filename)
     765          if fp == 0:
     766              print ("Could not open file: %s" % filename)
     767              return
     768  
     769          # Dump function to file
     770          _ = gdb.parse_and_eval("dump_function_to_file (%s, %s, %u)" %
     771                                 (func, fp, flags))
     772  
     773          # Close file
     774          ret = gdb.parse_and_eval("(int) fclose (%s)" % fp)
     775          if ret != 0:
     776              print ("Could not close file: %s" % filename)
     777              return
     778  
     779          # Open file in editor, if necessary
     780          if editor_mode:
     781              os.system("( %s \"%s\"; rm \"%s\" ) &" %
     782                        (editor, filename, filename))
     783  
     784  DumpFn()
     785  
     786  class ESC[4;38;5;81mDotFn(ESC[4;38;5;149mgdbESC[4;38;5;149m.ESC[4;38;5;149mCommand):
     787      """
     788      A custom command to show a gimple/rtl function control flow graph.
     789      By default, it show the current function, but the function can also be
     790      specified.
     791  
     792      Examples of use:
     793        (gdb) dot-fn
     794        (gdb) dot-fn cfun
     795        (gdb) dot-fn cfun 0
     796        (gdb) dot-fn cfun dump_flags
     797      """
     798      def __init__(self):
     799          gdb.Command.__init__(self, 'dot-fn', gdb.COMMAND_USER)
     800  
     801      def invoke(self, arg, from_tty):
     802          # Parse args, check number of args
     803          args = gdb.string_to_argv(arg)
     804          if len(args) > 2:
     805              print("Too many arguments")
     806              return
     807  
     808          # Set func
     809          if len(args) >= 1:
     810              funcname = args[0]
     811              printfuncname = "function %s" % funcname
     812          else:
     813              funcname = "cfun"
     814              printfuncname = "current function"
     815          func = gdb.parse_and_eval(funcname)
     816          if func == 0:
     817              print("Could not find %s" % printfuncname)
     818              return
     819          func = "(struct function *)%s" % func
     820  
     821          # Set flags
     822          if len(args) >= 2:
     823              flags = gdb.parse_and_eval(args[1])
     824          else:
     825              flags = 0
     826  
     827          # Get temp file
     828          f = tempfile.NamedTemporaryFile(delete=False)
     829          filename = f.name
     830  
     831          # Close and reopen temp file to get C FILE*
     832          f.close()
     833          fp = gdb.parse_and_eval("(FILE *) fopen (\"%s\", \"w\")" % filename)
     834          if fp == 0:
     835              print("Cannot open temp file")
     836              return
     837  
     838          # Write graph to temp file
     839          _ = gdb.parse_and_eval("start_graph_dump (%s, \"<debug>\")" % fp)
     840          _ = gdb.parse_and_eval("print_graph_cfg (%s, %s, %u)"
     841                                 % (fp, func, flags))
     842          _ = gdb.parse_and_eval("end_graph_dump (%s)" % fp)
     843  
     844          # Close temp file
     845          ret = gdb.parse_and_eval("(int) fclose (%s)" % fp)
     846          if ret != 0:
     847              print("Could not close temp file: %s" % filename)
     848              return
     849  
     850          # Show graph in temp file
     851          os.system("( dot -Tx11 \"%s\"; rm \"%s\" ) &" % (filename, filename))
     852  
     853  DotFn()
     854  
     855  print('Successfully loaded GDB hooks for GCC')