1<html lang="en"> 2<head> 3<title>Writing a Frame Filter - Debugging with GDB</title> 4<meta http-equiv="Content-Type" content="text/html"> 5<meta name="description" content="Debugging with GDB"> 6<meta name="generator" content="makeinfo 4.13"> 7<link title="Top" rel="start" href="index.html#Top"> 8<link rel="up" href="Python-API.html#Python-API" title="Python API"> 9<link rel="prev" href="Frame-Decorator-API.html#Frame-Decorator-API" title="Frame Decorator API"> 10<link rel="next" href="Inferiors-In-Python.html#Inferiors-In-Python" title="Inferiors In Python"> 11<link href="http://www.gnu.org/software/texinfo/" rel="generator-home" title="Texinfo Homepage"> 12<!-- 13Copyright (C) 1988-2013 Free Software Foundation, Inc. 14 15Permission is granted to copy, distribute and/or modify this document 16under the terms of the GNU Free Documentation License, Version 1.3 or 17any later version published by the Free Software Foundation; with the 18Invariant Sections being ``Free Software'' and ``Free Software Needs 19Free Documentation'', with the Front-Cover Texts being ``A GNU Manual,'' 20and with the Back-Cover Texts as in (a) below. 21 22(a) The FSF's Back-Cover Text is: ``You are free to copy and modify 23this GNU Manual. Buying copies from GNU Press supports the FSF in 24developing GNU and promoting software freedom.'' 25--> 26<meta http-equiv="Content-Style-Type" content="text/css"> 27<style type="text/css"><!-- 28 pre.display { font-family:inherit } 29 pre.format { font-family:inherit } 30 pre.smalldisplay { font-family:inherit; font-size:smaller } 31 pre.smallformat { font-family:inherit; font-size:smaller } 32 pre.smallexample { font-size:smaller } 33 pre.smalllisp { font-size:smaller } 34 span.sc { font-variant:small-caps } 35 span.roman { font-family:serif; font-weight:normal; } 36 span.sansserif { font-family:sans-serif; font-weight:normal; } 37--></style> 38<link rel="stylesheet" type="text/css" href="../cs.css"> 39</head> 40<body> 41<div class="node"> 42<a name="Writing-a-Frame-Filter"></a> 43<p> 44Next: <a rel="next" accesskey="n" href="Inferiors-In-Python.html#Inferiors-In-Python">Inferiors In Python</a>, 45Previous: <a rel="previous" accesskey="p" href="Frame-Decorator-API.html#Frame-Decorator-API">Frame Decorator API</a>, 46Up: <a rel="up" accesskey="u" href="Python-API.html#Python-API">Python API</a> 47<hr> 48</div> 49 50<h5 class="subsubsection">23.2.2.11 Writing a Frame Filter</h5> 51 52<p><a name="index-writing-a-frame-filter-1897"></a> 53There are three basic elements that a frame filter must implement: it 54must correctly implement the documented interface (see <a href="Frame-Filter-API.html#Frame-Filter-API">Frame Filter API</a>), it must register itself with <span class="sc">gdb</span>, and finally, it must 55decide if it is to work on the data provided by <span class="sc">gdb</span>. In all 56cases, whether it works on the iterator or not, each frame filter must 57return an iterator. A bare-bones frame filter follows the pattern in 58the following example. 59 60<pre class="smallexample"> import gdb 61 62 class FrameFilter(): 63 64 def __init__(self): 65 # Frame filter attribute creation. 66 # 67 # 'name' is the name of the filter that GDB will display. 68 # 69 # 'priority' is the priority of the filter relative to other 70 # filters. 71 # 72 # 'enabled' is a boolean that indicates whether this filter is 73 # enabled and should be executed. 74 75 self.name = "Foo" 76 self.priority = 100 77 self.enabled = True 78 79 # Register this frame filter with the global frame_filters 80 # dictionary. 81 gdb.frame_filters[self.name] = self 82 83 def filter(self, frame_iter): 84 # Just return the iterator. 85 return frame_iter 86</pre> 87 <p>The frame filter in the example above implements the three 88requirements for all frame filters. It implements the API, self 89registers, and makes a decision on the iterator (in this case, it just 90returns the iterator untouched). 91 92 <p>The first step is attribute creation and assignment, and as shown in 93the comments the filter assigns the following attributes: <code>name</code>, 94<code>priority</code> and whether the filter should be enabled with the 95<code>enabled</code> attribute. 96 97 <p>The second step is registering the frame filter with the dictionary or 98dictionaries that the frame filter has interest in. As shown in the 99comments, this filter just registers itself with the global dictionary 100<code>gdb.frame_filters</code>. As noted earlier, <code>gdb.frame_filters</code> 101is a dictionary that is initialized in the <code>gdb</code> module when 102<span class="sc">gdb</span> starts. What dictionary a filter registers with is an 103important consideration. Generally, if a filter is specific to a set 104of code, it should be registered either in the <code>objfile</code> or 105<code>progspace</code> dictionaries as they are specific to the program 106currently loaded in <span class="sc">gdb</span>. The global dictionary is always 107present in <span class="sc">gdb</span> and is never unloaded. Any filters registered 108with the global dictionary will exist until <span class="sc">gdb</span> exits. To 109avoid filters that may conflict, it is generally better to register 110frame filters against the dictionaries that more closely align with 111the usage of the filter currently in question. See <a href="Python-Auto_002dloading.html#Python-Auto_002dloading">Python Auto-loading</a>, for further information on auto-loading Python scripts. 112 113 <p><span class="sc">gdb</span> takes a hands-off approach to frame filter registration, 114therefore it is the frame filter's responsibility to ensure 115registration has occurred, and that any exceptions are handled 116appropriately. In particular, you may wish to handle exceptions 117relating to Python dictionary key uniqueness. It is mandatory that 118the dictionary key is the same as frame filter's <code>name</code> 119attribute. When a user manages frame filters (see <a href="Frame-Filter-Management.html#Frame-Filter-Management">Frame Filter Management</a>), the names <span class="sc">gdb</span> will display are those contained 120in the <code>name</code> attribute. 121 122 <p>The final step of this example is the implementation of the 123<code>filter</code> method. As shown in the example comments, we define the 124<code>filter</code> method and note that the method must take an iterator, 125and also must return an iterator. In this bare-bones example, the 126frame filter is not very useful as it just returns the iterator 127untouched. However this is a valid operation for frame filters that 128have the <code>enabled</code> attribute set, but decide not to operate on 129any frames. 130 131 <p>In the next example, the frame filter operates on all frames and 132utilizes a frame decorator to perform some work on the frames. 133See <a href="Frame-Decorator-API.html#Frame-Decorator-API">Frame Decorator API</a>, for further information on the frame 134decorator interface. 135 136 <p>This example works on inlined frames. It highlights frames which are 137inlined by tagging them with an “[inlined]” tag. By applying a 138frame decorator to all frames with the Python <code>itertools imap</code> 139method, the example defers actions to the frame decorator. Frame 140decorators are only processed when <span class="sc">gdb</span> prints the backtrace. 141 142 <p>This introduces a new decision making topic: whether to perform 143decision making operations at the filtering step, or at the printing 144step. In this example's approach, it does not perform any filtering 145decisions at the filtering step beyond mapping a frame decorator to 146each frame. This allows the actual decision making to be performed 147when each frame is printed. This is an important consideration, and 148well worth reflecting upon when designing a frame filter. An issue 149that frame filters should avoid is unwinding the stack if possible. 150Some stacks can run very deep, into the tens of thousands in some 151cases. To search every frame to determine if it is inlined ahead of 152time may be too expensive at the filtering step. The frame filter 153cannot know how many frames it has to iterate over, and it would have 154to iterate through them all. This ends up duplicating effort as 155<span class="sc">gdb</span> performs this iteration when it prints the frames. 156 157 <p>In this example decision making can be deferred to the printing step. 158As each frame is printed, the frame decorator can examine each frame 159in turn when <span class="sc">gdb</span> iterates. From a performance viewpoint, 160this is the most appropriate decision to make as it avoids duplicating 161the effort that the printing step would undertake anyway. Also, if 162there are many frame filters unwinding the stack during filtering, it 163can substantially delay the printing of the backtrace which will 164result in large memory usage, and a poor user experience. 165 166<pre class="smallexample"> class InlineFilter(): 167 168 def __init__(self): 169 self.name = "InlinedFrameFilter" 170 self.priority = 100 171 self.enabled = True 172 gdb.frame_filters[self.name] = self 173 174 def filter(self, frame_iter): 175 frame_iter = itertools.imap(InlinedFrameDecorator, 176 frame_iter) 177 return frame_iter 178</pre> 179 <p>This frame filter is somewhat similar to the earlier example, except 180that the <code>filter</code> method applies a frame decorator object called 181<code>InlinedFrameDecorator</code> to each element in the iterator. The 182<code>imap</code> Python method is light-weight. It does not proactively 183iterate over the iterator, but rather creates a new iterator which 184wraps the existing one. 185 186 <p>Below is the frame decorator for this example. 187 188<pre class="smallexample"> class InlinedFrameDecorator(FrameDecorator): 189 190 def __init__(self, fobj): 191 super(InlinedFrameDecorator, self).__init__(fobj) 192 193 def function(self): 194 frame = fobj.inferior_frame() 195 name = str(frame.name()) 196 197 if frame.type() == gdb.INLINE_FRAME: 198 name = name + " [inlined]" 199 200 return name 201</pre> 202 <p>This frame decorator only defines and overrides the <code>function</code> 203method. It lets the supplied <code>FrameDecorator</code>, which is shipped 204with <span class="sc">gdb</span>, perform the other work associated with printing 205this frame. 206 207 <p>The combination of these two objects create this output from a 208backtrace: 209 210<pre class="smallexample"> #0 0x004004e0 in bar () at inline.c:11 211 #1 0x00400566 in max [inlined] (b=6, a=12) at inline.c:21 212 #2 0x00400566 in main () at inline.c:31 213</pre> 214 <p>So in the case of this example, a frame decorator is applied to all 215frames, regardless of whether they may be inlined or not. As 216<span class="sc">gdb</span> iterates over the iterator produced by the frame filters, 217<span class="sc">gdb</span> executes each frame decorator which then makes a decision 218on what to print in the <code>function</code> callback. Using a strategy 219like this is a way to defer decisions on the frame content to printing 220time. 221 222<h4 class="subheading">Eliding Frames</h4> 223 224<p>It might be that the above example is not desirable for representing 225inlined frames, and a hierarchical approach may be preferred. If we 226want to hierarchically represent frames, the <code>elided</code> frame 227decorator interface might be preferable. 228 229 <p>This example approaches the issue with the <code>elided</code> method. This 230example is quite long, but very simplistic. It is out-of-scope for 231this section to write a complete example that comprehensively covers 232all approaches of finding and printing inlined frames. However, this 233example illustrates the approach an author might use. 234 235 <p>This example comprises of three sections. 236 237<pre class="smallexample"> class InlineFrameFilter(): 238 239 def __init__(self): 240 self.name = "InlinedFrameFilter" 241 self.priority = 100 242 self.enabled = True 243 gdb.frame_filters[self.name] = self 244 245 def filter(self, frame_iter): 246 return ElidingInlineIterator(frame_iter) 247</pre> 248 <p>This frame filter is very similar to the other examples. The only 249difference is this frame filter is wrapping the iterator provided to 250it (<code>frame_iter</code>) with a custom iterator called 251<code>ElidingInlineIterator</code>. This again defers actions to when 252<span class="sc">gdb</span> prints the backtrace, as the iterator is not traversed 253until printing. 254 255 <p>The iterator for this example is as follows. It is in this section of 256the example where decisions are made on the content of the backtrace. 257 258<pre class="smallexample"> class ElidingInlineIterator: 259 def __init__(self, ii): 260 self.input_iterator = ii 261 262 def __iter__(self): 263 return self 264 265 def next(self): 266 frame = next(self.input_iterator) 267 268 if frame.inferior_frame().type() != gdb.INLINE_FRAME: 269 return frame 270 271 try: 272 eliding_frame = next(self.input_iterator) 273 except StopIteration: 274 return frame 275 return ElidingFrameDecorator(eliding_frame, [frame]) 276</pre> 277 <p>This iterator implements the Python iterator protocol. When the 278<code>next</code> function is called (when <span class="sc">gdb</span> prints each frame), 279the iterator checks if this frame decorator, <code>frame</code>, is wrapping 280an inlined frame. If it is not, it returns the existing frame decorator 281untouched. If it is wrapping an inlined frame, it assumes that the 282inlined frame was contained within the next oldest frame, 283<code>eliding_frame</code>, which it fetches. It then creates and returns a 284frame decorator, <code>ElidingFrameDecorator</code>, which contains both the 285elided frame, and the eliding frame. 286 287<pre class="smallexample"> class ElidingInlineDecorator(FrameDecorator): 288 289 def __init__(self, frame, elided_frames): 290 super(ElidingInlineDecorator, self).__init__(frame) 291 self.frame = frame 292 self.elided_frames = elided_frames 293 294 def elided(self): 295 return iter(self.elided_frames) 296</pre> 297 <p>This frame decorator overrides one function and returns the inlined 298frame in the <code>elided</code> method. As before it lets 299<code>FrameDecorator</code> do the rest of the work involved in printing 300this frame. This produces the following output. 301 302<pre class="smallexample"> #0 0x004004e0 in bar () at inline.c:11 303 #2 0x00400529 in main () at inline.c:25 304 #1 0x00400529 in max (b=6, a=12) at inline.c:15 305</pre> 306 <p>In that output, <code>max</code> which has been inlined into <code>main</code> is 307printed hierarchically. Another approach would be to combine the 308<code>function</code> method, and the <code>elided</code> method to both print a 309marker in the inlined frame, and also show the hierarchical 310relationship. 311 312 </body></html> 313 314