Bool VG_(maybe_Z_demangle) ( const HChar* sym, /*OUT*/const HChar** so, /*OUT*/const HChar** fn, /*OUT*/Bool* isWrap, /*OUT*/Int* eclassTag, /*OUT*/Int* eclassPrio ) { static HChar *sobuf; static HChar *fnbuf; static SizeT buf_len = 0; /* The length of the name after undoing Z-encoding is always smaller than the mangled name. Making the soname and fnname buffers as large as the demangled name is therefore always safe and overflow can never occur. */ SizeT len = VG_(strlen)(sym) + 1; if (buf_len < len) { sobuf = VG_(arena_realloc)(VG_AR_DEMANGLE, "Z-demangle", sobuf, len); fnbuf = VG_(arena_realloc)(VG_AR_DEMANGLE, "Z-demangle", fnbuf, len); buf_len = len; } sobuf[0] = fnbuf[0] = '\0'; if (so) *so = sobuf; *fn = fnbuf; # define EMITSO(ch) \ do { \ if (so) { \ sobuf[soi++] = ch; sobuf[soi] = 0; \ } \ } while (0) # define EMITFN(ch) \ do { \ fnbuf[fni++] = ch; fnbuf[fni] = 0; \ } while (0) Bool error, valid, fn_is_encoded, is_VG_Z_prefixed; Int soi, fni, i; error = False; soi = 0; fni = 0; valid = sym[0] == '_' && sym[1] == 'v' && sym[2] == 'g' && (sym[3] == 'r' || sym[3] == 'w') && VG_(isdigit)(sym[4]) && VG_(isdigit)(sym[5]) && VG_(isdigit)(sym[6]) && VG_(isdigit)(sym[7]) && VG_(isdigit)(sym[8]) && sym[9] == 'Z' && (sym[10] == 'Z' || sym[10] == 'U') && sym[11] == '_'; if (valid && sym[4] == '0' && sym[5] == '0' && sym[6] == '0' && sym[7] == '0' && sym[8] != '0') { /* If the eclass tag is 0000 (meaning "no eclass"), the priority must be 0 too. */ valid = False; } if (!valid) return False; fn_is_encoded = sym[10] == 'Z'; if (isWrap) *isWrap = sym[3] == 'w'; if (eclassTag) { *eclassTag = 1000 * ((Int)sym[4] - '0') + 100 * ((Int)sym[5] - '0') + 10 * ((Int)sym[6] - '0') + 1 * ((Int)sym[7] - '0'); vg_assert(*eclassTag >= 0 && *eclassTag <= 9999); } if (eclassPrio) { *eclassPrio = ((Int)sym[8]) - '0'; vg_assert(*eclassPrio >= 0 && *eclassPrio <= 9); } /* Now check the soname prefix isn't "VG_Z_", as described in pub_tool_redir.h. */ is_VG_Z_prefixed = sym[12] == 'V' && sym[13] == 'G' && sym[14] == '_' && sym[15] == 'Z' && sym[16] == '_'; if (is_VG_Z_prefixed) { vg_assert2(0, "symbol with a 'VG_Z_' prefix: %s.\n" "see pub_tool_redir.h for an explanation.", sym); } /* Now scan the Z-encoded soname. */ i = 12; while (True) { if (sym[i] == '_') /* Found the delimiter. Move on to the fnname loop. */ break; if (sym[i] == 0) { error = True; goto out; } if (sym[i] != 'Z') { EMITSO(sym[i]); i++; continue; } /* We've got a Z-escape. */ i++; switch (sym[i]) { case 'a': EMITSO('*'); break; case 'c': EMITSO(':'); break; case 'd': EMITSO('.'); break; case 'h': EMITSO('-'); break; case 'p': EMITSO('+'); break; case 's': EMITSO(' '); break; case 'u': EMITSO('_'); break; case 'A': EMITSO('@'); break; case 'D': EMITSO('$'); break; case 'L': EMITSO('('); break; case 'R': EMITSO(')'); break; case 'S': EMITSO('/'); break; case 'Z': EMITSO('Z'); break; default: error = True; goto out; } i++; } vg_assert(sym[i] == '_'); i++; /* Now deal with the function name part. */ if (!fn_is_encoded) { /* simple; just copy. */ while (True) { if (sym[i] == 0) break; EMITFN(sym[i]); i++; } goto out; } /* else use a Z-decoding loop like with soname */ while (True) { if (sym[i] == 0) break; if (sym[i] != 'Z') { EMITFN(sym[i]); i++; continue; } /* We've got a Z-escape. */ i++; switch (sym[i]) { case 'a': EMITFN('*'); break; case 'c': EMITFN(':'); break; case 'd': EMITFN('.'); break; case 'h': EMITFN('-'); break; case 'p': EMITFN('+'); break; case 's': EMITFN(' '); break; case 'u': EMITFN('_'); break; case 'A': EMITFN('@'); break; case 'D': EMITFN('$'); break; case 'L': EMITFN('('); break; case 'R': EMITFN(')'); break; case 'Z': EMITFN('Z'); break; default: error = True; goto out; } i++; } out: EMITSO(0); EMITFN(0); if (error) { /* Something's wrong. Give up. */ VG_(message)(Vg_UserMsg, "m_demangle: error Z-demangling: %s\n", sym); return False; } return True; }
Bool VG_(maybe_Z_demangle) ( const HChar* sym, /*OUT*/HChar* so, Int soLen, /*OUT*/HChar* fn, Int fnLen, /*OUT*/Bool* isWrap ) { # define EMITSO(ch) \ do { \ if (so) { \ if (soi >= soLen) { \ so[soLen-1] = 0; oflow = True; \ } else { \ so[soi++] = ch; so[soi] = 0; \ } \ } \ } while (0) # define EMITFN(ch) \ do { \ if (fni >= fnLen) { \ fn[fnLen-1] = 0; oflow = True; \ } else { \ fn[fni++] = ch; fn[fni] = 0; \ } \ } while (0) Bool error, oflow, valid, fn_is_encoded, is_VG_Z_prefixed; Int soi, fni, i; vg_assert(soLen > 0 || (soLen == 0 && so == NULL)); vg_assert(fnLen > 0); error = False; oflow = False; soi = 0; fni = 0; valid = sym[0] == '_' && sym[1] == 'v' && sym[2] == 'g' && (sym[3] == 'r' || sym[3] == 'w' || sym[3] == 'n') && sym[4] == 'Z' && (sym[5] == 'Z' || sym[5] == 'U') && sym[6] == '_'; if (!valid) return False; fn_is_encoded = sym[5] == 'Z'; if (isWrap) *isWrap = sym[3] == 'w'; /* Now check the soname prefix isn't "VG_Z_", as described in pub_tool_redir.h. */ is_VG_Z_prefixed = sym[ 7] == 'V' && sym[ 8] == 'G' && sym[ 9] == '_' && sym[10] == 'Z' && sym[11] == '_'; if (is_VG_Z_prefixed) { vg_assert2(0, "symbol with a 'VG_Z_' prefix: %s.\n" "see pub_tool_redir.h for an explanation.", sym); } /* Now scan the Z-encoded soname. */ i = 7; while (True) { if (sym[i] == '_') /* Found the delimiter. Move on to the fnname loop. */ break; if (sym[i] == 0) { error = True; goto out; } if (sym[i] != 'Z') { EMITSO(sym[i]); i++; continue; } /* We've got a Z-escape. */ i++; switch (sym[i]) { case 'a': EMITSO('*'); break; case 'c': EMITSO(':'); break; case 'd': EMITSO('.'); break; case 'h': EMITSO('-'); break; case 'p': EMITSO('+'); break; case 's': EMITSO(' '); break; case 'u': EMITSO('_'); break; case 'A': EMITSO('@'); break; case 'D': EMITSO('$'); break; case 'L': EMITSO('('); break; case 'R': EMITSO(')'); break; case 'Z': EMITSO('Z'); break; default: error = True; goto out; } i++; } vg_assert(sym[i] == '_'); i++; /* Now deal with the function name part. */ if (!fn_is_encoded) { /* simple; just copy. */ while (True) { if (sym[i] == 0) break; EMITFN(sym[i]); i++; } goto out; } /* else use a Z-decoding loop like with soname */ while (True) { if (sym[i] == 0) break; if (sym[i] != 'Z') { EMITFN(sym[i]); i++; continue; } /* We've got a Z-escape. */ i++; switch (sym[i]) { case 'a': EMITFN('*'); break; case 'c': EMITFN(':'); break; case 'd': EMITFN('.'); break; case 'h': EMITFN('-'); break; case 'p': EMITFN('+'); break; case 's': EMITFN(' '); break; case 'u': EMITFN('_'); break; case 'A': EMITFN('@'); break; case 'D': EMITFN('$'); break; case 'L': EMITFN('('); break; case 'R': EMITFN(')'); break; case 'Z': EMITFN('Z'); break; default: error = True; goto out; } i++; } out: EMITSO(0); EMITFN(0); if (error) { /* Something's wrong. Give up. */ VG_(message)(Vg_UserMsg, "m_demangle: error Z-demangling: %s\n", sym); return False; } if (oflow) { /* It didn't fit. Give up. */ VG_(message)(Vg_UserMsg, "m_demangle: oflow Z-demangling: %s\n", sym); return False; } return True; }