From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 31659 invoked by alias); 27 Nov 2012 14:10:14 -0000 Mailing-List: contact archer-commits-help@sourceware.org; run by ezmlm Sender: Precedence: bulk List-Post: List-Help: List-Subscribe: Received: (qmail 31429 invoked by uid 9514); 27 Nov 2012 14:10:10 -0000 Date: Tue, 27 Nov 2012 14:10:00 -0000 Message-ID: <20121127141010.31381.qmail@sourceware.org> From: pmuldoon@sourceware.org To: archer-commits@sourceware.org Subject: [SCM] archer-pmuldoon-python-backtrace: Clean up typos. Fix testsuite due to type changes in GDB. Document python code. X-Git-Refname: refs/heads/archer-pmuldoon-python-backtrace X-Git-Reftype: branch X-Git-Oldrev: 6bc97e6b4fd186000825e9e20021e253580dd840 X-Git-Newrev: f4ac160f931caacea57610f08d92f80221e5d893 X-SW-Source: 2012-q4/txt/msg00011.txt.bz2 List-Id: The branch, archer-pmuldoon-python-backtrace has been updated via f4ac160f931caacea57610f08d92f80221e5d893 (commit) from 6bc97e6b4fd186000825e9e20021e253580dd840 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit f4ac160f931caacea57610f08d92f80221e5d893 Author: Phil Muldoon Date: Tue Nov 27 14:09:23 2012 +0000 Clean up typos. Fix testsuite due to type changes in GDB. Document python code. ----------------------------------------------------------------------- Summary of changes: gdb/doc/gdb.texinfo | 51 ++++---- gdb/python/lib/gdb/BaseFrameWrapper.py | 151 ++++++++++++++++++------ gdb/python/py-framefilter.c | 10 +- gdb/testsuite/gdb.python/py-framefilter-mi.exp | 8 +- gdb/testsuite/gdb.python/py-framefilter.py | 3 +- 5 files changed, 149 insertions(+), 74 deletions(-) First 500 lines of diff: diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index d900402..837bf34 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -24050,19 +24050,19 @@ done then type printers would have to make use of the event system in order to avoid holding information that could become stale as the inferior changed. -@node Frame Filters API +@node Frame Filters API @subsubsection Filtering and Wrapping Frames. @cindex Frame Filter/Wrappers API Frame filters are Python objects that manipulate the visibility of a frame or frames when a backtrace (@pxref{Backtrace}) is printed by -@value{GDBN}. +@value{GDBN}. Only commands that print a backtrace, or, in the case of @sc{gdb/mi} commands (@pxref{GDB/MI}), those that return a collection of frames are affected. The -commands that work with frame filters are: +commands that work with frame filters are: -@code{backtrace} (@pxref{backtrace-command,, The backtrace command}), +@code{backtrace} (@pxref{backtrace-command,, The backtrace command}), @code{-stack-list-frames} (@pxref{-stack-list-frames,, The -stack-list-frames command}), @code{-stack-list-variables} (@pxref{-stack-list-variables,, The @@ -24074,7 +24074,7 @@ commands that work with frame filters are: Frame filters work by applying actions to an iterator that is passed to the frame filter. The frame filter works with tools such as Python's @code{itertools} module to modify the iterator, and returns -this modified iterator. A frame filter must not alter the underlying +this modified iterator. A frame filter must not alter the underlying @value{GDBN} frame or frames, or attempt to alter the call stack within @value{GDBN}. Frame filters may only work on the wrapping iterator. This preserves data integrity within @value{GDBN}. @@ -24091,7 +24091,7 @@ implement, defined here: @defun FrameFilter.filter (iterator) @value{GDBN} will call this method on a frame filter when it has -reached the order in the priority list for that filter. +reached the order in the priority list for that filter. For example, if there are four frame filters: @@ -24164,7 +24164,7 @@ priority are executed in unsorted order in that priority slot. This attribute is mandatory. @end defvar -@node Frame Wrapper API +@node Frame Wrapper API @subsubsection Wrapping and Decorating Frames. @cindex Frame Wrapper API @@ -24280,7 +24280,7 @@ class SymValueWrapper (): return self.val def symbol (self): - + return self.sym class SomeFrameWrapper () @@ -24289,7 +24289,7 @@ class SomeFrameWrapper () def frame_args (self): fvars = [] fvars.append (SymValueWrapper (``foo'', 42)) - + return iter (fvars) @end smallexample @@ -24328,7 +24328,7 @@ class SymValueWrapper (): return self.val def symbol (self): - + return self.sym class SomeFrameWrapper () @@ -24337,10 +24337,10 @@ class SomeFrameWrapper () def frame_locals (self): fvars = [] fvars.append (SymValueWrapper (``foo'', 42)) - + return iter (fvars) @end smallexample - + Even if the @code{frame_locals} method returns only a single object, it must be wrapped in an iterator. @@ -24400,7 +24400,7 @@ There are three basic elements that a frame filter must implement: it must correctly implement the documented interface (@pxref{Frame Filters API}), it must register itself with @value{GDBN}, and finally, it must decide if it is to work on the data provided by -@value{GDBN}. In all cases, whether it works on the iterator or not, +@value{GDBN}. In all cases, whether it works on the iterator or not, each frame filter must return an iterator. A bare-bones frame filter follows the pattern: @@ -24470,7 +24470,7 @@ this is a valid operation for frame filters that have the In the next example, the frame filter operates on all frames and utilizes a frame wrapper to perform some work on the -frames. @xref{Frame Wrapper API}, for the further information on the +frames. @xref{Frame Wrapper API}, for the further information on the interface. The following example works on inlined frames. It highlights frames @@ -24488,13 +24488,13 @@ performed when each frame is printed. This is an important consideration, and well worth reflecting upon when designing a frame filter. An issue that frame filters should avoid is unwinding the stack if possible. To search every frame to determine if it is -inlined may be too expensive at the filtering step. The frame filter +inlined may be too expensive at the filtering step. The frame filter cannot know how many frames it has to deal with, and it would have to iterate through them all. This ends up duplicating effort as -@value{GDBN} performs this unwinding when it prints the frames. In +@value{GDBN} performs this unwinding when it prints the frames. In this example it can be deferred to the printing step where it can examine each frame when it is printed. From a performance viewpoint, -this is an important note. A backtrace from large or complex programs +this is an important note. A backtrace from large or complex programs can constitute many thousands of frames. Also, if there are many frame filters unwinding the stack during filtering, it can substantially delay the printing of the backtrace which will result in large memory @@ -24517,7 +24517,7 @@ class InlineFilter (): This frame filter is somewhat similar to the earlier example, except that the @code{filter} method applies a frame wrapper object called -@code{InlinedFrameWrapper} to each element in the iterator. +@code{InlinedFrameWrapper} to each element in the iterator. Below is the frame wrapper: @@ -24529,7 +24529,7 @@ class InlinedFrameWrapper (BaseFrameWrapper): self.fobj = fobj def function (self): - frame = self.inferior_frame() + frame = self.inferior_frame() name = str(frame.name()) function = str(frame.function()) @@ -24585,7 +24585,7 @@ class InlineFrameFilter (): This frame filter is very similar to the other examples. The only difference is this frame filter is wrapping the iterator provided to -it (@code{frame_iter}) with a custom iterator: +it (@code{frame_iter}) with a custom iterator: @code{ElidingInlineIterator}. This again defers actions to when @value{GDBN} prints the backtrace, as the iterator is not traversed until printing. @@ -24618,10 +24618,10 @@ untouched. If it is wrapping an inlined frame, it assumes that the inlined frame was contained within the next oldest frame, @code{eliding_frame}, which it fetches. It then creates and returns a frame wrapper, @code{ElidingFrameWrapper}, which contains both the -elided frame, and the eliding frame. +elided frame, and the eliding frame. @smallexample -ElidingInlineWrapper(BaseFrameWrapper): +class ElidingInlineWrapper(BaseFrameWrapper): def __init__(self, frame, elided_frames): super(ElidingInlineWrapper, self).__init__(frame) @@ -24671,7 +24671,7 @@ Enable a frame filter in the dictionary matching @var{filter-dictionary} and @var{filter-name}. @var{filter-dictionary} may be @code{global}, @code{progspace} or the name of the object file where the frame filter dictionary resides. -@var{filter-name} is the name of the frame filter. +@var{filter-name} is the name of the frame filter. Example: @@ -24728,7 +24728,7 @@ objfile /build/test frame-filters: @end smallexample -@kindex set python frame-filter priority +@kindex set python frame-filter priority @item set python frame-filter priority @var{filter-dictionary} @var{filter-name} @var{priority} Set the @var{priority} of a frame filter in the dictionary matching @var{filter-dictionary}, and the frame filter name matching @@ -30408,6 +30408,7 @@ For a stack with frame levels 0 through 11: @anchor{-stack-list-arguments} @subheading The @code{-stack-list-arguments} Command @findex -stack-list-arguments + @subsubheading Synopsis @smallexample @@ -30498,9 +30499,11 @@ args=[@{name="intarg",value="2"@}, @c @subheading -stack-list-exception-handlers + @anchor{-stack-list-frames} @subheading The @code{-stack-list-frames} Command @findex -stack-list-frames + @subsubheading Synopsis @smallexample diff --git a/gdb/python/lib/gdb/BaseFrameWrapper.py b/gdb/python/lib/gdb/BaseFrameWrapper.py index 0ddeb55..169930f 100644 --- a/gdb/python/lib/gdb/BaseFrameWrapper.py +++ b/gdb/python/lib/gdb/BaseFrameWrapper.py @@ -17,20 +17,43 @@ import gdb from gdb.FrameWrapper import FrameWrapper class BaseFrameWrapper (FrameWrapper): - "Base Frame Wrapper" - - # 'base' here can refer to a gdb.Frame or another frame like - # object conforming to the interface of the FrameWrapper class. - # As we can have frame wrappers wrapping frame wrappers, we should - # defer to that object's method. + """Basic implementation of a Frame Wrapper""" + + """ This base frame wrapper wraps a frame or another frame + wrapper, and provides convenience methods. If this object is + wrapping a frame wrapper, defer to that wrapped object's method if + it has one. This allows for frame wrappers that have sub-classed + BaseFrameWrapper, but also wrap other frame wrappers 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 wrappers, all sub-classed from + BaseFrameWrapper: + + Wrapper1(Wrapper2(BaseFrameWrapper(gdb.Frame))) + + In this case we have two frame wrappers, both of which are + sub-classed from BaseFrameWrapper. If Wrapper1 just overrides the + 'function' method, then all of the other methods are carried out + by the super-class BaseFrameWrapper. But Wrapper2 may have + overriden other methods, so BaseFrameWrapper 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 filter. 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): super(BaseFrameWrapper, self).__init__(base) self.base = base - # Determine if this a library or limited frame - frame = self.inferior_frame() - - def is_limited_frame (self, frame): + @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 @@ -42,116 +65,158 @@ class BaseFrameWrapper (FrameWrapper): 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): - # As this is the base wrapper, "base" can either be a gdb.Frame, - # or a another frame wrapper object (another filter may extend - # this object, but not implement "function". So in this case - # we must instance check what "base" is, as later there is - # some work to be done on solib names. - if isinstance(self.base, gdb.Frame): - name = self.base.name() - else: + """ Return the name of the frame's function, first determining + if it 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 not isinstance(self.base, gdb.Frame): if hasattr(self.base, "function"): - return str(self.base.function()) + return self.base.function() frame = self.inferior_frame() - if frame == gdb.DUMMY_FRAME: + if frame.type() == gdb.DUMMY_FRAME: return "" - elif frame == gdb.SIGTRAMP_FRAME: + elif frame.type() == gdb.SIGTRAMP_FRAME: return "" - sal = frame.find_sal () - pc = frame.pc () + func = frame.function() + sal = frame.find_sal() + pc = frame.pc() - if not name and not sal.symtab: + if func == None: unknown = format (" 0x%08x in" % pc) return unknown - return name + return str(func) def address (self): + """ Return the address of the frame's pc""" + if hasattr(self.base, "address"): return self.base.address() - return self.base.pc() + frame = self.inferior_frame() + return frame.pc() def filename (self): + """ Return the filename associated with this frame, detecting + and returns the appropriate library name is this is a shared + library.""" + if hasattr(self.base, "filename"): return self.base.filename() - sal = self.base.find_sal() + frame = self.inferior_frame() + sal = frame.find_sal() if (not sal.symtab or not sal.symtab.filename): - pc = self.inferior_frame().pc() + pc = frame.pc() return gdb.solib_name (pc) else: return sal.symtab.filename def frame_args (self): + """ Return an iterator of frame arguments for this frame, if + any. The iterator 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() - if self.is_limited_frame (self.base): + frame = self.inferior_frame() + if self.is_limited_frame (frame): return None - args = FrameVars (self.base) + args = FrameVars (frame) return args.fetch_frame_args() def frame_locals (self): + """ Return an iterator of local variables for this frame, if + any. The iterator 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() - if self.is_limited_frame (self.base): + frame = self.inferior_frame() + if self.is_limited_frame (frame): return None - args = FrameVars (self.base) + 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() - if self.is_limited_frame (self.base): + frame = self.inferior_frame() + if self.is_limited_frame (frame): return None - sal = self.base.find_sal() + sal = frame.find_sal() if (sal): return sal.line else: return None def inferior_frame (self): + """ Return the gdb.Frame underpinning this frame wrapper.""" + + # If 'base' is a frame wrapper, 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 BaseSymValueWrapper (): - + """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 (): + """Utility class to fetch and store frame local variables, or + frame arguments.""" + def __init__(self,frame): self.frame = frame - def fetch_b (self, sym): + @staticmethod + def fetch_b (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.""" - # We may have a string as a symbol, in the case of synthetic - # locals/args + # 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 @@ -168,6 +233,9 @@ class FrameVars (): }.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 not frame local variables, return None.""" lvars = [] try: block = self.frame.block() @@ -186,6 +254,10 @@ class FrameVars (): return iter (lvars) def fetch_frame_args (self): + """Public utility method to fetch frame argument for the + stored frame. Frame arguments are the only type fetched. If + there are no frame arguments variables, return None.""" + args = [] try: block = self.frame.block() @@ -203,6 +275,7 @@ class FrameVars (): return iter (args) def get_value (self, sym, block): + """Public utility method to fetch a value from a symbol.""" if len (sym.linkage_name): nsym, is_field_of_this = gdb.lookup_symbol (sym.linkage_name, block) if nsym != None: diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c index a508a4b..d48ed28 100644 --- a/gdb/python/py-framefilter.c +++ b/gdb/python/py-framefilter.c @@ -44,7 +44,7 @@ for clean up. **SYM is a pass-through argument where the symbol will be written. In the case of the API returning a string, this will be set to NULL. **LANGUAGE is also a pass-through argument - denoting the language attributed to the Symbol. In the case of + denoting the language attributed to the Symbol. In the case of **SYM being NULL, this will be set to the current language. Returns 0 on error with the appropriate Python exception set, and 1 on success. */ @@ -342,7 +342,7 @@ get_py_iter_from_func (PyObject *filter, char *func) frame argument structure. If FA is populated, both SYM_NAME and FV are ignored. OPTS contains the value printing options, MI_PRINT_TYPE is an enumerator to the value types that will be hooks/post-receive -- Repository for Project Archer.