Ben Cheng | 7334f0a | 2014-04-30 14:28:17 -0700 | [diff] [blame] | 1 | # Copyright (C) 2013-2014 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 | # 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 | |
| 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 | |
| 261 | try: |
| 262 | block = self.frame.block() |
| 263 | except RuntimeError: |
| 264 | block = None |
| 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 = [] |
| 285 | |
| 286 | try: |
| 287 | block = self.frame.block() |
| 288 | except RuntimeError: |
| 289 | block = None |
| 290 | |
| 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 |