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