]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/python/lib/gdb/disassembler.py
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / disassembler.py
CommitLineData
213516ef 1# Copyright (C) 2021-2023 Free Software Foundation, Inc.
15e15b2d
AB
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
19import _gdb.disassembler
20
21# Re-export everything from the _gdb.disassembler module, which is
22# defined within GDB's C++ code.
23from _gdb.disassembler import *
24
25# Module global dictionary of gdb.disassembler.Disassembler objects.
26# The keys of this dictionary are bfd architecture names, or the
27# special value None.
28#
29# When a request to disassemble comes in we first lookup the bfd
30# architecture name from the gdbarch, if that name exists in this
31# dictionary then we use that Disassembler object.
32#
33# If there's no architecture specific disassembler then we look for
34# the key None in this dictionary, and if that key exists, we use that
35# disassembler.
36#
37# If none of the above checks found a suitable disassembler, then no
38# disassembly is performed in Python.
39_disassemblers_dict = {}
40
41
42class Disassembler(object):
43 """A base class from which all user implemented disassemblers must
44 inherit."""
45
46 def __init__(self, name):
47 """Constructor. Takes a name, which should be a string, which can be
48 used to identify this disassembler in diagnostic messages."""
49 self.name = name
50
51 def __call__(self, info):
52 """A default implementation of __call__. All sub-classes must
53 override this method. Calling this default implementation will throw
54 a NotImplementedError exception."""
55 raise NotImplementedError("Disassembler.__call__")
56
57
58def register_disassembler(disassembler, architecture=None):
59 """Register a disassembler. DISASSEMBLER is a sub-class of
60 gdb.disassembler.Disassembler. ARCHITECTURE is either None or a
61 string, the name of an architecture known to GDB.
62
63 DISASSEMBLER is registered as a disassembler for ARCHITECTURE, or
64 all architectures when ARCHITECTURE is None.
65
66 Returns the previous disassembler registered with this
67 ARCHITECTURE value.
68 """
69
70 if not isinstance(disassembler, Disassembler) and disassembler is not None:
71 raise TypeError("disassembler should sub-class gdb.disassembler.Disassembler")
72
73 old = None
74 if architecture in _disassemblers_dict:
75 old = _disassemblers_dict[architecture]
76 del _disassemblers_dict[architecture]
77 if disassembler is not None:
78 _disassemblers_dict[architecture] = disassembler
79
80 # Call the private _set_enabled function within the
81 # _gdb.disassembler module. This function sets a global flag
82 # within GDB's C++ code that enables or dissables the Python
83 # disassembler functionality, this improves performance of the
84 # disassembler by avoiding unneeded calls into Python when we know
85 # that no disassemblers are registered.
86 _gdb.disassembler._set_enabled(len(_disassemblers_dict) > 0)
87 return old
88
89
90def _print_insn(info):
91 """This function is called by GDB when it wants to disassemble an
92 instruction. INFO describes the instruction to be
93 disassembled."""
94
95 def lookup_disassembler(arch):
96 try:
97 name = arch.name()
98 if name is None:
99 return None
100 if name in _disassemblers_dict:
101 return _disassemblers_dict[name]
102 if None in _disassemblers_dict:
103 return _disassemblers_dict[None]
104 return None
105 except:
106 # It's pretty unlikely this exception case will ever
107 # trigger, one situation would be if the user somehow
108 # corrupted the _disassemblers_dict variable such that it
109 # was no longer a dictionary.
110 return None
111
112 disassembler = lookup_disassembler(info.architecture)
113 if disassembler is None:
114 return None
115 return disassembler(info)
116
117
118class maint_info_py_disassemblers_cmd(gdb.Command):
119 """
120 List all registered Python disassemblers.
121
122 List the name of all registered Python disassemblers, next to the
123 name of the architecture for which the disassembler is registered.
124
125 The global Python disassembler is listed next to the string
126 'GLOBAL'.
127
128 The disassembler that matches the architecture of the currently
129 selected inferior will be marked, this is an indication of which
130 disassembler will be invoked if any disassembly is performed in
131 the current inferior.
132 """
133
134 def __init__(self):
135 super().__init__("maintenance info python-disassemblers", gdb.COMMAND_USER)
136
137 def invoke(self, args, from_tty):
138 # If no disassemblers are registered, tell the user.
139 if len(_disassemblers_dict) == 0:
140 print("No Python disassemblers registered.")
141 return
142
143 # Figure out the longest architecture name, so we can
144 # correctly format the table of results.
145 longest_arch_name = 0
146 for architecture in _disassemblers_dict:
147 if architecture is not None:
148 name = _disassemblers_dict[architecture].name
149 if len(name) > longest_arch_name:
150 longest_arch_name = len(name)
151
152 # Figure out the name of the current architecture. There
153 # should always be a current inferior, but if, somehow, there
154 # isn't, then leave curr_arch as the empty string, which will
155 # not then match agaisnt any architecture in the dictionary.
156 curr_arch = ""
157 if gdb.selected_inferior() is not None:
158 curr_arch = gdb.selected_inferior().architecture().name()
159
160 # Now print the dictionary of registered disassemblers out to
161 # the user.
162 match_tag = "\t(Matches current architecture)"
163 fmt_len = max(longest_arch_name, len("Architecture"))
164 format_string = "{:" + str(fmt_len) + "s} {:s}"
165 print(format_string.format("Architecture", "Disassember Name"))
166 for architecture in _disassemblers_dict:
167 if architecture is not None:
168 name = _disassemblers_dict[architecture].name
169 if architecture == curr_arch:
170 name += match_tag
171 match_tag = ""
172 print(format_string.format(architecture, name))
173 if None in _disassemblers_dict:
174 name = _disassemblers_dict[None].name + match_tag
175 print(format_string.format("GLOBAL", name))
176
177
178maint_info_py_disassemblers_cmd()