Index: gdb/python/lib/gdb/FrameDecorator.py |
diff --git a/gdb/python/lib/gdb/FrameDecorator.py b/gdb/python/lib/gdb/FrameDecorator.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4e9cd7af07299e1ce8593a8cc65fa7065da39119 |
--- /dev/null |
+++ b/gdb/python/lib/gdb/FrameDecorator.py |
@@ -0,0 +1,294 @@ |
+# Copyright (C) 2013 Free Software Foundation, Inc. |
+ |
+# This program is free software; you can redistribute it and/or modify |
+# it under the terms of the GNU General Public License as published by |
+# the Free Software Foundation; either version 3 of the License, or |
+# (at your option) any later version. |
+# |
+# This program is distributed in the hope that it will be useful, |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+# GNU General Public License for more details. |
+# |
+# You should have received a copy of the GNU General Public License |
+# along with this program. If not, see <http://www.gnu.org/licenses/>. |
+ |
+import gdb |
+ |
+# This small code snippet deals with problem of strings in Python 2.x |
+# and Python 3.x. Python 2.x has str and unicode classes which are |
+# sub-classes of basestring. In Python 3.x all strings are encoded |
+# and basestring has been removed. |
+try: |
+ basestring |
+except NameError: |
+ basestring = str |
+ |
+class FrameDecorator(object): |
+ """Basic implementation of a Frame Decorator""" |
+ |
+ """ This base frame decorator decorates a frame or another frame |
+ decorator, and provides convenience methods. If this object is |
+ wrapping a frame decorator, defer to that wrapped object's method |
+ if it has one. This allows for frame decorators that have |
+ sub-classed FrameDecorator object, but also wrap other frame |
+ decorators on the same frame to correctly execute. |
+ |
+ E.g |
+ |
+ If the result of frame filters running means we have one gdb.Frame |
+ wrapped by multiple frame decorators, all sub-classed from |
+ FrameDecorator, the resulting hierarchy will be: |
+ |
+ Decorator1 |
+ -- (wraps) Decorator2 |
+ -- (wraps) FrameDecorator |
+ -- (wraps) gdb.Frame |
+ |
+ In this case we have two frame decorators, both of which are |
+ sub-classed from FrameDecorator. If Decorator1 just overrides the |
+ 'function' method, then all of the other methods are carried out |
+ by the super-class FrameDecorator. But Decorator2 may have |
+ overriden other methods, so FrameDecorator will look at the |
+ 'base' parameter and defer to that class's methods. And so on, |
+ down the chain.""" |
+ |
+ # 'base' can refer to a gdb.Frame or another frame decorator. In |
+ # the latter case, the child class will have called the super |
+ # method and _base will be an object conforming to the Frame Filter |
+ # class. |
+ def __init__(self, base): |
+ self._base = base |
+ |
+ @staticmethod |
+ def _is_limited_frame(frame): |
+ """Internal utility to determine if the frame is special or |
+ limited.""" |
+ sal = frame.find_sal() |
+ |
+ if (not sal.symtab or not sal.symtab.filename |
+ or frame.type() == gdb.DUMMY_FRAME |
+ or frame.type() == gdb.SIGTRAMP_FRAME): |
+ |
+ return True |
+ |
+ return False |
+ |
+ def elided(self): |
+ """Return any elided frames that this class might be |
+ wrapping, or None.""" |
+ if hasattr(self._base, "elided"): |
+ return self._base.elided() |
+ |
+ return None |
+ |
+ def function(self): |
+ """ Return the name of the frame's function or an address of |
+ the function of the frame. First determine if this is a |
+ special frame. If not, try to determine filename from GDB's |
+ frame internal function API. Finally, if a name cannot be |
+ determined return the address. If this function returns an |
+ address, GDB will attempt to determine the function name from |
+ its internal minimal symbols store (for example, for inferiors |
+ without debug-info).""" |
+ |
+ # Both gdb.Frame, and FrameDecorator have a method called |
+ # "function", so determine which object this is. |
+ if not isinstance(self._base, gdb.Frame): |
+ if hasattr(self._base, "function"): |
+ # If it is not a gdb.Frame, and there is already a |
+ # "function" method, use that. |
+ return self._base.function() |
+ |
+ frame = self.inferior_frame() |
+ |
+ if frame.type() == gdb.DUMMY_FRAME: |
+ return "<function called from gdb>" |
+ elif frame.type() == gdb.SIGTRAMP_FRAME: |
+ return "<signal handler called>" |
+ |
+ func = frame.function() |
+ |
+ # If we cannot determine the function name, return the |
+ # address. If GDB detects an integer value from this function |
+ # it will attempt to find the function name from minimal |
+ # symbols via its own internal functions. |
+ if func == None: |
+ pc = frame.pc() |
+ return pc |
+ |
+ return str(func) |
+ |
+ def address(self): |
+ """ Return the address of the frame's pc""" |
+ |
+ if hasattr(self._base, "address"): |
+ return self._base.address() |
+ |
+ frame = self.inferior_frame() |
+ return frame.pc() |
+ |
+ def filename(self): |
+ """ Return the filename associated with this frame, detecting |
+ and returning the appropriate library name is this is a shared |
+ library.""" |
+ |
+ if hasattr(self._base, "filename"): |
+ return self._base.filename() |
+ |
+ frame = self.inferior_frame() |
+ sal = frame.find_sal() |
+ if not sal.symtab or not sal.symtab.filename: |
+ pc = frame.pc() |
+ return gdb.solib_name(pc) |
+ else: |
+ return sal.symtab.filename |
+ |
+ def frame_args(self): |
+ """ Return an iterable of frame arguments for this frame, if |
+ any. The iterable object contains objects conforming with the |
+ Symbol/Value interface. If there are no frame arguments, or |
+ if this frame is deemed to be a special case, return None.""" |
+ |
+ if hasattr(self._base, "frame_args"): |
+ return self._base.frame_args() |
+ |
+ frame = self.inferior_frame() |
+ if self._is_limited_frame(frame): |
+ return None |
+ |
+ args = FrameVars(frame) |
+ return args.fetch_frame_args() |
+ |
+ def frame_locals(self): |
+ """ Return an iterable of local variables for this frame, if |
+ any. The iterable object contains objects conforming with the |
+ Symbol/Value interface. If there are no frame locals, or if |
+ this frame is deemed to be a special case, return None.""" |
+ |
+ if hasattr(self._base, "frame_locals"): |
+ return self._base.frame_locals() |
+ |
+ frame = self.inferior_frame() |
+ if self._is_limited_frame(frame): |
+ return None |
+ |
+ args = FrameVars(frame) |
+ return args.fetch_frame_locals() |
+ |
+ def line(self): |
+ """ Return line number information associated with the frame's |
+ pc. If symbol table/line information does not exist, or if |
+ this frame is deemed to be a special case, return None""" |
+ |
+ if hasattr(self._base, "line"): |
+ return self._base.line() |
+ |
+ frame = self.inferior_frame() |
+ if self._is_limited_frame(frame): |
+ return None |
+ |
+ sal = frame.find_sal() |
+ if (sal): |
+ return sal.line |
+ else: |
+ return None |
+ |
+ def inferior_frame(self): |
+ """ Return the gdb.Frame underpinning this frame decorator.""" |
+ |
+ # If 'base' is a frame decorator, we want to call its inferior |
+ # frame method. If '_base' is a gdb.Frame, just return that. |
+ if hasattr(self._base, "inferior_frame"): |
+ return self._base.inferior_frame() |
+ return self._base |
+ |
+class SymValueWrapper(object): |
+ """A container class conforming to the Symbol/Value interface |
+ which holds frame locals or frame arguments.""" |
+ def __init__(self, symbol, value): |
+ self.sym = symbol |
+ self.val = value |
+ |
+ def value(self): |
+ """ Return the value associated with this symbol, or None""" |
+ return self.val |
+ |
+ def symbol(self): |
+ """ Return the symbol, or Python text, associated with this |
+ symbol, or None""" |
+ return self.sym |
+ |
+class FrameVars(object): |
+ |
+ """Utility class to fetch and store frame local variables, or |
+ frame arguments.""" |
+ |
+ def __init__(self, frame): |
+ self.frame = frame |
+ self.symbol_class = { |
+ gdb.SYMBOL_LOC_STATIC: True, |
+ gdb.SYMBOL_LOC_REGISTER: True, |
+ gdb.SYMBOL_LOC_ARG: True, |
+ gdb.SYMBOL_LOC_REF_ARG: True, |
+ gdb.SYMBOL_LOC_LOCAL: True, |
+ gdb.SYMBOL_LOC_REGPARM_ADDR: True, |
+ gdb.SYMBOL_LOC_COMPUTED: True |
+ } |
+ |
+ def fetch_b(self, sym): |
+ """ Local utility method to determine if according to Symbol |
+ type whether it should be included in the iterator. Not all |
+ symbols are fetched, and only symbols that return |
+ True from this method should be fetched.""" |
+ |
+ # SYM may be a string instead of a symbol in the case of |
+ # synthetic local arguments or locals. If that is the case, |
+ # always fetch. |
+ if isinstance(sym, basestring): |
+ return True |
+ |
+ sym_type = sym.addr_class |
+ |
+ return self.symbol_class.get(sym_type, False) |
+ |
+ def fetch_frame_locals(self): |
+ """Public utility method to fetch frame local variables for |
+ the stored frame. Frame arguments are not fetched. If there |
+ are no frame local variables, return an empty list.""" |
+ lvars = [] |
+ |
+ block = self.frame.block() |
+ |
+ while block != None: |
+ if block.is_global or block.is_static: |
+ break |
+ for sym in block: |
+ if sym.is_argument: |
+ continue; |
+ if self.fetch_b(sym): |
+ lvars.append(SymValueWrapper(sym, None)) |
+ |
+ block = block.superblock |
+ |
+ return lvars |
+ |
+ def fetch_frame_args(self): |
+ """Public utility method to fetch frame arguments for the |
+ stored frame. Frame arguments are the only type fetched. If |
+ there are no frame argument variables, return an empty list.""" |
+ |
+ args = [] |
+ block = self.frame.block() |
+ while block != None: |
+ if block.function != None: |
+ break |
+ block = block.superblock |
+ |
+ if block != None: |
+ for sym in block: |
+ if not sym.is_argument: |
+ continue; |
+ args.append(SymValueWrapper(sym, None)) |
+ |
+ return args |