39ee2e2547c662602acfffa26d45273a84d01ff8
[binutils-gdb.git] / gdb / python / lib / gdb / FrameDecorator.py
1 # Copyright (C) 2013-2023 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 import gdb
17
18
19 class _FrameDecoratorBase(object):
20 """Base class of frame decorators."""
21
22 # 'base' can refer to a gdb.Frame or another frame decorator. In
23 # the latter case, the child class will have called the super
24 # method and _base will be an object conforming to the Frame Filter
25 # class.
26 def __init__(self, base):
27 self._base = base
28
29 @staticmethod
30 def __is_limited_frame(frame):
31 """Internal utility to determine if the frame is special or
32 limited."""
33 sal = frame.find_sal()
34
35 if (
36 not sal.symtab
37 or not sal.symtab.filename
38 or frame.type() == gdb.DUMMY_FRAME
39 or frame.type() == gdb.SIGTRAMP_FRAME
40 ):
41 return True
42
43 return False
44
45 def elided(self):
46 """Return any elided frames that this class might be
47 wrapping, or None."""
48 if hasattr(self._base, "elided"):
49 return self._base.elided()
50
51 return None
52
53 def function(self):
54 """Return the name of the frame's function or an address of
55 the function of the frame. First determine if this is a
56 special frame. If not, try to determine filename from GDB's
57 frame internal function API. Finally, if a name cannot be
58 determined return the address. If this function returns an
59 address, GDB will attempt to determine the function name from
60 its internal minimal symbols store (for example, for inferiors
61 without debug-info)."""
62
63 # Both gdb.Frame, and FrameDecorator have a method called
64 # "function", so determine which object this is.
65 if not isinstance(self._base, gdb.Frame):
66 if hasattr(self._base, "function"):
67 # If it is not a gdb.Frame, and there is already a
68 # "function" method, use that.
69 return self._base.function()
70
71 frame = self.inferior_frame()
72
73 if frame.type() == gdb.DUMMY_FRAME:
74 return "<function called from gdb>"
75 elif frame.type() == gdb.SIGTRAMP_FRAME:
76 return "<signal handler called>"
77
78 func = frame.name()
79 if not isinstance(func, str):
80 func = "???"
81 return func
82
83 def address(self):
84 """Return the address of the frame's pc"""
85
86 if hasattr(self._base, "address"):
87 return self._base.address()
88
89 frame = self.inferior_frame()
90 return frame.pc()
91
92 def frame_args(self):
93 """Return an iterable of frame arguments for this frame, if
94 any. The iterable object contains objects conforming with the
95 Symbol/Value interface. If there are no frame arguments, or
96 if this frame is deemed to be a special case, return None."""
97
98 if hasattr(self._base, "frame_args"):
99 return self._base.frame_args()
100
101 frame = self.inferior_frame()
102 if self.__is_limited_frame(frame):
103 return None
104
105 args = FrameVars(frame)
106 return args.fetch_frame_args()
107
108 def frame_locals(self):
109 """Return an iterable of local variables for this frame, if
110 any. The iterable object contains objects conforming with the
111 Symbol/Value interface. If there are no frame locals, or if
112 this frame is deemed to be a special case, return None."""
113
114 if hasattr(self._base, "frame_locals"):
115 return self._base.frame_locals()
116
117 frame = self.inferior_frame()
118 if self.__is_limited_frame(frame):
119 return None
120
121 args = FrameVars(frame)
122 return args.fetch_frame_locals()
123
124 def line(self):
125 """Return line number information associated with the frame's
126 pc. If symbol table/line information does not exist, or if
127 this frame is deemed to be a special case, return None"""
128
129 if hasattr(self._base, "line"):
130 return self._base.line()
131
132 frame = self.inferior_frame()
133 if self.__is_limited_frame(frame):
134 return None
135
136 sal = frame.find_sal()
137 if sal:
138 return sal.line
139 else:
140 return None
141
142 def inferior_frame(self):
143 """Return the gdb.Frame underpinning this frame decorator."""
144
145 # If 'base' is a frame decorator, we want to call its inferior
146 # frame method. If '_base' is a gdb.Frame, just return that.
147 if hasattr(self._base, "inferior_frame"):
148 return self._base.inferior_frame()
149 return self._base
150
151
152 class FrameDecorator(_FrameDecoratorBase):
153 """Basic implementation of a Frame Decorator
154
155 This base frame decorator decorates a frame or another frame
156 decorator, and provides convenience methods. If this object is
157 wrapping a frame decorator, defer to that wrapped object's method
158 if it has one. This allows for frame decorators that have
159 sub-classed FrameDecorator object, but also wrap other frame
160 decorators on the same frame to correctly execute.
161
162 E.g
163
164 If the result of frame filters running means we have one gdb.Frame
165 wrapped by multiple frame decorators, all sub-classed from
166 FrameDecorator, the resulting hierarchy will be:
167
168 Decorator1
169 -- (wraps) Decorator2
170 -- (wraps) FrameDecorator
171 -- (wraps) gdb.Frame
172
173 In this case we have two frame decorators, both of which are
174 sub-classed from FrameDecorator. If Decorator1 just overrides the
175 'function' method, then all of the other methods are carried out
176 by the super-class FrameDecorator. But Decorator2 may have
177 overriden other methods, so FrameDecorator will look at the
178 'base' parameter and defer to that class's methods. And so on,
179 down the chain."""
180
181 def filename(self):
182 """Return the filename associated with this frame, detecting
183 and returning the appropriate library name is this is a shared
184 library."""
185
186 if hasattr(self._base, "filename"):
187 return self._base.filename()
188
189 frame = self.inferior_frame()
190 sal = frame.find_sal()
191 if not sal.symtab or not sal.symtab.filename:
192 pc = frame.pc()
193 return gdb.solib_name(pc)
194 else:
195 return sal.symtab.filename
196
197
198 class DAPFrameDecorator(_FrameDecoratorBase):
199 """Like FrameDecorator, but has slightly different results
200 for the "filename" method."""
201
202 def filename(self):
203 """Return the filename associated with this frame, detecting
204 and returning the appropriate library name is this is a shared
205 library."""
206
207 if hasattr(self._base, "filename"):
208 return self._base.filename()
209
210 frame = self.inferior_frame()
211 sal = frame.find_sal()
212 if sal.symtab is not None:
213 return sal.symtab.fullname()
214 return None
215
216
217 class SymValueWrapper(object):
218 """A container class conforming to the Symbol/Value interface
219 which holds frame locals or frame arguments."""
220
221 def __init__(self, symbol, value):
222 self.sym = symbol
223 self.val = value
224
225 def value(self):
226 """Return the value associated with this symbol, or None"""
227 return self.val
228
229 def symbol(self):
230 """Return the symbol, or Python text, associated with this
231 symbol, or None"""
232 return self.sym
233
234
235 class FrameVars(object):
236
237 """Utility class to fetch and store frame local variables, or
238 frame arguments."""
239
240 def __init__(self, frame):
241 self.frame = frame
242
243 def fetch_frame_locals(self):
244 """Public utility method to fetch frame local variables for
245 the stored frame. Frame arguments are not fetched. If there
246 are no frame local variables, return an empty list."""
247 lvars = []
248
249 try:
250 block = self.frame.block()
251 except RuntimeError:
252 block = None
253
254 while block is not None:
255 if block.is_global or block.is_static:
256 break
257 for sym in block:
258 if sym.is_argument:
259 continue
260 if sym.is_variable:
261 lvars.append(SymValueWrapper(sym, None))
262
263 # Stop when the function itself is seen, to avoid showing
264 # variables from outer functions in a nested function.
265 if block.function is not None:
266 break
267
268 block = block.superblock
269
270 return lvars
271
272 def fetch_frame_args(self):
273 """Public utility method to fetch frame arguments for the
274 stored frame. Frame arguments are the only type fetched. If
275 there are no frame argument variables, return an empty list."""
276
277 args = []
278
279 try:
280 block = self.frame.block()
281 except RuntimeError:
282 block = None
283
284 while block is not None:
285 if block.is_global or block.is_static:
286 break
287 for sym in block:
288 if not sym.is_argument:
289 continue
290 args.append(SymValueWrapper(sym, None))
291
292 # Stop when the function itself is seen, to avoid showing
293 # variables from outer functions in a nested function.
294 if block.function is not None:
295 break
296
297 block = block.superblock
298
299 return args