]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame_incremental - gdb/python/lib/gdb/disassembler.py
RELOC_AGAINST_DISCARDED_SECTION zero size reloc sections
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / disassembler.py
... / ...
CommitLineData
1# Copyright (C) 2021-2025 Free Software Foundation, Inc.
2
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16"""Disassembler related module."""
17
18import _gdb.disassembler
19
20# Re-export everything from the _gdb.disassembler module, which is
21# defined within GDB's C++ code. Note that two indicators are needed
22# here to silence flake8.
23from _gdb.disassembler import * # noqa: F401,F403
24
25import gdb
26
27# Module global dictionary of gdb.disassembler.Disassembler objects.
28# The keys of this dictionary are bfd architecture names, or the
29# special value None.
30#
31# When a request to disassemble comes in we first lookup the bfd
32# architecture name from the gdbarch, if that name exists in this
33# dictionary then we use that Disassembler object.
34#
35# If there's no architecture specific disassembler then we look for
36# the key None in this dictionary, and if that key exists, we use that
37# disassembler.
38#
39# If none of the above checks found a suitable disassembler, then no
40# disassembly is performed in Python.
41_disassemblers_dict = {}
42
43
44class Disassembler(object):
45 """A base class from which all user implemented disassemblers must
46 inherit."""
47
48 def __init__(self, name):
49 """Constructor. Takes a name, which should be a string, which can be
50 used to identify this disassembler in diagnostic messages."""
51 self.name = name
52
53 def __call__(self, info):
54 """A default implementation of __call__. All sub-classes must
55 override this method. Calling this default implementation will throw
56 a NotImplementedError exception."""
57 raise NotImplementedError("Disassembler.__call__")
58
59
60def register_disassembler(disassembler, architecture=None):
61 """Register a disassembler. DISASSEMBLER is a sub-class of
62 gdb.disassembler.Disassembler. ARCHITECTURE is either None or a
63 string, the name of an architecture known to GDB.
64
65 DISASSEMBLER is registered as a disassembler for ARCHITECTURE, or
66 all architectures when ARCHITECTURE is None.
67
68 Returns the previous disassembler registered with this
69 ARCHITECTURE value.
70 """
71
72 if not isinstance(disassembler, Disassembler) and disassembler is not None:
73 raise TypeError("disassembler should sub-class gdb.disassembler.Disassembler")
74
75 old = None
76 if architecture in _disassemblers_dict:
77 old = _disassemblers_dict[architecture]
78 del _disassemblers_dict[architecture]
79 if disassembler is not None:
80 _disassemblers_dict[architecture] = disassembler
81
82 # Call the private _set_enabled function within the
83 # _gdb.disassembler module. This function sets a global flag
84 # within GDB's C++ code that enables or disables the Python
85 # disassembler functionality, this improves performance of the
86 # disassembler by avoiding unneeded calls into Python when we know
87 # that no disassemblers are registered.
88 _gdb.disassembler._set_enabled(len(_disassemblers_dict) > 0)
89 return old
90
91
92def _print_insn(info):
93 """This function is called by GDB when it wants to disassemble an
94 instruction. INFO describes the instruction to be
95 disassembled."""
96
97 def lookup_disassembler(arch):
98 name = arch.name()
99 if name is None:
100 return None
101 if name in _disassemblers_dict:
102 return _disassemblers_dict[name]
103 if None in _disassemblers_dict:
104 return _disassemblers_dict[None]
105 return None
106
107 disassembler = lookup_disassembler(info.architecture)
108 if disassembler is None:
109 return None
110 return disassembler(info)
111
112
113class maint_info_py_disassemblers_cmd(gdb.Command):
114 """
115 List all registered Python disassemblers.
116
117 List the name of all registered Python disassemblers, next to the
118 name of the architecture for which the disassembler is registered.
119
120 The global Python disassembler is listed next to the string
121 'GLOBAL'.
122
123 The disassembler that matches the architecture of the currently
124 selected inferior will be marked, this is an indication of which
125 disassembler will be invoked if any disassembly is performed in
126 the current inferior.
127 """
128
129 def __init__(self):
130 super().__init__("maintenance info python-disassemblers", gdb.COMMAND_USER)
131
132 def invoke(self, args, from_tty):
133 # If no disassemblers are registered, tell the user.
134 if len(_disassemblers_dict) == 0:
135 print("No Python disassemblers registered.")
136 return
137
138 # Figure out the longest architecture name, so we can
139 # correctly format the table of results.
140 longest_arch_name = 0
141 for architecture in _disassemblers_dict:
142 if architecture is not None:
143 name = _disassemblers_dict[architecture].name
144 if len(name) > longest_arch_name:
145 longest_arch_name = len(name)
146
147 # Figure out the name of the current architecture. There
148 # should always be a current inferior, but if, somehow, there
149 # isn't, then leave curr_arch as the empty string, which will
150 # not then match against any architecture in the dictionary.
151 curr_arch = ""
152 if gdb.selected_inferior() is not None:
153 curr_arch = gdb.selected_inferior().architecture().name()
154
155 # Now print the dictionary of registered disassemblers out to
156 # the user.
157 match_tag = "\t(Matches current architecture)"
158 fmt_len = max(longest_arch_name, len("Architecture"))
159 format_string = "{:" + str(fmt_len) + "s} {:s}"
160 print(format_string.format("Architecture", "Disassember Name"))
161 for architecture in _disassemblers_dict:
162 if architecture is not None:
163 name = _disassemblers_dict[architecture].name
164 if architecture == curr_arch:
165 name += match_tag
166 match_tag = ""
167 print(format_string.format(architecture, name))
168 if None in _disassemblers_dict:
169 name = _disassemblers_dict[None].name + match_tag
170 print(format_string.format("GLOBAL", name))
171
172
173maint_info_py_disassemblers_cmd()