1import gdb 2import sys 3 4if sys.version_info[0] >= 3: 5 long = int 6 7 8# This is not quite right, as local vars may override symname 9def read_global_var(symname): 10 return gdb.selected_frame().read_var(symname) 11 12 13def g_quark_to_string(quark): 14 if quark is None: 15 return None 16 quark = long(quark) 17 if quark == 0: 18 return None 19 try: 20 val = read_global_var("quarks") 21 max_q = long(read_global_var("quark_seq_id")) 22 except Exception: 23 try: 24 val = read_global_var("g_quarks") 25 max_q = long(read_global_var("g_quark_seq_id")) 26 except Exception: 27 return None 28 if quark < max_q: 29 return val[quark].string() 30 return None 31 32 33# We override the node printers too, so that node->next is not expanded 34class GListNodePrinter: 35 "Prints a GList node" 36 37 def __init__(self, val): 38 self.val = val 39 40 def to_string(self): 41 return "{data=%s, next=0x%x, prev=0x%x}" % ( 42 str(self.val["data"]), 43 long(self.val["next"]), 44 long(self.val["prev"]), 45 ) 46 47 48class GSListNodePrinter: 49 "Prints a GSList node" 50 51 def __init__(self, val): 52 self.val = val 53 54 def to_string(self): 55 return "{data=%s, next=0x%x}" % (str(self.val["data"]), long(self.val["next"])) 56 57 58class GListPrinter: 59 "Prints a GList" 60 61 class _iterator: 62 def __init__(self, head, listtype): 63 self.link = head 64 self.listtype = listtype 65 self.count = 0 66 67 def __iter__(self): 68 return self 69 70 def next(self): 71 if self.link == 0: 72 raise StopIteration 73 data = self.link["data"] 74 self.link = self.link["next"] 75 count = self.count 76 self.count = self.count + 1 77 return ("[%d]" % count, data) 78 79 __next__ = next 80 81 def __init__(self, val, listtype): 82 self.val = val 83 self.listtype = listtype 84 85 def children(self): 86 return self._iterator(self.val, self.listtype) 87 88 def to_string(self): 89 return "0x%x" % (long(self.val)) 90 91 def display_hint(self): 92 return "array" 93 94 95class GHashPrinter: 96 "Prints a GHashTable" 97 98 class _iterator: 99 class _pointer_array: 100 def __init__(self, ptr, big_items): 101 self._big_items = big_items 102 self._gpointer_type = gdb.lookup_type("gpointer") 103 item_type = ( 104 self._gpointer_type if self._big_items else gdb.lookup_type("guint") 105 ) 106 107 self._items = ptr.cast(item_type.pointer()) 108 109 def __getitem__(self, item): 110 item = self._items[item] 111 112 if not self._big_items: 113 item = item.cast(self._gpointer_type) 114 115 return item 116 117 def __init__(self, ht, keys_are_strings): 118 self.ht = ht 119 if ht != 0: 120 self.keys = self._pointer_array(ht["keys"], ht["have_big_keys"]) 121 self.values = self._pointer_array(ht["values"], ht["have_big_values"]) 122 self.hashes = ht["hashes"] 123 self.size = ht["size"] 124 self.pos = 0 125 self.keys_are_strings = keys_are_strings 126 self.value = None 127 128 def __iter__(self): 129 return self 130 131 def next(self): 132 if self.ht == 0: 133 raise StopIteration 134 if self.value is not None: 135 v = self.value 136 self.value = None 137 return v 138 while long(self.pos) < long(self.size): 139 if long(self.hashes[self.pos]) >= 2: 140 key = self.keys[self.pos] 141 val = self.values[self.pos] 142 143 if self.keys_are_strings: 144 key = key.cast(gdb.lookup_type("char").pointer()) 145 146 # Queue value for next result 147 self.value = ("[%dv]" % (self.pos), val) 148 149 # Increment pos and return key 150 key = ("[%dk]" % (self.pos), key) 151 self.pos += 1 152 return key 153 154 self.pos += 1 155 raise StopIteration 156 157 __next__ = next 158 159 def __init__(self, val): 160 self.val = val 161 self.keys_are_strings = False 162 try: 163 string_hash = read_global_var("g_str_hash") 164 except Exception: 165 string_hash = None 166 if ( 167 self.val != 0 168 and string_hash is not None 169 and self.val["hash_func"] == string_hash 170 ): 171 self.keys_are_strings = True 172 173 def children(self): 174 return self._iterator(self.val, self.keys_are_strings) 175 176 def to_string(self): 177 return "0x%x" % (long(self.val)) 178 179 def display_hint(self): 180 return "map" 181 182 183def pretty_printer_lookup(val): 184 # None yet, want things like hash table and list 185 186 type = val.type.unqualified() 187 188 # If it points to a reference, get the reference. 189 if type.code == gdb.TYPE_CODE_REF: 190 type = type.target() 191 192 if type.code == gdb.TYPE_CODE_PTR: 193 type = type.target().unqualified() 194 t = str(type) 195 if t == "GList": 196 return GListPrinter(val, "GList") 197 if t == "GSList": 198 return GListPrinter(val, "GSList") 199 if t == "GHashTable": 200 return GHashPrinter(val) 201 else: 202 t = str(type) 203 if t == "GList": 204 return GListNodePrinter(val) 205 if t == "GSList *": 206 return GListPrinter(val, "GSList") 207 return None 208 209 210def register(obj): 211 if obj is None: 212 obj = gdb 213 214 obj.pretty_printers.append(pretty_printer_lookup) 215 216 217class ForeachCommand(gdb.Command): 218 """Foreach on list""" 219 220 def __init__(self): 221 super(ForeachCommand, self).__init__( 222 "gforeach", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL 223 ) 224 225 def valid_name(self, name): 226 if not name[0].isalpha(): 227 return False 228 return True 229 230 def parse_args(self, arg): 231 i = arg.find(" ") 232 if i <= 0: 233 raise Exception("No var specified") 234 var = arg[:i] 235 if not self.valid_name(var): 236 raise Exception("Invalid variable name") 237 238 while i < len(arg) and arg[i].isspace(): 239 i = i + 1 240 241 if arg[i : i + 2] != "in": 242 raise Exception("Invalid syntax, missing in") 243 244 i = i + 2 245 246 while i < len(arg) and arg[i].isspace(): 247 i = i + 1 248 249 colon = arg.find(":", i) 250 if colon == -1: 251 raise Exception("Invalid syntax, missing colon") 252 253 val = arg[i:colon] 254 255 colon = colon + 1 256 while colon < len(arg) and arg[colon].isspace(): 257 colon = colon + 1 258 259 command = arg[colon:] 260 261 return (var, val, command) 262 263 def do_iter(self, arg, item, command): 264 item = item.cast(gdb.lookup_type("void").pointer()) 265 item = long(item) 266 to_eval = "set $%s = (void *)0x%x\n" % (arg, item) 267 gdb.execute(to_eval) 268 gdb.execute(command) 269 270 def slist_iterator(self, arg, container, command): 271 list_element = container.cast(gdb.lookup_type("GSList").pointer()) 272 while long(list_element) != 0: 273 self.do_iter(arg, list_element["data"], command) 274 list_element = list_element["next"] 275 276 def list_iterator(self, arg, container, command): 277 list_element = container.cast(gdb.lookup_type("GList").pointer()) 278 while long(list_element) != 0: 279 self.do_iter(arg, list_element["data"], command) 280 list_element = list_element["next"] 281 282 def pick_iterator(self, container): 283 t = container.type.unqualified() 284 if t.code == gdb.TYPE_CODE_PTR: 285 t = t.target().unqualified() 286 t = str(t) 287 if t == "GSList": 288 return self.slist_iterator 289 if t == "GList": 290 return self.list_iterator 291 raise Exception("Invalid container type %s" % (str(container.type))) 292 293 def invoke(self, arg, from_tty): 294 (var, container, command) = self.parse_args(arg) 295 container = gdb.parse_and_eval(container) 296 func = self.pick_iterator(container) 297 func(var, container, command) 298 299 300ForeachCommand() 301