• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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