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