Handle the static link in FrameDecorator
[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 def frame_locals(self):
217 """Return an iterable of local variables for this frame, if
218 any. The iterable object contains objects conforming with the
219 Symbol/Value interface. If there are no frame locals, or if
220 this frame is deemed to be a special case, return None."""
221
222 if hasattr(self._base, "frame_locals"):
223 return self._base.frame_locals()
224
225 frame = self.inferior_frame()
226 args = FrameVars(frame)
227 return args.fetch_frame_locals(True)
228
229
230 class SymValueWrapper(object):
231 """A container class conforming to the Symbol/Value interface
232 which holds frame locals or frame arguments."""
233
234 # The FRAME argument is needed here because gdb.Symbol doesn't
235 # carry the block with it, and so read_var can't find symbols from
236 # outer (static link) frames.
237 def __init__(self, frame, symbol):
238 self.frame = frame
239 self.sym = symbol
240
241 def value(self):
242 """Return the value associated with this symbol, or None"""
243 if self.frame is None:
244 return None
245 return self.frame.read_var(self.sym)
246
247 def symbol(self):
248 """Return the symbol, or Python text, associated with this
249 symbol, or None"""
250 return self.sym
251
252
253 class FrameVars(object):
254
255 """Utility class to fetch and store frame local variables, or
256 frame arguments."""
257
258 def __init__(self, frame):
259 self.frame = frame
260
261 def fetch_frame_locals(self, follow_link=False):
262 """Public utility method to fetch frame local variables for
263 the stored frame. Frame arguments are not fetched. If there
264 are no frame local variables, return an empty list."""
265 lvars = []
266
267 frame = self.frame
268 try:
269 block = frame.block()
270 except RuntimeError:
271 block = None
272
273 traversed_link = False
274 while block is not None:
275 if block.is_global or block.is_static:
276 break
277 for sym in block:
278 # Exclude arguments from the innermost function, but
279 # if we found and traversed a static link, just treat
280 # all such variables as "local".
281 if sym.is_argument:
282 if not traversed_link:
283 continue
284 elif not sym.is_variable:
285 # We use an 'elif' here because is_variable
286 # returns False for arguments as well. Anyway,
287 # don't include non-variables here.
288 continue
289 lvars.append(SymValueWrapper(frame, sym))
290
291 if block.function is not None:
292 if not follow_link:
293 break
294 # If the frame has a static link, follow it here.
295 traversed_link = True
296 frame = frame.static_link()
297 if frame is None:
298 break
299 try:
300 block = frame.block()
301 except RuntimeError:
302 block = None
303 else:
304 block = block.superblock
305
306 return lvars
307
308 def fetch_frame_args(self):
309 """Public utility method to fetch frame arguments for the
310 stored frame. Frame arguments are the only type fetched. If
311 there are no frame argument variables, return an empty list."""
312
313 args = []
314
315 try:
316 block = self.frame.block()
317 except RuntimeError:
318 block = None
319
320 while block is not None:
321 if block.is_global or block.is_static:
322 break
323 for sym in block:
324 if not sym.is_argument:
325 continue
326 args.append(SymValueWrapper(None, sym))
327
328 # Stop when the function itself is seen, to avoid showing
329 # variables from outer functions in a nested function.
330 # Note that we don't traverse the static link for
331 # arguments, only for locals.
332 if block.function is not None:
333 break
334
335 block = block.superblock
336
337 return args