]>
Commit | Line | Data |
---|---|---|
8dce4dbc | 1 | # Python hooks for gdb for debugging GCC |
a945c346 | 2 | # Copyright (C) 2013-2024 Free Software Foundation, Inc. |
8dce4dbc DM |
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 | |
efbf619b | 108 | #5 0x00000000006c288a in expand_function (node=<cgraph_node* 0x7ffff0312720 "foo"/12345>) at ../../src/gcc/cgraphunit.c:1594 |
8dce4dbc DM |
109 | 1594 execute_pass_list (g->get_passes ()->all_passes); |
110 | (gdb) p node | |
efbf619b ML |
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)> | |
59e3393d DM |
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 | ||
4ee2f419 JJ |
136 | Instead (for now) you must access the payload directly: |
137 | (gdb) p ((edge_def**)(bb->preds+1))[0] | |
59e3393d | 138 | $20 = <edge 0x7ffff044d380 (3 -> 5)> |
4ee2f419 | 139 | (gdb) p ((edge_def**)(bb->preds+1))[1] |
59e3393d | 140 | $21 = <edge 0x7ffff044d3b8 (4 -> 5)> |
8dce4dbc | 141 | """ |
17ef89b2 | 142 | import os.path |
8dce4dbc | 143 | import re |
74103219 | 144 | import sys |
b6e5b400 | 145 | import tempfile |
8dce4dbc DM |
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'] | |
fc6b42bb | 157 | SSA_NAME = tree_code_dict['SSA_NAME'] |
8dce4dbc DM |
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 | ||
74103219 JK |
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 | ||
8dce4dbc DM |
170 | class Tree: |
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): | |
74103219 | 179 | return intptr(self.gdbval) |
8dce4dbc DM |
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 TreePrinter: | |
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)]) | |
74103219 | 218 | if intptr(self.gdbval) == 0: |
8dce4dbc DM |
219 | return '<tree 0x0>' |
220 | ||
221 | val_TREE_CODE = self.node.TREE_CODE() | |
222 | ||
be6195c7 | 223 | # constexpr inline enum tree_code_class tree_code_type[] = { ... }; |
8dce4dbc | 224 | # #define TREE_CODE_CLASS(CODE) tree_code_type[(int) (CODE)] |
be6195c7 JJ |
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)] | |
8dce4dbc | 232 | |
92812757 JM |
233 | if val_TREE_CODE == 0xa5a5: |
234 | return '<ggc_freed 0x%x>' % intptr(self.gdbval) | |
235 | ||
be6195c7 JJ |
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') | |
8dce4dbc DM |
240 | val_tclass = val_tree_code_type[val_TREE_CODE] |
241 | ||
242 | val_tree_code_name = gdb.parse_and_eval('tree_code_name') | |
74103219 | 243 | val_code_name = val_tree_code_name[intptr(val_TREE_CODE)] |
4c50b221 | 244 | #print(val_code_name.string()) |
8dce4dbc | 245 | |
224d9de0 ES |
246 | try: |
247 | result = '<%s 0x%x' % (val_code_name.string(), intptr(self.gdbval)) | |
248 | except: | |
249 | return '<tree 0x%x>' % intptr(self.gdbval) | |
74103219 | 250 | if intptr(val_tclass) == tcc_declaration: |
8dce4dbc DM |
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 | |
74103219 | 256 | elif intptr(val_tclass) == tcc_type: |
8dce4dbc DM |
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() | |
fc6b42bb RB |
266 | elif self.node.TREE_CODE() == SSA_NAME: |
267 | result += ' %u' % self.gdbval['base']['u']['version'] | |
8dce4dbc DM |
268 | # etc |
269 | result += '>' | |
270 | return result | |
271 | ||
272 | ###################################################################### | |
273 | # Callgraph pretty-printers | |
274 | ###################################################################### | |
275 | ||
efbf619b | 276 | class SymtabNodePrinter: |
8dce4dbc DM |
277 | def __init__(self, gdbval): |
278 | self.gdbval = gdbval | |
279 | ||
280 | def to_string (self): | |
efbf619b ML |
281 | t = str(self.gdbval.type) |
282 | result = '<%s 0x%x' % (t, intptr(self.gdbval)) | |
74103219 | 283 | if intptr(self.gdbval): |
fec39fa6 | 284 | # symtab_node::name calls lang_hooks.decl_printable_name |
8dce4dbc DM |
285 | # default implementation (lhd_decl_printable_name) is: |
286 | # return IDENTIFIER_POINTER (DECL_NAME (decl)); | |
d19245aa | 287 | tree_decl = Tree(self.gdbval['decl']) |
efbf619b ML |
288 | result += ' "%s"/%d' % (tree_decl.DECL_NAME().IDENTIFIER_POINTER(), self.gdbval['order']) |
289 | result += '>' | |
290 | return result | |
291 | ||
292 | class CgraphEdgePrinter: | |
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 IpaReferencePrinter: | |
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'])) | |
8dce4dbc DM |
315 | result += '>' |
316 | return result | |
317 | ||
53afce20 AH |
318 | ###################################################################### |
319 | # Dwarf DIE pretty-printers | |
320 | ###################################################################### | |
321 | ||
322 | class DWDieRefPrinter: | |
323 | def __init__(self, gdbval): | |
324 | self.gdbval = gdbval | |
325 | ||
326 | def to_string (self): | |
74103219 | 327 | if intptr(self.gdbval) == 0: |
53afce20 | 328 | return '<dw_die_ref 0x0>' |
74103219 | 329 | result = '<dw_die_ref 0x%x' % intptr(self.gdbval) |
53afce20 | 330 | result += ' %s' % self.gdbval['die_tag'] |
74103219 JK |
331 | if intptr(self.gdbval['die_parent']) != 0: |
332 | result += ' <parent=0x%x %s>' % (intptr(self.gdbval['die_parent']), | |
53afce20 AH |
333 | self.gdbval['die_parent']['die_tag']) |
334 | ||
335 | result += '>' | |
336 | return result | |
337 | ||
8dce4dbc DM |
338 | ###################################################################### |
339 | ||
340 | class GimplePrinter: | |
341 | def __init__(self, gdbval): | |
342 | self.gdbval = gdbval | |
343 | ||
344 | def to_string (self): | |
74103219 | 345 | if intptr(self.gdbval) == 0: |
8dce4dbc | 346 | return '<gimple 0x0>' |
daa6e488 | 347 | val_gimple_code = self.gdbval['code'] |
8dce4dbc | 348 | val_gimple_code_name = gdb.parse_and_eval('gimple_code_name') |
74103219 | 349 | val_code_name = val_gimple_code_name[intptr(val_gimple_code)] |
8dce4dbc | 350 | result = '<%s 0x%x' % (val_code_name.string(), |
74103219 | 351 | intptr(self.gdbval)) |
8dce4dbc DM |
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 BasicBlockPrinter: | |
368 | def __init__(self, gdbval): | |
369 | self.gdbval = gdbval | |
370 | ||
371 | def to_string (self): | |
74103219 JK |
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'])) | |
8dce4dbc DM |
375 | result += '>' |
376 | return result | |
377 | ||
378 | class CfgEdgePrinter: | |
379 | def __init__(self, gdbval): | |
380 | self.gdbval = gdbval | |
381 | ||
382 | def to_string (self): | |
74103219 JK |
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'])) | |
8dce4dbc DM |
387 | result += ' (%s -> %s)' % (src, dest) |
388 | result += '>' | |
389 | return result | |
390 | ||
391 | ###################################################################### | |
392 | ||
393 | class Rtx: | |
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') | |
74103219 | 402 | return intptr(val_rtx_length[code]) |
8dce4dbc DM |
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 RtxPrinter: | |
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)' | |
74103219 | 425 | % intptr(self.gdbval)) |
8dce4dbc DM |
426 | return '' |
427 | ||
428 | # or by hand; based on gcc/print-rtl.c:print_rtx | |
429 | result = ('<rtx_def 0x%x' | |
74103219 | 430 | % (intptr(self.gdbval))) |
8dce4dbc DM |
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)): | |
4c50b221 | 435 | print(format_[i]) |
8dce4dbc DM |
436 | result += ')>' |
437 | return result | |
438 | ||
439 | ###################################################################### | |
440 | ||
441 | class PassPrinter: | |
442 | def __init__(self, gdbval): | |
443 | self.gdbval = gdbval | |
444 | ||
445 | def to_string (self): | |
74103219 JK |
446 | result = '<opt_pass* 0x%x' % intptr(self.gdbval) |
447 | if intptr(self.gdbval): | |
8dce4dbc DM |
448 | result += (' "%s"(%i)' |
449 | % (self.gdbval['name'].string(), | |
74103219 | 450 | intptr(self.gdbval['static_pass_number']))) |
8dce4dbc DM |
451 | result += '>' |
452 | return result | |
453 | ||
454 | ###################################################################### | |
455 | ||
59e3393d DM |
456 | class VecPrinter: |
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. | |
74103219 | 467 | return '0x%x' % intptr(self.gdbval) |
59e3393d DM |
468 | |
469 | def children (self): | |
74103219 | 470 | if intptr(self.gdbval) == 0: |
1fef3644 | 471 | return |
59e3393d DM |
472 | m_vecpfx = self.gdbval['m_vecpfx'] |
473 | m_num = m_vecpfx['m_num'] | |
59a576f2 JW |
474 | val = self.gdbval |
475 | typ = val.type | |
ce1c99f1 JW |
476 | if typ.code == gdb.TYPE_CODE_PTR: |
477 | typ = typ.target() | |
59a576f2 JW |
478 | else: |
479 | val = val.address | |
480 | typ_T = typ.template_argument(0) # the type T | |
481 | vecdata = (val + 1).cast(typ_T.pointer()) | |
59e3393d | 482 | for i in range(m_num): |
59a576f2 | 483 | yield ('[%d]' % i, vecdata[i]) |
59e3393d DM |
484 | |
485 | ###################################################################### | |
486 | ||
e386a52f RS |
487 | class MachineModePrinter: |
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 | ||
490d0f6c RS |
497 | class OptMachineModePrinter: |
498 | def __init__(self, gdbval): | |
499 | self.gdbval = gdbval | |
500 | ||
501 | def to_string (self): | |
502 | name = str(self.gdbval['m_mode']) | |
40008742 JJ |
503 | if name == 'E_VOIDmode': |
504 | return '<None>' | |
490d0f6c RS |
505 | return name[2:] if name.startswith('E_') else name |
506 | ||
507 | ###################################################################### | |
508 | ||
8dce4dbc | 509 | # TODO: |
8dce4dbc DM |
510 | # * hashtab |
511 | # * location_t | |
512 | ||
513 | class GdbSubprinter(gdb.printing.SubPrettyPrinter): | |
8f1edba1 | 514 | def __init__(self, name, class_): |
8dce4dbc | 515 | super(GdbSubprinter, self).__init__(name) |
8dce4dbc DM |
516 | self.class_ = class_ |
517 | ||
8f1edba1 DM |
518 | def handles_type(self, str_type): |
519 | raise NotImplementedError | |
520 | ||
521 | class GdbSubprinterTypeList(GdbSubprinter): | |
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 GdbSubprinterRegex(GdbSubprinter): | |
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 | ||
8dce4dbc DM |
543 | class GdbPrettyPrinters(gdb.printing.PrettyPrinter): |
544 | def __init__(self, name): | |
545 | super(GdbPrettyPrinters, self).__init__(name, []) | |
546 | ||
823d12a8 VI |
547 | def add_printer_for_types(self, types, name, class_): |
548 | self.subprinters.append(GdbSubprinterTypeList(types, name, class_)) | |
8f1edba1 | 549 | |
823d12a8 VI |
550 | def add_printer_for_regex(self, regex, name, class_): |
551 | self.subprinters.append(GdbSubprinterRegex(regex, name, class_)) | |
8dce4dbc DM |
552 | |
553 | def __call__(self, gdbval): | |
554 | type_ = gdbval.type.unqualified() | |
8f1edba1 | 555 | str_type = str(type_) |
8dce4dbc | 556 | for printer in self.subprinters: |
8f1edba1 | 557 | if printer.enabled and printer.handles_type(str_type): |
8dce4dbc DM |
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') | |
decc53df | 566 | pp.add_printer_for_types(['tree', 'const_tree'], |
8f1edba1 | 567 | 'tree', TreePrinter) |
efbf619b ML |
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) | |
53afce20 AH |
574 | pp.add_printer_for_types(['dw_die_ref'], |
575 | 'dw_die_ref', DWDieRefPrinter) | |
7b954766 | 576 | pp.add_printer_for_types(['gimple', 'gimple *', |
538dd0b7 DM |
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 | ||
8f1edba1 DM |
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 | ||
59e3393d DM |
605 | pp.add_printer_for_regex(r'vec<(\S+), (\S+), (\S+)> \*', |
606 | 'vec', | |
607 | VecPrinter) | |
608 | ||
490d0f6c RS |
609 | pp.add_printer_for_regex(r'opt_mode<(\S+)>', |
610 | 'opt_mode', OptMachineModePrinter) | |
501623d4 | 611 | pp.add_printer_for_types(['opt_scalar_int_mode', |
16d22000 RS |
612 | 'opt_scalar_float_mode', |
613 | 'opt_scalar_mode'], | |
857c7b46 | 614 | 'opt_mode', OptMachineModePrinter) |
bf862c53 RS |
615 | pp.add_printer_for_regex(r'pod_mode<(\S+)>', |
616 | 'pod_mode', MachineModePrinter) | |
382615c6 RS |
617 | pp.add_printer_for_types(['scalar_int_mode_pod', |
618 | 'scalar_mode_pod'], | |
bf862c53 | 619 | 'pod_mode', MachineModePrinter) |
a97390bf RS |
620 | for mode in ('scalar_mode', 'scalar_int_mode', 'scalar_float_mode', |
621 | 'complex_mode'): | |
501623d4 | 622 | pp.add_printer_for_types([mode], mode, MachineModePrinter) |
490d0f6c | 623 | |
8dce4dbc DM |
624 | return pp |
625 | ||
626 | gdb.printing.register_pretty_printer( | |
627 | gdb.current_objfile(), | |
e41dd068 VI |
628 | build_pretty_printer(), |
629 | replace=True) | |
8dce4dbc | 630 | |
17ef89b2 DM |
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 PassNames: | |
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: | |
945cb849 | 645 | m = re.match(r'\s*NEXT_PASS \(([^,]+).*\);', line) |
17ef89b2 DM |
646 | if m: |
647 | self.names.append(m.group(1)) | |
648 | ||
649 | class BreakOnPass(gdb.Command): | |
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 | ||
b6e5b400 TV |
697 | class DumpFn(gdb.Command): |
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 | |
cbfde6ee | 764 | fp = gdb.parse_and_eval("(FILE *) fopen (\"%s\", \"w\")" % filename) |
b6e5b400 TV |
765 | if fp == 0: |
766 | print ("Could not open file: %s" % filename) | |
767 | return | |
b6e5b400 TV |
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 | |
cbfde6ee | 774 | ret = gdb.parse_and_eval("(int) fclose (%s)" % fp) |
b6e5b400 TV |
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 | ||
bddb7adb RB |
786 | class DotFn(gdb.Command): |
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() | |
cbfde6ee | 833 | fp = gdb.parse_and_eval("(FILE *) fopen (\"%s\", \"w\")" % filename) |
bddb7adb RB |
834 | if fp == 0: |
835 | print("Cannot open temp file") | |
836 | return | |
bddb7adb RB |
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 | |
cbfde6ee | 845 | ret = gdb.parse_and_eval("(int) fclose (%s)" % fp) |
bddb7adb RB |
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 | ||
8dce4dbc | 855 | print('Successfully loaded GDB hooks for GCC') |