hc
2023-11-06 15ade055295d13f95d49e3d99b09f3bbfb4a43e7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!-- Copyright (C) 1988-2021 Free Software Foundation, Inc.
 
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with the
Invariant Sections being "Free Software" and "Free Software Needs
Free Documentation", with the Front-Cover Texts being "A GNU Manual,"
and with the Back-Cover Texts as in (a) below.
 
(a) The FSF's Back-Cover Text is: "You are free to copy and modify
this GNU Manual.  Buying copies from GNU Press supports the FSF in
developing GNU and promoting software freedom." -->
<!-- Created by GNU Texinfo 5.1, http://www.gnu.org/software/texinfo/ -->
<head>
<title>Debugging with GDB: Writing a Pretty-Printer</title>
 
<meta name="description" content="Debugging with GDB: Writing a Pretty-Printer">
<meta name="keywords" content="Debugging with GDB: Writing a Pretty-Printer">
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="index.html#Top" rel="start" title="Top">
<link href="Concept-Index.html#Concept-Index" rel="index" title="Concept Index">
<link href="index.html#SEC_Contents" rel="contents" title="Table of Contents">
<link href="Python-API.html#Python-API" rel="up" title="Python API">
<link href="Type-Printing-API.html#Type-Printing-API" rel="next" title="Type Printing API">
<link href="Selecting-Pretty_002dPrinters.html#Selecting-Pretty_002dPrinters" rel="previous" title="Selecting Pretty-Printers">
<style type="text/css">
<!--
a.summary-letter {text-decoration: none}
blockquote.smallquotation {font-size: smaller}
div.display {margin-left: 3.2em}
div.example {margin-left: 3.2em}
div.indentedblock {margin-left: 3.2em}
div.lisp {margin-left: 3.2em}
div.smalldisplay {margin-left: 3.2em}
div.smallexample {margin-left: 3.2em}
div.smallindentedblock {margin-left: 3.2em; font-size: smaller}
div.smalllisp {margin-left: 3.2em}
kbd {font-style:oblique}
pre.display {font-family: inherit}
pre.format {font-family: inherit}
pre.menu-comment {font-family: serif}
pre.menu-preformatted {font-family: serif}
pre.smalldisplay {font-family: inherit; font-size: smaller}
pre.smallexample {font-size: smaller}
pre.smallformat {font-family: inherit; font-size: smaller}
pre.smalllisp {font-size: smaller}
span.nocodebreak {white-space:nowrap}
span.nolinebreak {white-space:nowrap}
span.roman {font-family:serif; font-weight:normal}
span.sansserif {font-family:sans-serif; font-weight:normal}
ul.no-bullet {list-style: none}
-->
</style>
 
 
</head>
 
<body lang="en" bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#800080" alink="#FF0000">
<a name="Writing-a-Pretty_002dPrinter"></a>
<div class="header">
<p>
Next: <a href="Type-Printing-API.html#Type-Printing-API" accesskey="n" rel="next">Type Printing API</a>, Previous: <a href="Selecting-Pretty_002dPrinters.html#Selecting-Pretty_002dPrinters" accesskey="p" rel="previous">Selecting Pretty-Printers</a>, Up: <a href="Python-API.html#Python-API" accesskey="u" rel="up">Python API</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html#Concept-Index" title="Index" rel="index">Index</a>]</p>
</div>
<hr>
<a name="Writing-a-Pretty_002dPrinter-1"></a>
<h4 class="subsubsection">23.2.2.7 Writing a Pretty-Printer</h4>
<a name="index-writing-a-pretty_002dprinter"></a>
 
<p>A pretty-printer consists of two parts: a lookup function to detect
if the type is supported, and the printer itself.
</p>
<p>Here is an example showing how a <code>std::string</code> printer might be
written.  See <a href="Pretty-Printing-API.html#Pretty-Printing-API">Pretty Printing API</a>, for details on the API this class
must provide.
</p>
<div class="smallexample">
<pre class="smallexample">class StdStringPrinter(object):
    &quot;Print a std::string&quot;
 
    def __init__(self, val):
        self.val = val
 
    def to_string(self):
        return self.val['_M_dataplus']['_M_p']
 
    def display_hint(self):
        return 'string'
</pre></div>
 
<p>And here is an example showing how a lookup function for the printer
example above might be written.
</p>
<div class="smallexample">
<pre class="smallexample">def str_lookup_function(val):
    lookup_tag = val.type.tag
    if lookup_tag == None:
        return None
    regex = re.compile(&quot;^std::basic_string&lt;char,.*&gt;$&quot;)
    if regex.match(lookup_tag):
        return StdStringPrinter(val)
    return None
</pre></div>
 
