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