Home | History | Annotate | Download | only in m_demangle
      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 (at) 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 
     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 
    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