• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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-2012 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    r181975, dated 12 Dec 2011 (when the gcc trunk was in Stage 3
79    leading up to a gcc-4.7 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 r181975 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, NULL, 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                              /*OUT*/Int*  eclassTag,
151                              /*OUT*/Int*  eclassPrio )
152 {
153 #  define EMITSO(ch)                           \
154       do {                                     \
155          if (so) {                             \
156             if (soi >= soLen) {                \
157                so[soLen-1] = 0; oflow = True;  \
158             } else {                           \
159                so[soi++] = ch; so[soi] = 0;    \
160             }                                  \
161          }                                     \
162       } while (0)
163 #  define EMITFN(ch)                           \
164       do {                                     \
165          if (fni >= fnLen) {                   \
166             fn[fnLen-1] = 0; oflow = True;     \
167          } else {                              \
168             fn[fni++] = ch; fn[fni] = 0;       \
169          }                                     \
170       } while (0)
171 
172    Bool error, oflow, valid, fn_is_encoded, is_VG_Z_prefixed;
173    Int  soi, fni, i;
174 
175    vg_assert(soLen > 0 || (soLen == 0 && so == NULL));
176    vg_assert(fnLen > 0);
177    error = False;
178    oflow = False;
179    soi = 0;
180    fni = 0;
181 
182    valid =     sym[0] == '_'
183            &&  sym[1] == 'v'
184            &&  sym[2] == 'g'
185            && (sym[3] == 'r' || sym[3] == 'w')
186            &&  VG_(isdigit)(sym[4])
187            &&  VG_(isdigit)(sym[5])
188            &&  VG_(isdigit)(sym[6])
189            &&  VG_(isdigit)(sym[7])
190            &&  VG_(isdigit)(sym[8])
191            &&  sym[9] == 'Z'
192            && (sym[10] == 'Z' || sym[10] == 'U')
193            &&  sym[11] == '_';
194 
195    if (valid
196        && sym[4] == '0' && sym[5] == '0' && sym[6] == '0' && sym[7] == '0'
197        && sym[8] != '0') {
198       /* If the eclass tag is 0000 (meaning "no eclass"), the priority
199          must be 0 too. */
200       valid = False;
201    }
202 
203    if (!valid)
204       return False;
205 
206    fn_is_encoded = sym[10] == 'Z';
207 
208    if (isWrap)
209       *isWrap = sym[3] == 'w';
210 
211    if (eclassTag) {
212       *eclassTag =    1000 * ((Int)sym[4] - '0')
213                    +  100 * ((Int)sym[5] - '0')
214                    +  10 * ((Int)sym[6] - '0')
215                    +  1 * ((Int)sym[7] - '0');
216       vg_assert(*eclassTag >= 0 && *eclassTag <= 9999);
217    }
218 
219    if (eclassPrio) {
220       *eclassPrio = ((Int)sym[8]) - '0';
221       vg_assert(*eclassPrio >= 0 && *eclassPrio <= 9);
222    }
223 
224    /* Now check the soname prefix isn't "VG_Z_", as described in
225       pub_tool_redir.h. */
226    is_VG_Z_prefixed =
227       sym[12] == 'V' &&
228       sym[13] == 'G' &&
229       sym[14] == '_' &&
230       sym[15] == 'Z' &&
231       sym[16] == '_';
232    if (is_VG_Z_prefixed) {
233       vg_assert2(0, "symbol with a 'VG_Z_' prefix: %s.\n"
234                     "see pub_tool_redir.h for an explanation.", sym);
235    }
236 
237    /* Now scan the Z-encoded soname. */
238    i = 12;
239    while (True) {
240 
241       if (sym[i] == '_')
242       /* Found the delimiter.  Move on to the fnname loop. */
243          break;
244 
245       if (sym[i] == 0) {
246          error = True;
247          goto out;
248       }
249 
250       if (sym[i] != 'Z') {
251          EMITSO(sym[i]);
252          i++;
253          continue;
254       }
255 
256       /* We've got a Z-escape. */
257       i++;
258       switch (sym[i]) {
259          case 'a': EMITSO('*'); break;
260          case 'c': EMITSO(':'); break;
261          case 'd': EMITSO('.'); break;
262          case 'h': EMITSO('-'); break;
263          case 'p': EMITSO('+'); break;
264          case 's': EMITSO(' '); break;
265          case 'u': EMITSO('_'); break;
266          case 'A': EMITSO('@'); break;
267          case 'D': EMITSO('$'); break;
268          case 'L': EMITSO('('); break;
269          case 'R': EMITSO(')'); break;
270          case 'Z': EMITSO('Z'); break;
271          default: error = True; goto out;
272       }
273       i++;
274    }
275 
276    vg_assert(sym[i] == '_');
277    i++;
278 
279    /* Now deal with the function name part. */
280    if (!fn_is_encoded) {
281 
282       /* simple; just copy. */
283       while (True) {
284          if (sym[i] == 0)
285             break;
286          EMITFN(sym[i]);
287          i++;
288       }
289       goto out;
290 
291    }
292 
293    /* else use a Z-decoding loop like with soname */
294    while (True) {
295 
296       if (sym[i] == 0)
297          break;
298 
299       if (sym[i] != 'Z') {
300          EMITFN(sym[i]);
301          i++;
302          continue;
303       }
304 
305       /* We've got a Z-escape. */
306       i++;
307       switch (sym[i]) {
308          case 'a': EMITFN('*'); break;
309          case 'c': EMITFN(':'); break;
310          case 'd': EMITFN('.'); break;
311          case 'h': EMITFN('-'); break;
312          case 'p': EMITFN('+'); break;
313          case 's': EMITFN(' '); break;
314          case 'u': EMITFN('_'); break;
315          case 'A': EMITFN('@'); break;
316          case 'D': EMITFN('$'); break;
317          case 'L': EMITFN('('); break;
318          case 'R': EMITFN(')'); break;
319          case 'Z': EMITFN('Z'); break;
320          default: error = True; goto out;
321       }
322       i++;
323    }
324 
325   out:
326    EMITSO(0);
327    EMITFN(0);
328 
329    if (error) {
330       /* Something's wrong.  Give up. */
331       VG_(message)(Vg_UserMsg,
332                    "m_demangle: error Z-demangling: %s\n", sym);
333       return False;
334    }
335    if (oflow) {
336       /* It didn't fit.  Give up. */
337       VG_(message)(Vg_UserMsg,
338                    "m_demangle: oflow Z-demangling: %s\n", sym);
339       return False;
340    }
341 
342    return True;
343 }
344 
345 
346 /*--------------------------------------------------------------------*/
347 /*--- end                                                          ---*/
348 /*--------------------------------------------------------------------*/
349