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