1
2 /*--------------------------------------------------------------------*/
3 /*--- Demangling of C++ mangled names. demangle.c ---*/
4 /*--------------------------------------------------------------------*/
5
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2000-2010 Julian Seward
11 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29 */
30
31 #include "pub_core_basics.h"
32 #include "pub_core_demangle.h"
33 #include "pub_core_libcassert.h"
34 #include "pub_core_libcbase.h"
35 #include "pub_core_libcprint.h"
36 #include "pub_core_mallocfree.h"
37 #include "pub_core_options.h"
38
39 #include "vg_libciface.h"
40 #include "demangle.h"
41
42 /* The demangler's job is to take a raw symbol name and turn it into
43 something a Human Bean can understand. There are two levels of
44 mangling.
45
46 1. First, C++ names are mangled by the compiler. So we'll have to
47 undo that.
48
49 2. Optionally, in relatively rare cases, the resulting name is then
50 itself encoded using Z-escaping (see pub_core_redir.h) so as to
51 become part of a redirect-specification.
52
53 Therefore, VG_(demangle) first tries to undo (2). If successful,
54 the soname part is discarded (humans don't want to see that).
55 Then, it tries to undo (1) (using demangling code from GNU/FSF).
56
57 Finally, change the name of all symbols which are known to be
58 functions below main() to "(below main)". This helps reduce
59 variability of stack traces, something which has been a problem for
60 the testsuite for a long time.
61
62 --------
63 If do_cxx_demangle == True, does all the above stages:
64 - undo (2) [Z-encoding]
65 - undo (1) [C++ mangling]
66 - do the below-main hack
67
68 If do_cxx_demangle == False, the middle stage is skipped:
69 - undo (2) [Z-encoding]
70 - do the below-main hack
71 */
72
73 /* Note that the C++ demangler is from GNU libiberty and is almost
74 completely unmodified. We use vg_libciface.h as a way to
75 impedance-match the libiberty code into our own framework.
76
77 The current code is from libiberty in the gcc tree, gcc svn
78 r141363, dated 26 Oct 2008 (when the gcc trunk was in Stage 3
79 leading up to a gcc-4.4 release). As of r141363, libiberty is LGPL
80 2.1, which AFAICT is compatible with "GPL 2 or later" and so is OK
81 for inclusion in Valgrind.
82
83 To update to a newer libiberty, it might be simplest to svn diff
84 the gcc tree libibery against r141363 and then apply those diffs
85 here. */
86
87 /* This is the main, standard demangler entry point. */
88
VG_(demangle)89 void VG_(demangle) ( Bool do_cxx_demangling, Bool do_z_demangling,
90 Char* orig, Char* result, Int result_size )
91 {
92 # define N_ZBUF 4096
93 HChar* demangled = NULL;
94 HChar z_demangled[N_ZBUF];
95
96 /* Possibly undo (2) */
97 /* Z-Demangling was requested.
98 The fastest way to see if it's a Z-mangled name is just to attempt
99 to Z-demangle it (with NULL for the soname buffer, since we're not
100 interested in that). */
101 if (do_z_demangling) {
102 if (VG_(maybe_Z_demangle)( orig, NULL,0,/*soname*/
103 z_demangled, N_ZBUF, NULL)) {
104 orig = z_demangled;
105 }
106 }
107
108 /* Possibly undo (1) */
109 if (do_cxx_demangling && VG_(clo_demangle)) {
110 demangled = ML_(cplus_demangle) ( orig, DMGL_ANSI | DMGL_PARAMS );
111 } else {
112 demangled = NULL;
113 }
114 if (demangled) {
115 VG_(strncpy_safely)(result, demangled, result_size);
116 VG_(arena_free) (VG_AR_DEMANGLE, demangled);
117 } else {
118 VG_(strncpy_safely)(result, orig, result_size);
119 }
120
121 // 13 Mar 2005: We used to check here that the demangler wasn't leaking
122 // by calling the (now-removed) function VG_(is_empty_arena)(). But,
123 // very rarely (ie. I've heard of it twice in 3 years), the demangler
124 // does leak. But, we can't do much about it, and it's not a disaster,
125 // so we just let it slide without aborting or telling the user.
126 # undef N_ZBUF
127 }
128
129
130 /*------------------------------------------------------------*/
131 /*--- DEMANGLE Z-ENCODED NAMES ---*/
132 /*------------------------------------------------------------*/
133
134 /* Demangle a Z-encoded name as described in pub_tool_redir.h.
135 Z-encoded names are used by Valgrind for doing function
136 interception/wrapping.
137
138 Demangle 'sym' into its soname and fnname parts, putting them in
139 the specified buffers. Returns a Bool indicating whether the
140 demangled failed or not. A failure can occur because the prefix
141 isn't recognised, the internal Z-escaping is wrong, or because one
142 or the other (or both) of the output buffers becomes full. Passing
143 'so' as NULL is acceptable if the caller is only interested in the
144 function name part. */
145
VG_(maybe_Z_demangle)146 Bool VG_(maybe_Z_demangle) ( const HChar* sym,
147 /*OUT*/HChar* so, Int soLen,
148 /*OUT*/HChar* fn, Int fnLen,
149 /*OUT*/Bool* isWrap )
150 {
151 # define EMITSO(ch) \
152 do { \
153 if (so) { \
154 if (soi >= soLen) { \
155 so[soLen-1] = 0; oflow = True; \
156 } else { \
157 so[soi++] = ch; so[soi] = 0; \
158 } \
159 } \
160 } while (0)
161 # define EMITFN(ch) \
162 do { \
163 if (fni >= fnLen) { \
164 fn[fnLen-1] = 0; oflow = True; \
165 } else { \
166 fn[fni++] = ch; fn[fni] = 0; \
167 } \
168 } while (0)
169
170 Bool error, oflow, valid, fn_is_encoded, is_VG_Z_prefixed;
171 Int soi, fni, i;
172
173 vg_assert(soLen > 0 || (soLen == 0 && so == NULL));
174 vg_assert(fnLen > 0);
175 error = False;
176 oflow = False;
177 soi = 0;
178 fni = 0;
179
180 valid = sym[0] == '_'
181 && sym[1] == 'v'
182 && sym[2] == 'g'
183 && (sym[3] == 'r' || sym[3] == 'w' || sym[3] == 'n')
184 && sym[4] == 'Z'
185 && (sym[5] == 'Z' || sym[5] == 'U')
186 && sym[6] == '_';
187 if (!valid)
188 return False;
189
190 fn_is_encoded = sym[5] == 'Z';
191
192 if (isWrap)
193 *isWrap = sym[3] == 'w';
194
195 /* Now check the soname prefix isn't "VG_Z_", as described in
196 pub_tool_redir.h. */
197 is_VG_Z_prefixed =
198 sym[ 7] == 'V' &&
199 sym[ 8] == 'G' &&
200 sym[ 9] == '_' &&
201 sym[10] == 'Z' &&
202 sym[11] == '_';
203 if (is_VG_Z_prefixed) {
204 vg_assert2(0, "symbol with a 'VG_Z_' prefix: %s.\n"
205 "see pub_tool_redir.h for an explanation.", sym);
206 }
207
208 /* Now scan the Z-encoded soname. */
209 i = 7;
210 while (True) {
211
212 if (sym[i] == '_')
213 /* Found the delimiter. Move on to the fnname loop. */
214 break;
215
216 if (sym[i] == 0) {
217 error = True;
218 goto out;
219 }
220
221 if (sym[i] != 'Z') {
222 EMITSO(sym[i]);
223 i++;
224 continue;
225 }
226
227 /* We've got a Z-escape. */
228 i++;
229 switch (sym[i]) {
230 case 'a': EMITSO('*'); break;
231 case 'c': EMITSO(':'); break;
232 case 'd': EMITSO('.'); break;
233 case 'h': EMITSO('-'); break;
234 case 'p': EMITSO('+'); break;
235 case 's': EMITSO(' '); break;
236 case 'u': EMITSO('_'); break;
237 case 'A': EMITSO('@'); break;
238 case 'D': EMITSO('$'); break;
239 case 'L': EMITSO('('); break;
240 case 'R': EMITSO(')'); break;
241 case 'Z': EMITSO('Z'); break;
242 default: error = True; goto out;
243 }
244 i++;
245 }
246
247 vg_assert(sym[i] == '_');
248 i++;
249
250 /* Now deal with the function name part. */
251 if (!fn_is_encoded) {
252
253 /* simple; just copy. */
254 while (True) {
255 if (sym[i] == 0)
256 break;
257 EMITFN(sym[i]);
258 i++;
259 }
260 goto out;
261
262 }
263
264 /* else use a Z-decoding loop like with soname */
265 while (True) {
266
267 if (sym[i] == 0)
268 break;
269
270 if (sym[i] != 'Z') {
271 EMITFN(sym[i]);
272 i++;
273 continue;
274 }
275
276 /* We've got a Z-escape. */
277 i++;
278 switch (sym[i]) {
279 case 'a': EMITFN('*'); break;
280 case 'c': EMITFN(':'); break;
281 case 'd': EMITFN('.'); break;
282 case 'h': EMITFN('-'); break;
283 case 'p': EMITFN('+'); break;
284 case 's': EMITFN(' '); break;
285 case 'u': EMITFN('_'); break;
286 case 'A': EMITFN('@'); break;
287 case 'D': EMITFN('$'); break;
288 case 'L': EMITFN('('); break;
289 case 'R': EMITFN(')'); break;
290 case 'Z': EMITFN('Z'); break;
291 default: error = True; goto out;
292 }
293 i++;
294 }
295
296 out:
297 EMITSO(0);
298 EMITFN(0);
299
300 if (error) {
301 /* Something's wrong. Give up. */
302 VG_(message)(Vg_UserMsg,
303 "m_demangle: error Z-demangling: %s\n", sym);
304 return False;
305 }
306 if (oflow) {
307 /* It didn't fit. Give up. */
308 VG_(message)(Vg_UserMsg,
309 "m_demangle: oflow Z-demangling: %s\n", sym);
310 return False;
311 }
312
313 return True;
314 }
315
316
317 /*--------------------------------------------------------------------*/
318 /*--- end ---*/
319 /*--------------------------------------------------------------------*/
320