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;
}
Example #2
0
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;
}