]>
Commit | Line | Data |
---|---|---|
8dce4dbc | 1 | # Python hooks for gdb for debugging GCC |
7adcbafe | 2 | # Copyright (C) 2013-2022 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 | ||
136 | Instead (for now) you must access m_vecdata: | |
137 | (gdb) p bb->preds->m_vecdata[0] | |
138 | $20 = <edge 0x7ffff044d380 (3 -> 5)> | |
139 | (gdb) p bb->preds->m_vecdata[1] | |
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 | ||
223 | # extern const enum tree_code_class tree_code_type[]; | |
224 | # #define TREE_CODE_CLASS(CODE) tree_code_type[(int) (CODE)] | |
225 | ||
92812757 JM |
226 | if val_TREE_CODE == 0xa5a5: |
227 | return '<ggc_freed 0x%x>' % intptr(self.gdbval) | |
228 | ||
8dce4dbc DM |
229 | val_tree_code_type = gdb.parse_and_eval('tree_code_type') |
230 | val_tclass = val_tree_code_type[val_TREE_CODE] | |
231 | ||
232 | val_tree_code_name = gdb.parse_and_eval('tree_code_name') | |
74103219 | 233 | val_code_name = val_tree_code_name[intptr(val_TREE_CODE)] |
4c50b221 | 234 | #print(val_code_name.string()) |
8dce4dbc | 235 | |
224d9de0 ES |
236 | try: |
237 | result = '<%s 0x%x' % (val_code_name.string(), intptr(self.gdbval)) | |
238 | except: | |
239 | return '<tree 0x%x>' % intptr(self.gdbval) | |
74103219 | 240 | if intptr(val_tclass) == tcc_declaration: |
8dce4dbc DM |
241 | tree_DECL_NAME = self.node.DECL_NAME() |
242 | if tree_DECL_NAME.is_nonnull(): | |
243 | result += ' %s' % tree_DECL_NAME.IDENTIFIER_POINTER() | |
244 | else: | |
245 | pass # TODO: labels etc | |
74103219 | 246 | elif intptr(val_tclass) == tcc_type: |
8dce4dbc DM |
247 | tree_TYPE_NAME = Tree(self.gdbval['type_common']['name']) |
248 | if tree_TYPE_NAME.is_nonnull(): | |
249 | if tree_TYPE_NAME.TREE_CODE() == IDENTIFIER_NODE: | |
250 | result += ' %s' % tree_TYPE_NAME.IDENTIFIER_POINTER() | |
251 | elif tree_TYPE_NAME.TREE_CODE() == TYPE_DECL: | |
252 | if tree_TYPE_NAME.DECL_NAME().is_nonnull(): | |
253 | result += ' %s' % tree_TYPE_NAME.DECL_NAME().IDENTIFIER_POINTER() | |
254 | if self.node.TREE_CODE() == IDENTIFIER_NODE: | |
255 | result += ' %s' % self.node.IDENTIFIER_POINTER() | |
fc6b42bb RB |
256 | elif self.node.TREE_CODE() == SSA_NAME: |
257 | result += ' %u' % self.gdbval['base']['u']['version'] | |
8dce4dbc DM |
258 | # etc |
259 | result += '>' | |
260 | return result | |
261 | ||
262 | ###################################################################### | |
263 | # Callgraph pretty-printers | |
264 | ###################################################################### | |
265 | ||
efbf619b | 266 | class SymtabNodePrinter: |
8dce4dbc DM |
267 | def __init__(self, gdbval): |
268 | self.gdbval = gdbval | |
269 | ||
270 | def to_string (self): | |
efbf619b ML |
271 | t = str(self.gdbval.type) |
272 | result = '<%s 0x%x' % (t, intptr(self.gdbval)) | |
74103219 | 273 | if intptr(self.gdbval): |
fec39fa6 | 274 | # symtab_node::name calls lang_hooks.decl_printable_name |
8dce4dbc DM |
275 | # default implementation (lhd_decl_printable_name) is: |
276 | # return IDENTIFIER_POINTER (DECL_NAME (decl)); | |
d19245aa | 277 | tree_decl = Tree(self.gdbval['decl']) |
efbf619b ML |
278 | result += ' "%s"/%d' % (tree_decl.DECL_NAME().IDENTIFIER_POINTER(), self.gdbval['order']) |
279 | result += '>' | |
280 | return result | |
281 | ||
282 | class CgraphEdgePrinter: | |
283 | def __init__(self, gdbval): | |
284 | self.gdbval = gdbval | |
285 | ||
286 | def to_string (self): | |
287 | result = '<cgraph_edge* 0x%x' % intptr(self.gdbval) | |
288 | if intptr(self.gdbval): | |
289 | src = SymtabNodePrinter(self.gdbval['caller']).to_string() | |
290 | dest = SymtabNodePrinter(self.gdbval['callee']).to_string() | |
291 | result += ' (%s -> %s)' % (src, dest) | |
292 | result += '>' | |
293 | return result | |
294 | ||
295 | class IpaReferencePrinter: | |
296 | def __init__(self, gdbval): | |
297 | self.gdbval = gdbval | |
298 | ||
299 | def to_string (self): | |
300 | result = '<ipa_ref* 0x%x' % intptr(self.gdbval) | |
301 | if intptr(self.gdbval): | |
302 | src = SymtabNodePrinter(self.gdbval['referring']).to_string() | |
303 | dest = SymtabNodePrinter(self.gdbval['referred']).to_string() | |
304 | result += ' (%s -> %s:%s)' % (src, dest, str(self.gdbval['use'])) | |
8dce4dbc DM |
305 | result += '>' |
306 | return result | |
307 | ||
53afce20 AH |
308 | ###################################################################### |
309 | # Dwarf DIE pretty-printers | |
310 | ###################################################################### | |
311 | ||
312 | class DWDieRefPrinter: | |
313 | def __init__(self, gdbval): | |
314 | self.gdbval = gdbval | |
315 | ||
316 | def to_string (self): | |
74103219 | 317 | if intptr(self.gdbval) == 0: |
53afce20 | 318 | return '<dw_die_ref 0x0>' |
74103219 | 319 | result = '<dw_die_ref 0x%x' % intptr(self.gdbval) |
53afce20 | 320 | result += ' %s' % self.gdbval['die_tag'] |
74103219 JK |
321 | if intptr(self.gdbval['die_parent']) != 0: |
322 | result += ' <parent=0x%x %s>' % (intptr(self.gdbval['die_parent']), | |
53afce20 AH |
323 | self.gdbval['die_parent']['die_tag']) |
324 | ||
325 | result += '>' | |
326 | return result | |
327 | ||
8dce4dbc DM |
328 | ###################################################################### |
329 | ||
330 | class GimplePrinter: | |
331 | def __init__(self, gdbval): | |
332 | self.gdbval = gdbval | |
333 | ||
334 | def to_string (self): | |
74103219 | 335 | if intptr(self.gdbval) == 0: |
8dce4dbc | 336 | return '<gimple 0x0>' |
daa6e488 | 337 | val_gimple_code = self.gdbval['code'] |
8dce4dbc | 338 | val_gimple_code_name = gdb.parse_and_eval('gimple_code_name') |
74103219 | 339 | val_code_name = val_gimple_code_name[intptr(val_gimple_code)] |
8dce4dbc | 340 | result = '<%s 0x%x' % (val_code_name.string(), |
74103219 | 341 | intptr(self.gdbval)) |
8dce4dbc DM |
342 | result += '>' |
343 | return result | |
344 | ||
345 | ###################################################################### | |
346 | # CFG pretty-printers | |
347 | ###################################################################### | |
348 | ||
349 | def bb_index_to_str(index): | |
350 | if index == 0: | |
351 | return 'ENTRY' | |
352 | elif index == 1: | |
353 | return 'EXIT' | |
354 | else: | |
355 | return '%i' % index | |
356 | ||
357 | class BasicBlockPrinter: | |
358 | def __init__(self, gdbval): | |
359 | self.gdbval = gdbval | |
360 | ||
361 | def to_string (self): | |
74103219 JK |
362 | result = '<basic_block 0x%x' % intptr(self.gdbval) |
363 | if intptr(self.gdbval): | |
364 | result += ' (%s)' % bb_index_to_str(intptr(self.gdbval['index'])) | |
8dce4dbc DM |
365 | result += '>' |
366 | return result | |
367 | ||
368 | class CfgEdgePrinter: | |
369 | def __init__(self, gdbval): | |
370 | self.gdbval = gdbval | |
371 | ||
372 | def to_string (self): | |
74103219 JK |
373 | result = '<edge 0x%x' % intptr(self.gdbval) |
374 | if intptr(self.gdbval): | |
375 | src = bb_index_to_str(intptr(self.gdbval['src']['index'])) | |
376 | dest = bb_index_to_str(intptr(self.gdbval['dest']['index'])) | |
8dce4dbc DM |
377 | result += ' (%s -> %s)' % (src, dest) |
378 | result += '>' | |
379 | return result | |
380 | ||
381 | ###################################################################### | |
382 | ||
383 | class Rtx: | |
384 | def __init__(self, gdbval): | |
385 | self.gdbval = gdbval | |
386 | ||
387 | def GET_CODE(self): | |
388 | return self.gdbval['code'] | |
389 | ||
390 | def GET_RTX_LENGTH(code): | |
391 | val_rtx_length = gdb.parse_and_eval('rtx_length') | |
74103219 | 392 | return intptr(val_rtx_length[code]) |
8dce4dbc DM |
393 | |
394 | def GET_RTX_NAME(code): | |
395 | val_rtx_name = gdb.parse_and_eval('rtx_name') | |
396 | return val_rtx_name[code].string() | |
397 | ||
398 | def GET_RTX_FORMAT(code): | |
399 | val_rtx_format = gdb.parse_and_eval('rtx_format') | |
400 | return val_rtx_format[code].string() | |
401 | ||
402 | class RtxPrinter: | |
403 | def __init__(self, gdbval): | |
404 | self.gdbval = gdbval | |
405 | self.rtx = Rtx(gdbval) | |
406 | ||
407 | def to_string (self): | |
408 | """ | |
409 | For now, a cheap kludge: invoke the inferior's print | |
410 | function to get a string to use the user, and return an empty | |
411 | string for gdb | |
412 | """ | |
413 | # We use print_inline_rtx to avoid a trailing newline | |
414 | gdb.execute('call print_inline_rtx (stderr, (const_rtx) %s, 0)' | |
74103219 | 415 | % intptr(self.gdbval)) |
8dce4dbc DM |
416 | return '' |
417 | ||
418 | # or by hand; based on gcc/print-rtl.c:print_rtx | |
419 | result = ('<rtx_def 0x%x' | |
74103219 | 420 | % (intptr(self.gdbval))) |
8dce4dbc DM |
421 | code = self.rtx.GET_CODE() |
422 | result += ' (%s' % GET_RTX_NAME(code) | |
423 | format_ = GET_RTX_FORMAT(code) | |
424 | for i in range(GET_RTX_LENGTH(code)): | |
4c50b221 | 425 | print(format_[i]) |
8dce4dbc DM |
426 | result += ')>' |
427 | return result | |
428 | ||
429 | ###################################################################### | |
430 | ||
431 | class PassPrinter: | |
432 | def __init__(self, gdbval): | |
433 | self.gdbval = gdbval | |
434 | ||
435 | def to_string (self): | |
74103219 JK |
436 | result = '<opt_pass* 0x%x' % intptr(self.gdbval) |
437 | if intptr(self.gdbval): | |
8dce4dbc DM |
438 | result += (' "%s"(%i)' |
439 | % (self.gdbval['name'].string(), | |
74103219 | 440 | intptr(self.gdbval['static_pass_number']))) |
8dce4dbc DM |
441 | result += '>' |
442 | return result | |
443 | ||
444 | ###################################################################### | |
445 | ||
59e3393d DM |
446 | class VecPrinter: |
447 | # -ex "up" -ex "p bb->preds" | |
448 | def __init__(self, gdbval): | |
449 | self.gdbval = gdbval | |
450 | ||
451 | def display_hint (self): | |
452 | return 'array' | |
453 | ||
454 | def to_string (self): | |
455 | # A trivial implementation; prettyprinting the contents is done | |
456 | # by gdb calling the "children" method below. | |
74103219 | 457 | return '0x%x' % intptr(self.gdbval) |
59e3393d DM |
458 | |
459 | def children (self): | |
74103219 | 460 | if intptr(self.gdbval) == 0: |
1fef3644 | 461 | return |
59e3393d DM |
462 | m_vecpfx = self.gdbval['m_vecpfx'] |
463 | m_num = m_vecpfx['m_num'] | |
464 | m_vecdata = self.gdbval['m_vecdata'] | |
465 | for i in range(m_num): | |
466 | yield ('[%d]' % i, m_vecdata[i]) | |
467 | ||
468 | ###################################################################### | |
469 | ||
e386a52f RS |
470 | class MachineModePrinter: |
471 | def __init__(self, gdbval): | |
472 | self.gdbval = gdbval | |
473 | ||
474 | def to_string (self): | |
475 | name = str(self.gdbval['m_mode']) | |
476 | return name[2:] if name.startswith('E_') else name | |
477 | ||
478 | ###################################################################### | |
479 | ||
490d0f6c RS |
480 | class OptMachineModePrinter: |
481 | def __init__(self, gdbval): | |
482 | self.gdbval = gdbval | |
483 | ||
484 | def to_string (self): | |
485 | name = str(self.gdbval['m_mode']) | |
40008742 JJ |
486 | if name == 'E_VOIDmode': |
487 | return '<None>' | |
490d0f6c RS |
488 | return name[2:] if name.startswith('E_') else name |
489 | ||
490 | ###################################################################### | |
491 | ||
8dce4dbc | 492 | # TODO: |
8dce4dbc DM |
493 | # * hashtab |
494 | # * location_t | |
495 | ||
496 | class GdbSubprinter(gdb.printing.SubPrettyPrinter): | |
8f1edba1 | 497 | def __init__(self, name, class_): |
8dce4dbc | 498 | super(GdbSubprinter, self).__init__(name) |
8dce4dbc DM |
499 | self.class_ = class_ |
500 | ||
8f1edba1 DM |
501 | def handles_type(self, str_type): |
502 | raise NotImplementedError | |
503 | ||
504 | class GdbSubprinterTypeList(GdbSubprinter): | |
505 | """ | |
506 | A GdbSubprinter that handles a specific set of types | |
507 | """ | |
508 | def __init__(self, str_types, name, class_): | |
509 | super(GdbSubprinterTypeList, self).__init__(name, class_) | |
510 | self.str_types = frozenset(str_types) | |
511 | ||
512 | def handles_type(self, str_type): | |
513 | return str_type in self.str_types | |
514 | ||
515 | class GdbSubprinterRegex(GdbSubprinter): | |
516 | """ | |
517 | A GdbSubprinter that handles types that match a regex | |
518 | """ | |
519 | def __init__(self, regex, name, class_): | |
520 | super(GdbSubprinterRegex, self).__init__(name, class_) | |
521 | self.regex = re.compile(regex) | |
522 | ||
523 | def handles_type(self, str_type): | |
524 | return self.regex.match(str_type) | |
525 | ||
8dce4dbc DM |
526 | class GdbPrettyPrinters(gdb.printing.PrettyPrinter): |
527 | def __init__(self, name): | |
528 | super(GdbPrettyPrinters, self).__init__(name, []) | |
529 | ||
823d12a8 VI |
530 | def add_printer_for_types(self, types, name, class_): |
531 | self.subprinters.append(GdbSubprinterTypeList(types, name, class_)) | |
8f1edba1 | 532 | |
823d12a8 VI |
533 | def add_printer_for_regex(self, regex, name, class_): |
534 | self.subprinters.append(GdbSubprinterRegex(regex, name, class_)) | |
8dce4dbc DM |
535 | |
536 | def __call__(self, gdbval): | |
537 | type_ = gdbval.type.unqualified() | |
8f1edba1 | 538 | str_type = str(type_) |
8dce4dbc | 539 | for printer in self.subprinters: |
8f1edba1 | 540 | if printer.enabled and printer.handles_type(str_type): |
8dce4dbc DM |
541 | return printer.class_(gdbval) |
542 | ||
543 | # Couldn't find a pretty printer (or it was disabled): | |
544 | return None | |
545 | ||
546 | ||
547 | def build_pretty_printer(): | |
548 | pp = GdbPrettyPrinters('gcc') | |
decc53df | 549 | pp.add_printer_for_types(['tree', 'const_tree'], |
8f1edba1 | 550 | 'tree', TreePrinter) |
efbf619b ML |
551 | pp.add_printer_for_types(['cgraph_node *', 'varpool_node *', 'symtab_node *'], |
552 | 'symtab_node', SymtabNodePrinter) | |
553 | pp.add_printer_for_types(['cgraph_edge *'], | |
554 | 'cgraph_edge', CgraphEdgePrinter) | |
555 | pp.add_printer_for_types(['ipa_ref *'], | |
556 | 'ipa_ref', IpaReferencePrinter) | |
53afce20 AH |
557 | pp.add_printer_for_types(['dw_die_ref'], |
558 | 'dw_die_ref', DWDieRefPrinter) | |
7b954766 | 559 | pp.add_printer_for_types(['gimple', 'gimple *', |
538dd0b7 DM |
560 | |
561 | # Keep this in the same order as gimple.def: | |
562 | 'gimple_cond', 'const_gimple_cond', | |
563 | 'gimple_statement_cond *', | |
564 | 'gimple_debug', 'const_gimple_debug', | |
565 | 'gimple_statement_debug *', | |
566 | 'gimple_label', 'const_gimple_label', | |
567 | 'gimple_statement_label *', | |
568 | 'gimple_switch', 'const_gimple_switch', | |
569 | 'gimple_statement_switch *', | |
570 | 'gimple_assign', 'const_gimple_assign', | |
571 | 'gimple_statement_assign *', | |
572 | 'gimple_bind', 'const_gimple_bind', | |
573 | 'gimple_statement_bind *', | |
574 | 'gimple_phi', 'const_gimple_phi', | |
575 | 'gimple_statement_phi *'], | |
576 | ||
8f1edba1 DM |
577 | 'gimple', |
578 | GimplePrinter) | |
579 | pp.add_printer_for_types(['basic_block', 'basic_block_def *'], | |
580 | 'basic_block', | |
581 | BasicBlockPrinter) | |
582 | pp.add_printer_for_types(['edge', 'edge_def *'], | |
583 | 'edge', | |
584 | CfgEdgePrinter) | |
585 | pp.add_printer_for_types(['rtx_def *'], 'rtx_def', RtxPrinter) | |
586 | pp.add_printer_for_types(['opt_pass *'], 'opt_pass', PassPrinter) | |
587 | ||
59e3393d DM |
588 | pp.add_printer_for_regex(r'vec<(\S+), (\S+), (\S+)> \*', |
589 | 'vec', | |
590 | VecPrinter) | |
591 | ||
490d0f6c RS |
592 | pp.add_printer_for_regex(r'opt_mode<(\S+)>', |
593 | 'opt_mode', OptMachineModePrinter) | |
501623d4 | 594 | pp.add_printer_for_types(['opt_scalar_int_mode', |
16d22000 RS |
595 | 'opt_scalar_float_mode', |
596 | 'opt_scalar_mode'], | |
857c7b46 | 597 | 'opt_mode', OptMachineModePrinter) |
bf862c53 RS |
598 | pp.add_printer_for_regex(r'pod_mode<(\S+)>', |
599 | 'pod_mode', MachineModePrinter) | |
382615c6 RS |
600 | pp.add_printer_for_types(['scalar_int_mode_pod', |
601 | 'scalar_mode_pod'], | |
bf862c53 | 602 | 'pod_mode', MachineModePrinter) |
a97390bf RS |
603 | for mode in ('scalar_mode', 'scalar_int_mode', 'scalar_float_mode', |
604 | 'complex_mode'): | |
501623d4 | 605 | pp.add_printer_for_types([mode], mode, MachineModePrinter) |
490d0f6c | 606 | |
8dce4dbc DM |
607 | return pp |
608 | ||
609 | gdb.printing.register_pretty_printer( | |
610 | gdb.current_objfile(), | |
e41dd068 VI |
611 | build_pretty_printer(), |
612 | replace=True) | |
8dce4dbc | 613 | |
17ef89b2 DM |
614 | def find_gcc_source_dir(): |
615 | # Use location of global "g" to locate the source tree | |
616 | sym_g = gdb.lookup_global_symbol('g') | |
617 | path = sym_g.symtab.filename # e.g. '../../src/gcc/context.h' | |
618 | srcdir = os.path.split(path)[0] # e.g. '../../src/gcc' | |
619 | return srcdir | |
620 | ||
621 | class PassNames: | |
622 | """Parse passes.def, gathering a list of pass class names""" | |
623 | def __init__(self): | |
624 | srcdir = find_gcc_source_dir() | |
625 | self.names = [] | |
626 | with open(os.path.join(srcdir, 'passes.def')) as f: | |
627 | for line in f: | |
b0c77505 | 628 | m = re.match('\s*NEXT_PASS \(([^,]+).*\);', line) |
17ef89b2 DM |
629 | if m: |
630 | self.names.append(m.group(1)) | |
631 | ||
632 | class BreakOnPass(gdb.Command): | |
633 | """ | |
634 | A custom command for putting breakpoints on the execute hook of passes. | |
635 | This is largely a workaround for issues with tab-completion in gdb when | |
636 | setting breakpoints on methods on classes within anonymous namespaces. | |
637 | ||
638 | Example of use: putting a breakpoint on "final" | |
639 | (gdb) break-on-pass | |
640 | Press <TAB>; it autocompletes to "pass_": | |
641 | (gdb) break-on-pass pass_ | |
642 | Press <TAB>: | |
643 | Display all 219 possibilities? (y or n) | |
644 | Press "n"; then type "f": | |
645 | (gdb) break-on-pass pass_f | |
646 | Press <TAB> to autocomplete to pass classnames beginning with "pass_f": | |
647 | pass_fast_rtl_dce pass_fold_builtins | |
648 | pass_feedback_split_functions pass_forwprop | |
649 | pass_final pass_fre | |
650 | pass_fixup_cfg pass_free_cfg | |
651 | Type "in<TAB>" to complete to "pass_final": | |
652 | (gdb) break-on-pass pass_final | |
653 | ...and hit <RETURN>: | |
654 | Breakpoint 6 at 0x8396ba: file ../../src/gcc/final.c, line 4526. | |
655 | ...and we have a breakpoint set; continue execution: | |
656 | (gdb) cont | |
657 | Continuing. | |
658 | Breakpoint 6, (anonymous namespace)::pass_final::execute (this=0x17fb990) at ../../src/gcc/final.c:4526 | |
659 | 4526 virtual unsigned int execute (function *) { return rest_of_handle_final (); } | |
660 | """ | |
661 | def __init__(self): | |
662 | gdb.Command.__init__(self, 'break-on-pass', gdb.COMMAND_BREAKPOINTS) | |
663 | self.pass_names = None | |
664 | ||
665 | def complete(self, text, word): | |
666 | # Lazily load pass names: | |
667 | if not self.pass_names: | |
668 | self.pass_names = PassNames() | |
669 | ||
670 | return [name | |
671 | for name in sorted(self.pass_names.names) | |
672 | if name.startswith(text)] | |
673 | ||
674 | def invoke(self, arg, from_tty): | |
675 | sym = '(anonymous namespace)::%s::execute' % arg | |
676 | breakpoint = gdb.Breakpoint(sym) | |
677 | ||
678 | BreakOnPass() | |
679 | ||
b6e5b400 TV |
680 | class DumpFn(gdb.Command): |
681 | """ | |
682 | A custom command to dump a gimple/rtl function to file. By default, it | |
683 | dumps the current function using 0 as dump_flags, but the function and flags | |
684 | can also be specified. If /f <file> are passed as the first two arguments, | |
685 | the dump is written to that file. Otherwise, a temporary file is created | |
686 | and opened in the text editor specified in the EDITOR environment variable. | |
687 | ||
688 | Examples of use: | |
689 | (gdb) dump-fn | |
690 | (gdb) dump-fn /f foo.1.txt | |
691 | (gdb) dump-fn cfun->decl | |
692 | (gdb) dump-fn /f foo.1.txt cfun->decl | |
693 | (gdb) dump-fn cfun->decl 0 | |
694 | (gdb) dump-fn cfun->decl dump_flags | |
695 | """ | |
696 | ||
697 | def __init__(self): | |
698 | gdb.Command.__init__(self, 'dump-fn', gdb.COMMAND_USER) | |
699 | ||
700 | def invoke(self, arg, from_tty): | |
701 | # Parse args, check number of args | |
702 | args = gdb.string_to_argv(arg) | |
703 | if len(args) >= 1 and args[0] == "/f": | |
704 | if len(args) == 1: | |
705 | print ("Missing file argument") | |
706 | return | |
707 | filename = args[1] | |
708 | editor_mode = False | |
709 | base_arg = 2 | |
710 | else: | |
711 | editor = os.getenv("EDITOR", "") | |
712 | if editor == "": | |
713 | print ("EDITOR environment variable not defined") | |
714 | return | |
715 | editor_mode = True | |
716 | base_arg = 0 | |
717 | if len(args) - base_arg > 2: | |
718 | print ("Too many arguments") | |
719 | return | |
720 | ||
721 | # Set func | |
722 | if len(args) - base_arg >= 1: | |
723 | funcname = args[base_arg] | |
724 | printfuncname = "function %s" % funcname | |
725 | else: | |
726 | funcname = "cfun ? cfun->decl : current_function_decl" | |
727 | printfuncname = "current function" | |
728 | func = gdb.parse_and_eval(funcname) | |
729 | if func == 0: | |
730 | print ("Could not find %s" % printfuncname) | |
731 | return | |
732 | func = "(tree)%u" % func | |
733 | ||
734 | # Set flags | |
735 | if len(args) - base_arg >= 2: | |
736 | flags = gdb.parse_and_eval(args[base_arg + 1]) | |
737 | else: | |
738 | flags = 0 | |
739 | ||
740 | # Get tempory file, if necessary | |
741 | if editor_mode: | |
742 | f = tempfile.NamedTemporaryFile(delete=False, suffix=".txt") | |
743 | filename = f.name | |
744 | f.close() | |
745 | ||
746 | # Open file | |
cbfde6ee | 747 | fp = gdb.parse_and_eval("(FILE *) fopen (\"%s\", \"w\")" % filename) |
b6e5b400 TV |
748 | if fp == 0: |
749 | print ("Could not open file: %s" % filename) | |
750 | return | |
b6e5b400 TV |
751 | |
752 | # Dump function to file | |
753 | _ = gdb.parse_and_eval("dump_function_to_file (%s, %s, %u)" % | |
754 | (func, fp, flags)) | |
755 | ||
756 | # Close file | |
cbfde6ee | 757 | ret = gdb.parse_and_eval("(int) fclose (%s)" % fp) |
b6e5b400 TV |
758 | if ret != 0: |
759 | print ("Could not close file: %s" % filename) | |
760 | return | |
761 | ||
762 | # Open file in editor, if necessary | |
763 | if editor_mode: | |
764 | os.system("( %s \"%s\"; rm \"%s\" ) &" % | |
765 | (editor, filename, filename)) | |
766 | ||
767 | DumpFn() | |
768 | ||
bddb7adb RB |
769 | class DotFn(gdb.Command): |
770 | """ | |
771 | A custom command to show a gimple/rtl function control flow graph. | |
772 | By default, it show the current function, but the function can also be | |
773 | specified. | |
774 | ||
775 | Examples of use: | |
776 | (gdb) dot-fn | |
777 | (gdb) dot-fn cfun | |
778 | (gdb) dot-fn cfun 0 | |
779 | (gdb) dot-fn cfun dump_flags | |
780 | """ | |
781 | def __init__(self): | |
782 | gdb.Command.__init__(self, 'dot-fn', gdb.COMMAND_USER) | |
783 | ||
784 | def invoke(self, arg, from_tty): | |
785 | # Parse args, check number of args | |
786 | args = gdb.string_to_argv(arg) | |
787 | if len(args) > 2: | |
788 | print("Too many arguments") | |
789 | return | |
790 | ||
791 | # Set func | |
792 | if len(args) >= 1: | |
793 | funcname = args[0] | |
794 | printfuncname = "function %s" % funcname | |
795 | else: | |
796 | funcname = "cfun" | |
797 | printfuncname = "current function" | |
798 | func = gdb.parse_and_eval(funcname) | |
799 | if func == 0: | |
800 | print("Could not find %s" % printfuncname) | |
801 | return | |
802 | func = "(struct function *)%s" % func | |
803 | ||
804 | # Set flags | |
805 | if len(args) >= 2: | |
806 | flags = gdb.parse_and_eval(args[1]) | |
807 | else: | |
808 | flags = 0 | |
809 | ||
810 | # Get temp file | |
811 | f = tempfile.NamedTemporaryFile(delete=False) | |
812 | filename = f.name | |
813 | ||
814 | # Close and reopen temp file to get C FILE* | |
815 | f.close() | |
cbfde6ee | 816 | fp = gdb.parse_and_eval("(FILE *) fopen (\"%s\", \"w\")" % filename) |
bddb7adb RB |
817 | if fp == 0: |
818 | print("Cannot open temp file") | |
819 | return | |
bddb7adb RB |
820 | |
821 | # Write graph to temp file | |
822 | _ = gdb.parse_and_eval("start_graph_dump (%s, \"<debug>\")" % fp) | |
823 | _ = gdb.parse_and_eval("print_graph_cfg (%s, %s, %u)" | |
824 | % (fp, func, flags)) | |
825 | _ = gdb.parse_and_eval("end_graph_dump (%s)" % fp) | |
826 | ||
827 | # Close temp file | |
cbfde6ee | 828 | ret = gdb.parse_and_eval("(int) fclose (%s)" % fp) |
bddb7adb RB |
829 | if ret != 0: |
830 | print("Could not close temp file: %s" % filename) | |
831 | return | |
832 | ||
833 | # Show graph in temp file | |
834 | os.system("( dot -Tx11 \"%s\"; rm \"%s\" ) &" % (filename, filename)) | |
835 | ||
836 | DotFn() | |
837 | ||
8dce4dbc | 838 | print('Successfully loaded GDB hooks for GCC') |