1 # Type utilities. 2 # Copyright (C) 2010-2013 Free Software Foundation, Inc. 3 4 # This program is free software; you can redistribute it and/or modify 5 # it under the terms of the GNU General Public License as published by 6 # the Free Software Foundation; either version 3 of the License, or 7 # (at your option) any later version. 8 # 9 # This program is distributed in the hope that it will be useful, 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # GNU General Public License for more details. 13 # 14 # You should have received a copy of the GNU General Public License 15 # along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 """Utilities for working with gdb.Types.""" 18 19 import gdb 20 21 22 def get_basic_type(type_): 23 """Return the "basic" type of a type. 24 25 Arguments: 26 type_: The type to reduce to its basic type. 27 28 Returns: 29 type_ with const/volatile is stripped away, 30 and typedefs/references converted to the underlying type. 31 """ 32 33 while (type_.code == gdb.TYPE_CODE_REF or 34 type_.code == gdb.TYPE_CODE_TYPEDEF): 35 if type_.code == gdb.TYPE_CODE_REF: 36 type_ = type_.target() 37 else: 38 type_ = type_.strip_typedefs() 39 return type_.unqualified() 40 41 42 def has_field(type_, field): 43 """Return True if a type has the specified field. 44 45 Arguments: 46 type_: The type to examine. 47 It must be one of gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION. 48 field: The name of the field to look up. 49 50 Returns: 51 True if the field is present either in type_ or any baseclass. 52 53 Raises: 54 TypeError: The type is not a struct or union. 55 """ 56 57 type_ = get_basic_type(type_) 58 if (type_.code != gdb.TYPE_CODE_STRUCT and 59 type_.code != gdb.TYPE_CODE_UNION): 60 raise TypeError("not a struct or union") 61 for f in type_.fields(): 62 if f.is_base_class: 63 if has_field(f.type, field): 64 return True 65 else: 66 # NOTE: f.name could be None 67 if f.name == field: 68 return True 69 return False 70 71 72 def make_enum_dict(enum_type): 73 """Return a dictionary from a program's enum type. 74 75 Arguments: 76 enum_type: The enum to compute the dictionary for. 77 78 Returns: 79 The dictionary of the enum. 80 81 Raises: 82 TypeError: The type is not an enum. 83 """ 84 85 if enum_type.code != gdb.TYPE_CODE_ENUM: 86 raise TypeError("not an enum type") 87 enum_dict = {} 88 for field in enum_type.fields(): 89 # The enum's value is stored in "enumval". 90 enum_dict[field.name] = field.enumval 91 return enum_dict 92 93 94 def deep_items (type_): 95 """Return an iterator that recursively traverses anonymous fields. 96 97 Arguments: 98 type_: The type to traverse. It should be one of 99 gdb.TYPE_CODE_STRUCT or gdb.TYPE_CODE_UNION. 100 101 Returns: 102 an iterator similar to gdb.Type.iteritems(), i.e., it returns 103 pairs of key, value, but for any anonymous struct or union 104 field that field is traversed recursively, depth-first. 105 """ 106 for k, v in type_.iteritems (): 107 if k: 108 yield k, v 109 else: 110 for i in deep_items (v.type): 111 yield i 112 113 class TypePrinter(object): 114 """The base class for type printers. 115 116 Instances of this type can be used to substitute type names during 117 'ptype'. 118 119 A type printer must have at least 'name' and 'enabled' attributes, 120 and supply an 'instantiate' method. 121 122 The 'instantiate' method must either return None, or return an 123 object which has a 'recognize' method. This method must accept a 124 gdb.Type argument and either return None, meaning that the type 125 was not recognized, or a string naming the type. 126 """ 127 128 def __init__(self, name): 129 self.name = name 130 self.enabled = True 131 132 def instantiate(self): 133 return None 134 135 # Helper function for computing the list of type recognizers. 136 def _get_some_type_recognizers(result, plist): 137 for printer in plist: 138 if printer.enabled: 139 inst = printer.instantiate() 140 if inst is not None: 141 result.append(inst) 142 return None 143 144 def get_type_recognizers(): 145 "Return a list of the enabled type recognizers for the current context." 146 result = [] 147 148 # First try the objfiles. 149 for objfile in gdb.objfiles(): 150 _get_some_type_recognizers(result, objfile.type_printers) 151 # Now try the program space. 152 _get_some_type_recognizers(result, gdb.current_progspace().type_printers) 153 # Finally, globals. 154 _get_some_type_recognizers(result, gdb.type_printers) 155 156 return result 157 158 def apply_type_recognizers(recognizers, type_obj): 159 """Apply the given list of type recognizers to the type TYPE_OBJ. 160 If any recognizer in the list recognizes TYPE_OBJ, returns the name 161 given by the recognizer. Otherwise, this returns None.""" 162 for r in recognizers: 163 result = r.recognize(type_obj) 164 if result is not None: 165 return result 166 return None 167 168 def register_type_printer(locus, printer): 169 """Register a type printer. 170 PRINTER is the type printer instance. 171 LOCUS is either an objfile, a program space, or None, indicating 172 global registration.""" 173 174 if locus is None: 175 locus = gdb 176 locus.type_printers.insert(0, printer) 177