Imported Upstream version 2.74.3
[platform/upstream/glib.git] / glib / glib_gdb.py
1 import gdb
2 import sys
3
4 if sys.version_info[0] >= 3:
5     long = int
6
7
8 # This is not quite right, as local vars may override symname
9 def read_global_var(symname):
10     return gdb.selected_frame().read_var(symname)
11
12
13 def 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
34 class 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
48 class 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
58 class 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
95 class 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
183 def 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
210 def register(obj):
211     if obj is None:
212         obj = gdb
213
214     obj.pretty_printers.append(pretty_printer_lookup)
215
216
217 class 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
300 ForeachCommand()