<p>The example lookup function extracts the value&rsquo;s type, and attempts to
match it to a type that it can pretty-print.  If it is a type the
printer can pretty-print, it will return a printer object.  If not, it
returns <code>None</code>.
</p>
<p>We recommend that you put your core pretty-printers into a Python
package.  If your pretty-printers are for use with a library, we
further recommend embedding a version number into the package name.
This practice will enable <small>GDB</small> to load multiple versions of
your pretty-printers at the same time, because they will have
different names.
</p>
<p>You should write auto-loaded code (see <a href="Python-Auto_002dloading.html#Python-Auto_002dloading">Python Auto-loading</a>) such that it
can be evaluated multiple times without changing its meaning.  An
ideal auto-load file will consist solely of <code>import</code>s of your
printer modules, followed by a call to a register pretty-printers with
the current objfile.
</p>
<p>Taken as a whole, this approach will scale nicely to multiple
inferiors, each potentially using a different library version.
Embedding a version number in the Python package name will ensure that
<small>GDB</small> is able to load both sets of printers simultaneously.
Then, because the search for pretty-printers is done by objfile, and
because your auto-loaded code took care to register your library&rsquo;s
printers with a specific objfile, <small>GDB</small> will find the correct
printers for the specific version of the library used by each
inferior.
</p>
<p>To continue the <code>std::string</code> example (see <a href="Pretty-Printing-API.html#Pretty-Printing-API">Pretty Printing API</a>),
this code might appear in <code>gdb.libstdcxx.v6</code>:
</p>
<div class="smallexample">
<pre class="smallexample">def register_printers(objfile):
    objfile.pretty_printers.append(str_lookup_function)
</pre></div>
 
<p>And then the corresponding contents of the auto-load file would be:
</p>
<div class="smallexample">
<pre class="smallexample">import gdb.libstdcxx.v6
gdb.libstdcxx.v6.register_printers(gdb.current_objfile())
</pre></div>
 
<p>The previous example illustrates a basic pretty-printer.
There are a few things that can be improved on.
The printer doesn&rsquo;t have a name, making it hard to identify in a
list of installed printers.  The lookup function has a name, but
lookup functions can have arbitrary, even identical, names.
</p>
<p>Second, the printer only handles one type, whereas a library typically has
several types.  One could install a lookup function for each desired type
in the library, but one could also have a single lookup function recognize
several types.  The latter is the conventional way this is handled.
If a pretty-printer can handle multiple data types, then its
<em>subprinters</em> are the printers for the individual data types.
</p>
<p>The <code>gdb.printing</code> module provides a formal way of solving these
problems (see <a href="gdb_002eprinting.html#gdb_002eprinting">gdb.printing</a>).
Here is another example that handles multiple types.
</p>
<p>These are the types we are going to pretty-print:
</p>
<div class="smallexample">
<pre class="smallexample">struct foo { int a, b; };
struct bar { struct foo x, y; };
</pre></div>
 
<p>Here are the printers:
</p>
<div class="smallexample">
<pre class="smallexample">class fooPrinter:
    &quot;&quot;&quot;Print a foo object.&quot;&quot;&quot;
 
    def __init__(self, val):
        self.val = val
 
    def to_string(self):
        return (&quot;a=&lt;&quot; + str(self.val[&quot;a&quot;]) +
                &quot;&gt; b=&lt;&quot; + str(self.val[&quot;b&quot;]) + &quot;&gt;&quot;)
 
class barPrinter:
    &quot;&quot;&quot;Print a bar object.&quot;&quot;&quot;
 
    def __init__(self, val):
        self.val = val
 
    def to_string(self):
        return (&quot;x=&lt;&quot; + str(self.val[&quot;x&quot;]) +
                &quot;&gt; y=&lt;&quot; + str(self.val[&quot;y&quot;]) + &quot;&gt;&quot;)
</pre></div>
 
<p>This example doesn&rsquo;t need a lookup function, that is handled by the
<code>gdb.printing</code> module.  Instead a function is provided to build up
the object that handles the lookup.
</p>
<div class="smallexample">
<pre class="smallexample">import gdb.printing
 
def build_pretty_printer():
    pp = gdb.printing.RegexpCollectionPrettyPrinter(
        &quot;my_library&quot;)
    pp.add_printer('foo', '^foo$', fooPrinter)
    pp.add_printer('bar', '^bar$', barPrinter)
    return pp
</pre></div>
 
<p>And here is the autoload support:
</p>
<div class="smallexample">
<pre class="smallexample">import gdb.printing
import my_library
gdb.printing.register_pretty_printer(
    gdb.current_objfile(),
    my_library.build_pretty_printer())
</pre></div>
 
<p>Finally, when this printer is loaded into <small>GDB</small>, here is the
corresponding output of &lsquo;<samp>info pretty-printer</samp>&rsquo;:
</p>
<div class="smallexample">
<pre class="smallexample">(gdb) info pretty-printer
my_library.so:
  my_library
    foo
    bar
</pre></div>
 
<hr>
<div class="header">
<p>
Next: <a href="Type-Printing-API.html#Type-Printing-API" accesskey="n" rel="next">Type Printing API</a>, Previous: <a href="Selecting-Pretty_002dPrinters.html#Selecting-Pretty_002dPrinters" accesskey="p" rel="previous">Selecting Pretty-Printers</a>, Up: <a href="Python-API.html#Python-API" accesskey="u" rel="up">Python API</a> &nbsp; [<a href="index.html#SEC_Contents" title="Table of contents" rel="contents">Contents</a>][<a href="Concept-Index.html#Concept-Index" title="Index" rel="index">Index</a>]</p>
</div>
 
 
 
</body>
</html>