ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

undname.c
Go to the documentation of this file.
00001 /*
00002  *  Demangle VC++ symbols into C function prototypes
00003  *
00004  *  Copyright 2000 Jon Griffiths
00005  *            2004 Eric Pouech
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #define __WINE_DEBUG_CHANNEL__
00023 #include <precomp.h>
00024 #include <assert.h>
00025 
00026 #include <internal/wine/msvcrt.h>
00027 #include <internal/wine/cppexcept.h>
00028 
00029 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
00030 
00031 /* TODO:
00032  * - document a bit (grammar + functions)
00033  * - back-port this new code into tools/winedump/msmangle.c
00034  */
00035 
00036 #define UNDNAME_COMPLETE                 (0x0000)
00037 #define UNDNAME_NO_LEADING_UNDERSCORES   (0x0001) /* Don't show __ in calling convention */
00038 #define UNDNAME_NO_MS_KEYWORDS           (0x0002) /* Don't show calling convention at all */
00039 #define UNDNAME_NO_FUNCTION_RETURNS      (0x0004) /* Don't show function/method return value */
00040 #define UNDNAME_NO_ALLOCATION_MODEL      (0x0008)
00041 #define UNDNAME_NO_ALLOCATION_LANGUAGE   (0x0010)
00042 #define UNDNAME_NO_MS_THISTYPE           (0x0020)
00043 #define UNDNAME_NO_CV_THISTYPE           (0x0040)
00044 #define UNDNAME_NO_THISTYPE              (0x0060)
00045 #define UNDNAME_NO_ACCESS_SPECIFIERS     (0x0080) /* Don't show access specifier (public/protected/private) */
00046 #define UNDNAME_NO_THROW_SIGNATURES      (0x0100)
00047 #define UNDNAME_NO_MEMBER_TYPE           (0x0200) /* Don't show static/virtual specifier */
00048 #define UNDNAME_NO_RETURN_UDT_MODEL      (0x0400)
00049 #define UNDNAME_32_BIT_DECODE            (0x0800)
00050 #define UNDNAME_NAME_ONLY                (0x1000) /* Only report the variable/method name */
00051 #define UNDNAME_NO_ARGUMENTS             (0x2000) /* Don't show method arguments */
00052 #define UNDNAME_NO_SPECIAL_SYMS          (0x4000)
00053 #define UNDNAME_NO_COMPLEX_TYPE          (0x8000)
00054 
00055 /* How data types modifiers are stored:
00056  * M (in the following definitions) is defined for
00057  * 'A', 'B', 'C' and 'D' as follows
00058  *      {<A>}:  ""
00059  *      {<B>}:  "const "
00060  *      {<C>}:  "volatile "
00061  *      {<D>}:  "const volatile "
00062  *
00063  *      in arguments:
00064  *              P<M>x   {<M>}x*
00065  *              Q<M>x   {<M>}x* const
00066  *              A<M>x   {<M>}x&
00067  *      in data fields:
00068  *              same as for arguments and also the following
00069  *              ?<M>x   {<M>}x
00070  *
00071  */
00072 
00073 struct array
00074 {
00075     unsigned            start;          /* first valid reference in array */
00076     unsigned            num;            /* total number of used elts */
00077     unsigned            max;
00078     unsigned            alloc;
00079     char**              elts;
00080 };
00081 
00082 /* Structure holding a parsed symbol */
00083 struct parsed_symbol
00084 {
00085     unsigned            flags;          /* the UNDNAME_ flags used for demangling */
00086     malloc_func_t       mem_alloc_ptr;  /* internal allocator */
00087     free_func_t         mem_free_ptr;   /* internal deallocator */
00088 
00089     const char*         current;        /* pointer in input (mangled) string */
00090     char*               result;         /* demangled string */
00091 
00092     struct array        names;          /* array of names for back reference */
00093     struct array        stack;          /* stack of parsed strings */
00094 
00095     void*               alloc_list;     /* linked list of allocated blocks */
00096     unsigned            avail_in_first; /* number of available bytes in head block */
00097 };
00098 
00099 /* Type for parsing mangled types */
00100 struct datatype_t
00101 {
00102     const char*         left;
00103     const char*         right;
00104 };
00105 
00106 static BOOL symbol_demangle(struct parsed_symbol* sym);
00107 
00108 /******************************************************************
00109  *      und_alloc
00110  *
00111  * Internal allocator. Uses a simple linked list of large blocks
00112  * where we use a poor-man allocator. It's fast, and since all
00113  * allocation is pool, memory management is easy (esp. freeing).
00114  */
00115 static void*    und_alloc(struct parsed_symbol* sym, unsigned int len)
00116 {
00117     void*       ptr;
00118 
00119 #define BLOCK_SIZE      1024
00120 #define AVAIL_SIZE      (1024 - sizeof(void*))
00121 
00122     if (len > AVAIL_SIZE)
00123     {
00124         /* allocate a specific block */
00125         ptr = sym->mem_alloc_ptr(sizeof(void*) + len);
00126         if (!ptr) return NULL;
00127         *(void**)ptr = sym->alloc_list;
00128         sym->alloc_list = ptr;
00129         sym->avail_in_first = 0;
00130         ptr = (char*)sym->alloc_list + sizeof(void*);
00131     }
00132     else
00133     {
00134         if (len > sym->avail_in_first)
00135         {
00136             /* add a new block */
00137             ptr = sym->mem_alloc_ptr(BLOCK_SIZE);
00138             if (!ptr) return NULL;
00139             *(void**)ptr = sym->alloc_list;
00140             sym->alloc_list = ptr;
00141             sym->avail_in_first = AVAIL_SIZE;
00142         }
00143         /* grab memory from head block */
00144         ptr = (char*)sym->alloc_list + BLOCK_SIZE - sym->avail_in_first;
00145         sym->avail_in_first -= len;
00146     }
00147     return ptr;
00148 #undef BLOCK_SIZE
00149 #undef AVAIL_SIZE
00150 }
00151 
00152 /******************************************************************
00153  *      und_free
00154  * Frees all the blocks in the list of large blocks allocated by
00155  * und_alloc.
00156  */
00157 static void und_free_all(struct parsed_symbol* sym)
00158 {
00159     void*       next;
00160 
00161     while (sym->alloc_list)
00162     {
00163         next = *(void**)sym->alloc_list;
00164         if(sym->mem_free_ptr) sym->mem_free_ptr(sym->alloc_list);
00165         sym->alloc_list = next;
00166     }
00167     sym->avail_in_first = 0;
00168 }
00169 
00170 /******************************************************************
00171  *      str_array_init
00172  * Initialises an array of strings
00173  */
00174 static void str_array_init(struct array* a)
00175 {
00176     a->start = a->num = a->max = a->alloc = 0;
00177     a->elts = NULL;
00178 }
00179 
00180 /******************************************************************
00181  *      str_array_push
00182  * Adding a new string to an array
00183  */
00184 static BOOL str_array_push(struct parsed_symbol* sym, const char* ptr, int len,
00185                            struct array* a)
00186 {
00187     char**      new;
00188 
00189     assert(ptr);
00190     assert(a);
00191 
00192     if (!a->alloc)
00193     {
00194         new = und_alloc(sym, (a->alloc = 32) * sizeof(a->elts[0]));
00195         if (!new) return FALSE;
00196         a->elts = new;
00197     }
00198     else if (a->max >= a->alloc)
00199     {
00200         new = und_alloc(sym, (a->alloc * 2) * sizeof(a->elts[0]));
00201         if (!new) return FALSE;
00202         memcpy(new, a->elts, a->alloc * sizeof(a->elts[0]));
00203         a->alloc *= 2;
00204         a->elts = new;
00205     }
00206     if (len == -1) len = (int)strlen(ptr);
00207     a->elts[a->num] = und_alloc(sym, len + 1);
00208     assert(a->elts[a->num]);
00209     memcpy(a->elts[a->num], ptr, len);
00210     a->elts[a->num][len] = '\0';
00211     if (++a->num >= a->max) a->max = a->num;
00212     {
00213         int i;
00214         char c;
00215 
00216         for (i = a->max - 1; i >= 0; i--)
00217         {
00218             c = '>';
00219             if (i < a->start) c = '-';
00220             else if (i >= a->num) c = '}';
00221             /* This check is as useless as the unused-but-set gcc warning that we want to silence here */
00222             if (c != 0) TRACE("%p\t%d%c %s\n", a, i, c, a->elts[i]);
00223         }
00224     }
00225 
00226     return TRUE;
00227 }
00228 
00229 /******************************************************************
00230  *      str_array_get_ref
00231  * Extracts a reference from an existing array (doing proper type
00232  * checking)
00233  */
00234 static char* str_array_get_ref(struct array* cref, unsigned idx)
00235 {
00236     assert(cref);
00237     if (cref->start + idx >= cref->max)
00238     {
00239         WARN("Out of bounds: %p %d + %d >= %d\n",
00240               cref, cref->start, idx, cref->max);
00241         return NULL;
00242     }
00243     TRACE("Returning %p[%d] => %s\n",
00244           cref, idx, cref->elts[cref->start + idx]);
00245     return cref->elts[cref->start + idx];
00246 }
00247 
00248 /******************************************************************
00249  *      str_printf
00250  * Helper for printf type of command (only %s and %c are implemented)
00251  * while dynamically allocating the buffer
00252  */
00253 static char* str_printf(struct parsed_symbol* sym, const char* format, ...)
00254 {
00255     va_list      args;
00256     unsigned int len = 1, i, sz;
00257     char*        tmp;
00258     char*        p;
00259     char*        t;
00260 
00261     va_start(args, format);
00262     for (i = 0; format[i]; i++)
00263     {
00264         if (format[i] == '%')
00265         {
00266             switch (format[++i])
00267             {
00268             case 's': t = va_arg(args, char*); if (t) len += (int)strlen(t); break;
00269             case 'c': (void)va_arg(args, int); len++; break;
00270             default: i--; /* fall thru */
00271             case '%': len++; break;
00272             }
00273         }
00274         else len++;
00275     }
00276     va_end(args);
00277     if (!(tmp = und_alloc(sym, len))) return NULL;
00278     va_start(args, format);
00279     for (p = tmp, i = 0; format[i]; i++)
00280     {
00281         if (format[i] == '%')
00282         {
00283             switch (format[++i])
00284             {
00285             case 's':
00286                 t = va_arg(args, char*);
00287                 if (t)
00288                 {
00289                     sz = (int)strlen(t);
00290                     memcpy(p, t, sz);
00291                     p += sz;
00292                 }
00293                 break;
00294             case 'c':
00295                 *p++ = (char)va_arg(args, int);
00296                 break;
00297             default: i--; /* fall thru */
00298             case '%': *p++ = '%'; break;
00299             }
00300         }
00301         else *p++ = format[i];
00302     }
00303     va_end(args);
00304     *p = '\0';
00305     return tmp;
00306 }
00307 
00308 /* forward declaration */
00309 static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
00310                               struct array* pmt, BOOL in_args);
00311 
00312 static const char* get_number(struct parsed_symbol* sym)
00313 {
00314     char*       ptr;
00315     BOOL        sgn = FALSE;
00316 
00317     if (*sym->current == '?')
00318     {
00319         sgn = TRUE;
00320         sym->current++;
00321     }
00322     if (*sym->current >= '0' && *sym->current <= '8')
00323     {
00324         ptr = und_alloc(sym, 3);
00325         if (sgn) ptr[0] = '-';
00326         ptr[sgn ? 1 : 0] = *sym->current + 1;
00327         ptr[sgn ? 2 : 1] = '\0';
00328         sym->current++;
00329     }
00330     else if (*sym->current == '9')
00331     {
00332         ptr = und_alloc(sym, 4);
00333         if (sgn) ptr[0] = '-';
00334         ptr[sgn ? 1 : 0] = '1';
00335         ptr[sgn ? 2 : 1] = '0';
00336         ptr[sgn ? 3 : 2] = '\0';
00337         sym->current++;
00338     }
00339     else if (*sym->current >= 'A' && *sym->current <= 'P')
00340     {
00341         int ret = 0;
00342 
00343         while (*sym->current >= 'A' && *sym->current <= 'P')
00344         {
00345             ret *= 16;
00346             ret += *sym->current++ - 'A';
00347         }
00348         if (*sym->current != '@') return NULL;
00349 
00350         ptr = und_alloc(sym, 17);
00351         sprintf(ptr, "%s%d", sgn ? "-" : "", ret);
00352         sym->current++;
00353     }
00354     else return NULL;
00355     return ptr;
00356 }
00357 
00358 /******************************************************************
00359  *      get_args
00360  * Parses a list of function/method arguments, creates a string corresponding
00361  * to the arguments' list.
00362  */
00363 static char* get_args(struct parsed_symbol* sym, struct array* pmt_ref, BOOL z_term,
00364                       char open_char, char close_char)
00365 
00366 {
00367     struct datatype_t   ct;
00368     struct array        arg_collect;
00369     char*               args_str = NULL;
00370     char*               last;
00371     unsigned int        i;
00372 
00373     str_array_init(&arg_collect);
00374 
00375     /* Now come the function arguments */
00376     while (*sym->current)
00377     {
00378         /* Decode each data type and append it to the argument list */
00379         if (*sym->current == '@')
00380         {
00381             sym->current++;
00382             break;
00383         }
00384         if (!demangle_datatype(sym, &ct, pmt_ref, TRUE))
00385             return NULL;
00386         /* 'void' terminates an argument list in a function */
00387         if (z_term && !strcmp(ct.left, "void")) break;
00388         if (!str_array_push(sym, str_printf(sym, "%s%s", ct.left, ct.right), -1,
00389                             &arg_collect))
00390             return NULL;
00391         if (!strcmp(ct.left, "...")) break;
00392     }
00393     /* Functions are always terminated by 'Z'. If we made it this far and
00394      * don't find it, we have incorrectly identified a data type.
00395      */
00396     if (z_term && *sym->current++ != 'Z') return NULL;
00397 
00398     if (arg_collect.num == 0 ||
00399         (arg_collect.num == 1 && !strcmp(arg_collect.elts[0], "void")))
00400         return str_printf(sym, "%cvoid%c", open_char, close_char);
00401     for (i = 1; i < arg_collect.num; i++)
00402     {
00403         args_str = str_printf(sym, "%s,%s", args_str, arg_collect.elts[i]);
00404     }
00405 
00406     last = args_str ? args_str : arg_collect.elts[0];
00407     if (close_char == '>' && last[strlen(last) - 1] == '>')
00408         args_str = str_printf(sym, "%c%s%s %c",
00409                               open_char, arg_collect.elts[0], args_str, close_char);
00410     else
00411         args_str = str_printf(sym, "%c%s%s%c",
00412                               open_char, arg_collect.elts[0], args_str, close_char);
00413 
00414     return args_str;
00415 }
00416 
00417 /******************************************************************
00418  *      get_modifier
00419  * Parses the type modifier. Always returns static strings.
00420  */
00421 static BOOL get_modifier(struct parsed_symbol *sym, const char **ret, const char **ptr_modif)
00422 {
00423     *ptr_modif = NULL;
00424     if (*sym->current == 'E')
00425     {
00426         *ptr_modif = "__ptr64";
00427         sym->current++;
00428     }
00429     switch (*sym->current++)
00430     {
00431     case 'A': *ret = NULL; break;
00432     case 'B': *ret = "const"; break;
00433     case 'C': *ret = "volatile"; break;
00434     case 'D': *ret = "const volatile"; break;
00435     default: return FALSE;
00436     }
00437     return TRUE;
00438 }
00439 
00440 static BOOL get_modified_type(struct datatype_t *ct, struct parsed_symbol* sym,
00441                               struct array *pmt_ref, char modif, BOOL in_args)
00442 {
00443     const char* modifier;
00444     const char* str_modif;
00445     const char *ptr_modif = "";
00446 
00447     if (*sym->current == 'E')
00448     {
00449         ptr_modif = " __ptr64";
00450         sym->current++;
00451     }
00452 
00453     switch (modif)
00454     {
00455     case 'A': str_modif = str_printf(sym, " &%s", ptr_modif); break;
00456     case 'B': str_modif = str_printf(sym, " &%s volatile", ptr_modif); break;
00457     case 'P': str_modif = str_printf(sym, " *%s", ptr_modif); break;
00458     case 'Q': str_modif = str_printf(sym, " *%s const", ptr_modif); break;
00459     case 'R': str_modif = str_printf(sym, " *%s volatile", ptr_modif); break;
00460     case 'S': str_modif = str_printf(sym, " *%s const volatile", ptr_modif); break;
00461     case '?': str_modif = ""; break;
00462     default: return FALSE;
00463     }
00464 
00465     if (get_modifier(sym, &modifier, &ptr_modif))
00466     {
00467         unsigned            mark = sym->stack.num;
00468         struct datatype_t   sub_ct;
00469 
00470         /* multidimensional arrays */
00471         if (*sym->current == 'Y')
00472         {
00473             const char* n1;
00474             int num;
00475 
00476             sym->current++;
00477             if (!(n1 = get_number(sym))) return FALSE;
00478             num = atoi(n1);
00479 
00480             if (str_modif[0] == ' ' && !modifier)
00481                 str_modif++;
00482 
00483             if (modifier)
00484             {
00485                 str_modif = str_printf(sym, " (%s%s)", modifier, str_modif);
00486                 modifier = NULL;
00487             }
00488             else
00489                 str_modif = str_printf(sym, " (%s)", str_modif);
00490 
00491             while (num--)
00492                 str_modif = str_printf(sym, "%s[%s]", str_modif, get_number(sym));
00493         }
00494 
00495         /* Recurse to get the referred-to type */
00496         if (!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
00497             return FALSE;
00498         if (modifier)
00499             ct->left = str_printf(sym, "%s %s%s", sub_ct.left, modifier, str_modif );
00500         else
00501         {
00502             /* don't insert a space between duplicate '*' */
00503             if (!in_args && str_modif[0] && str_modif[1] == '*' && sub_ct.left[strlen(sub_ct.left)-1] == '*')
00504                 str_modif++;
00505             ct->left = str_printf(sym, "%s%s", sub_ct.left, str_modif );
00506         }
00507         ct->right = sub_ct.right;
00508         sym->stack.num = mark;
00509     }
00510     return TRUE;
00511 }
00512 
00513 /******************************************************************
00514  *             get_literal_string
00515  * Gets the literal name from the current position in the mangled
00516  * symbol to the first '@' character. It pushes the parsed name to
00517  * the symbol names stack and returns a pointer to it or NULL in
00518  * case of an error.
00519  */
00520 static char* get_literal_string(struct parsed_symbol* sym)
00521 {
00522     const char *ptr = sym->current;
00523 
00524     do {
00525         if (!((*sym->current >= 'A' && *sym->current <= 'Z') ||
00526               (*sym->current >= 'a' && *sym->current <= 'z') ||
00527               (*sym->current >= '0' && *sym->current <= '9') ||
00528               *sym->current == '_' || *sym->current == '$')) {
00529             TRACE("Failed at '%c' in %s\n", *sym->current, ptr);
00530             return NULL;
00531         }
00532     } while (*++sym->current != '@');
00533     sym->current++;
00534     if (!str_array_push(sym, ptr, (int)(sym->current - 1 - ptr), &sym->names))
00535         return NULL;
00536 
00537     return str_array_get_ref(&sym->names, sym->names.num - sym->names.start - 1);
00538 }
00539 
00540 /******************************************************************
00541  *      get_template_name
00542  * Parses a name with a template argument list and returns it as
00543  * a string.
00544  * In a template argument list the back reference to the names
00545  * table is separately created. '0' points to the class component
00546  * name with the template arguments.  We use the same stack array
00547  * to hold the names but save/restore the stack state before/after
00548  * parsing the template argument list.
00549  */
00550 static char* get_template_name(struct parsed_symbol* sym)
00551 {
00552     char *name, *args;
00553     unsigned num_mark = sym->names.num;
00554     unsigned start_mark = sym->names.start;
00555     unsigned stack_mark = sym->stack.num;
00556     struct array array_pmt;
00557 
00558     sym->names.start = sym->names.num;
00559     if (!(name = get_literal_string(sym)))
00560         return FALSE;
00561     str_array_init(&array_pmt);
00562     args = get_args(sym, &array_pmt, FALSE, '<', '>');
00563     if (args != NULL)
00564         name = str_printf(sym, "%s%s", name, args);
00565     sym->names.num = num_mark;
00566     sym->names.start = start_mark;
00567     sym->stack.num = stack_mark;
00568     return name;
00569 }
00570 
00571 /******************************************************************
00572  *      get_class
00573  * Parses class as a list of parent-classes, terminated by '@' and stores the
00574  * result in 'a' array. Each parent-classes, as well as the inner element
00575  * (either field/method name or class name), are represented in the mangled
00576  * name by a literal name ([a-zA-Z0-9_]+ terminated by '@') or a back reference
00577  * ([0-9]) or a name with template arguments ('?$' literal name followed by the
00578  * template argument list). The class name components appear in the reverse
00579  * order in the mangled name, e.g aaa@bbb@ccc@@ will be demangled to
00580  * ccc::bbb::aaa
00581  * For each of these class name components a string will be allocated in the
00582  * array.
00583  */
00584 static BOOL get_class(struct parsed_symbol* sym)
00585 {
00586     const char* name = NULL;
00587 
00588     while (*sym->current != '@')
00589     {
00590         switch (*sym->current)
00591         {
00592         case '\0': return FALSE;
00593 
00594         case '0': case '1': case '2': case '3':
00595         case '4': case '5': case '6': case '7':
00596         case '8': case '9':
00597             name = str_array_get_ref(&sym->names, *sym->current++ - '0');
00598             break;
00599         case '?':
00600             switch (*++sym->current)
00601             {
00602             case '$':
00603                 sym->current++;
00604                 if ((name = get_template_name(sym)) &&
00605                     !str_array_push(sym, name, -1, &sym->names))
00606                     return FALSE;
00607                 break;
00608             case '?':
00609                 {
00610                     struct array stack = sym->stack;
00611                     unsigned int start = sym->names.start;
00612                     unsigned int num = sym->names.num;
00613 
00614                     str_array_init( &sym->stack );
00615                     if (symbol_demangle( sym )) name = str_printf( sym, "`%s'", sym->result );
00616                     sym->names.start = start;
00617                     sym->names.num = num;
00618                     sym->stack = stack;
00619                 }
00620                 break;
00621             default:
00622                 if (!(name = get_number( sym ))) return FALSE;
00623                 name = str_printf( sym, "`%s'", name );
00624                 break;
00625             }
00626             break;
00627         default:
00628             name = get_literal_string(sym);
00629             break;
00630         }
00631         if (!name || !str_array_push(sym, name, -1, &sym->stack))
00632             return FALSE;
00633     }
00634     sym->current++;
00635     return TRUE;
00636 }
00637 
00638 /******************************************************************
00639  *      get_class_string
00640  * From an array collected by get_class in sym->stack, constructs the
00641  * corresponding (allocated) string
00642  */
00643 static char* get_class_string(struct parsed_symbol* sym, int start)
00644 {
00645     int          i;
00646     unsigned int len, sz;
00647     char*        ret;
00648     struct array *a = &sym->stack;
00649 
00650     for (len = 0, i = start; i < (int)a->num; i++)
00651     {
00652         assert(a->elts[i]);
00653         len += 2 + (int)strlen(a->elts[i]);
00654     }
00655     if (!(ret = und_alloc(sym, len - 1))) return NULL;
00656     for (len = 0, i = a->num - 1; i >= start; i--)
00657     {
00658         sz = (int)strlen(a->elts[i]);
00659         memcpy(ret + len, a->elts[i], sz);
00660         len += sz;
00661         if (i > start)
00662         {
00663             ret[len++] = ':';
00664             ret[len++] = ':';
00665         }
00666     }
00667     ret[len] = '\0';
00668     return ret;
00669 }
00670 
00671 /******************************************************************
00672  *            get_class_name
00673  * Wrapper around get_class and get_class_string.
00674  */
00675 static char* get_class_name(struct parsed_symbol* sym)
00676 {
00677     unsigned    mark = sym->stack.num;
00678     char*       s = NULL;
00679 
00680     if (get_class(sym))
00681         s = get_class_string(sym, mark);
00682     sym->stack.num = mark;
00683     return s;
00684 }
00685 
00686 /******************************************************************
00687  *      get_calling_convention
00688  * Returns a static string corresponding to the calling convention described
00689  * by char 'ch'. Sets export to TRUE iff the calling convention is exported.
00690  */
00691 static BOOL get_calling_convention(char ch, const char** call_conv,
00692                                    const char** exported, unsigned flags)
00693 {
00694     *call_conv = *exported = NULL;
00695 
00696     if (!(flags & (UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ALLOCATION_LANGUAGE)))
00697     {
00698         if (flags & UNDNAME_NO_LEADING_UNDERSCORES)
00699         {
00700             if (((ch - 'A') % 2) == 1) *exported = "dll_export ";
00701             switch (ch)
00702             {
00703             case 'A': case 'B': *call_conv = "cdecl"; break;
00704             case 'C': case 'D': *call_conv = "pascal"; break;
00705             case 'E': case 'F': *call_conv = "thiscall"; break;
00706             case 'G': case 'H': *call_conv = "stdcall"; break;
00707             case 'I': case 'J': *call_conv = "fastcall"; break;
00708             case 'K': case 'L': break;
00709             case 'M': *call_conv = "clrcall"; break;
00710             default: ERR("Unknown calling convention %c\n", ch); return FALSE;
00711             }
00712         }
00713         else
00714         {
00715             if (((ch - 'A') % 2) == 1) *exported = "__dll_export ";
00716             switch (ch)
00717             {
00718             case 'A': case 'B': *call_conv = "__cdecl"; break;
00719             case 'C': case 'D': *call_conv = "__pascal"; break;
00720             case 'E': case 'F': *call_conv = "__thiscall"; break;
00721             case 'G': case 'H': *call_conv = "__stdcall"; break;
00722             case 'I': case 'J': *call_conv = "__fastcall"; break;
00723             case 'K': case 'L': break;
00724             case 'M': *call_conv = "__clrcall"; break;
00725             default: ERR("Unknown calling convention %c\n", ch); return FALSE;
00726             }
00727         }
00728     }
00729     return TRUE;
00730 }
00731 
00732 /*******************************************************************
00733  *         get_simple_type
00734  * Return a string containing an allocated string for a simple data type
00735  */
00736 static const char* get_simple_type(char c)
00737 {
00738     const char* type_string;
00739 
00740     switch (c)
00741     {
00742     case 'C': type_string = "signed char"; break;
00743     case 'D': type_string = "char"; break;
00744     case 'E': type_string = "unsigned char"; break;
00745     case 'F': type_string = "short"; break;
00746     case 'G': type_string = "unsigned short"; break;
00747     case 'H': type_string = "int"; break;
00748     case 'I': type_string = "unsigned int"; break;
00749     case 'J': type_string = "long"; break;
00750     case 'K': type_string = "unsigned long"; break;
00751     case 'M': type_string = "float"; break;
00752     case 'N': type_string = "double"; break;
00753     case 'O': type_string = "long double"; break;
00754     case 'X': type_string = "void"; break;
00755     case 'Z': type_string = "..."; break;
00756     default:  type_string = NULL; break;
00757     }
00758     return type_string;
00759 }
00760 
00761 /*******************************************************************
00762  *         get_extended_type
00763  * Return a string containing an allocated string for a simple data type
00764  */
00765 static const char* get_extended_type(char c)
00766 {
00767     const char* type_string;
00768 
00769     switch (c)
00770     {
00771     case 'D': type_string = "__int8"; break;
00772     case 'E': type_string = "unsigned __int8"; break;
00773     case 'F': type_string = "__int16"; break;
00774     case 'G': type_string = "unsigned __int16"; break;
00775     case 'H': type_string = "__int32"; break;
00776     case 'I': type_string = "unsigned __int32"; break;
00777     case 'J': type_string = "__int64"; break;
00778     case 'K': type_string = "unsigned __int64"; break;
00779     case 'L': type_string = "__int128"; break;
00780     case 'M': type_string = "unsigned __int128"; break;
00781     case 'N': type_string = "bool"; break;
00782     case 'W': type_string = "wchar_t"; break;
00783     default:  type_string = NULL; break;
00784     }
00785     return type_string;
00786 }
00787 
00788 /*******************************************************************
00789  *         demangle_datatype
00790  *
00791  * Attempt to demangle a C++ data type, which may be datatype.
00792  * a datatype type is made up of a number of simple types. e.g:
00793  * char** = (pointer to (pointer to (char)))
00794  */
00795 static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
00796                               struct array* pmt_ref, BOOL in_args)
00797 {
00798     char                dt;
00799     BOOL                add_pmt = TRUE;
00800 
00801     assert(ct);
00802     ct->left = ct->right = NULL;
00803 
00804     switch (dt = *sym->current++)
00805     {
00806     case '_':
00807         /* MS type: __int8,__int16 etc */
00808         ct->left = get_extended_type(*sym->current++);
00809         break;
00810     case 'C': case 'D': case 'E': case 'F': case 'G':
00811     case 'H': case 'I': case 'J': case 'K': case 'M':
00812     case 'N': case 'O': case 'X': case 'Z':
00813         /* Simple data types */
00814         ct->left = get_simple_type(dt);
00815         add_pmt = FALSE;
00816         break;
00817     case 'T': /* union */
00818     case 'U': /* struct */
00819     case 'V': /* class */
00820     case 'Y': /* cointerface */
00821         /* Class/struct/union/cointerface */
00822         {
00823             const char* struct_name = NULL;
00824             const char* type_name = NULL;
00825 
00826             if (!(struct_name = get_class_name(sym)))
00827                 goto done;
00828             if (!(sym->flags & UNDNAME_NO_COMPLEX_TYPE))
00829             {
00830                 switch (dt)
00831                 {
00832                 case 'T': type_name = "union ";  break;
00833                 case 'U': type_name = "struct "; break;
00834                 case 'V': type_name = "class ";  break;
00835                 case 'Y': type_name = "cointerface "; break;
00836                 }
00837             }
00838             ct->left = str_printf(sym, "%s%s", type_name, struct_name);
00839         }
00840         break;
00841     case '?':
00842         /* not all the time is seems */
00843         if (in_args)
00844         {
00845             const char*   ptr;
00846             if (!(ptr = get_number(sym))) goto done;
00847             ct->left = str_printf(sym, "`template-parameter-%s'", ptr);
00848         }
00849         else
00850         {
00851             if (!get_modified_type(ct, sym, pmt_ref, '?', in_args)) goto done;
00852         }
00853         break;
00854     case 'A': /* reference */
00855     case 'B': /* volatile reference */
00856         if (!get_modified_type(ct, sym, pmt_ref, dt, in_args)) goto done;
00857         break;
00858     case 'Q': /* const pointer */
00859     case 'R': /* volatile pointer */
00860     case 'S': /* const volatile pointer */
00861         if (!get_modified_type(ct, sym, pmt_ref, in_args ? dt : 'P', in_args)) goto done;
00862         break;
00863     case 'P': /* Pointer */
00864         if (isdigit(*sym->current))
00865     {
00866             /* FIXME: P6 = Function pointer, others who knows.. */
00867             if (*sym->current++ == '6')
00868             {
00869                 char*                   args = NULL;
00870                 const char*             call_conv;
00871                 const char*             exported;
00872                 struct datatype_t       sub_ct;
00873                 unsigned                mark = sym->stack.num;
00874 
00875                 if (!get_calling_convention(*sym->current++,
00876                                             &call_conv, &exported,
00877                                             sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) ||
00878                     !demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
00879                     goto done;
00880 
00881                 args = get_args(sym, pmt_ref, TRUE, '(', ')');
00882                 if (!args) goto done;
00883                 sym->stack.num = mark;
00884 
00885                 ct->left  = str_printf(sym, "%s%s (%s*",
00886                                        sub_ct.left, sub_ct.right, call_conv);
00887                 ct->right = str_printf(sym, ")%s", args);
00888             }
00889             else goto done;
00890     }
00891     else if (!get_modified_type(ct, sym, pmt_ref, 'P', in_args)) goto done;
00892         break;
00893     case 'W':
00894         if (*sym->current == '4')
00895         {
00896             char*               enum_name;
00897             sym->current++;
00898             if (!(enum_name = get_class_name(sym)))
00899                 goto done;
00900             if (sym->flags & UNDNAME_NO_COMPLEX_TYPE)
00901                 ct->left = enum_name;
00902             else
00903                 ct->left = str_printf(sym, "enum %s", enum_name);
00904         }
00905         else goto done;
00906         break;
00907     case '0': case '1': case '2': case '3': case '4':
00908     case '5': case '6': case '7': case '8': case '9':
00909         /* Referring back to previously parsed type */
00910         /* left and right are pushed as two separate strings */
00911         ct->left = str_array_get_ref(pmt_ref, (dt - '0') * 2);
00912         ct->right = str_array_get_ref(pmt_ref, (dt - '0') * 2 + 1);
00913         if (!ct->left) goto done;
00914         add_pmt = FALSE;
00915         break;
00916     case '$':
00917         switch (*sym->current++)
00918         {
00919         case '0':
00920             if (!(ct->left = get_number(sym))) goto done;
00921             break;
00922         case 'D':
00923             {
00924                 const char*   ptr;
00925                 if (!(ptr = get_number(sym))) goto done;
00926                 ct->left = str_printf(sym, "`template-parameter%s'", ptr);
00927             }
00928             break;
00929         case 'F':
00930             {
00931                 const char*   p1;
00932                 const char*   p2;
00933                 if (!(p1 = get_number(sym))) goto done;
00934                 if (!(p2 = get_number(sym))) goto done;
00935                 ct->left = str_printf(sym, "{%s,%s}", p1, p2);
00936             }
00937             break;
00938         case 'G':
00939             {
00940                 const char*   p1;
00941                 const char*   p2;
00942                 const char*   p3;
00943                 if (!(p1 = get_number(sym))) goto done;
00944                 if (!(p2 = get_number(sym))) goto done;
00945                 if (!(p3 = get_number(sym))) goto done;
00946                 ct->left = str_printf(sym, "{%s,%s,%s}", p1, p2, p3);
00947             }
00948             break;
00949         case 'Q':
00950             {
00951                 const char*   ptr;
00952                 if (!(ptr = get_number(sym))) goto done;
00953                 ct->left = str_printf(sym, "`non-type-template-parameter%s'", ptr);
00954             }
00955             break;
00956         case '$':
00957             if (*sym->current == 'C')
00958             {
00959                 const char *ptr, *ptr_modif;
00960 
00961                 sym->current++;
00962                 if (!get_modifier(sym, &ptr, &ptr_modif)) goto done;
00963                 if (!demangle_datatype(sym, ct, pmt_ref, in_args)) goto done;
00964                 ct->left = str_printf(sym, "%s %s", ct->left, ptr);
00965             }
00966             break;
00967         }
00968         break;
00969     default :
00970         ERR("Unknown type %c\n", dt);
00971         break;
00972     }
00973     if (add_pmt && pmt_ref && in_args)
00974     {
00975         /* left and right are pushed as two separate strings */
00976         if (!str_array_push(sym, ct->left ? ct->left : "", -1, pmt_ref) ||
00977             !str_array_push(sym, ct->right ? ct->right : "", -1, pmt_ref))
00978             return FALSE;
00979     }
00980 done:
00981 
00982     return ct->left != NULL;
00983 }
00984 
00985 /******************************************************************
00986  *      handle_data
00987  * Does the final parsing and handling for a variable or a field in
00988  * a class.
00989  */
00990 static BOOL handle_data(struct parsed_symbol* sym)
00991 {
00992     const char*         access = NULL;
00993     const char*         member_type = NULL;
00994     const char*         modifier = NULL;
00995     const char*         ptr_modif;
00996     struct datatype_t   ct;
00997     char*               name = NULL;
00998     BOOL                ret = FALSE;
00999 
01000     /* 0 private static
01001      * 1 protected static
01002      * 2 public static
01003      * 3 private non-static
01004      * 4 protected non-static
01005      * 5 public non-static
01006      * 6 ?? static
01007      * 7 ?? static
01008      */
01009 
01010     if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))
01011     {
01012         /* we only print the access for static members */
01013         switch (*sym->current)
01014         {
01015         case '0': access = "private: "; break;
01016         case '1': access = "protected: "; break;
01017         case '2': access = "public: "; break;
01018         }
01019     }
01020 
01021     if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))
01022     {
01023         if (*sym->current >= '0' && *sym->current <= '2')
01024             member_type = "static ";
01025     }
01026 
01027     name = get_class_string(sym, 0);
01028 
01029     switch (*sym->current++)
01030     {
01031     case '0': case '1': case '2':
01032     case '3': case '4': case '5':
01033         {
01034             unsigned mark = sym->stack.num;
01035             struct array pmt;
01036 
01037             str_array_init(&pmt);
01038 
01039             if (!demangle_datatype(sym, &ct, &pmt, FALSE)) goto done;
01040             if (!get_modifier(sym, &modifier, &ptr_modif)) goto done;
01041             if (modifier && ptr_modif) modifier = str_printf(sym, "%s %s", modifier, ptr_modif);
01042             else if (!modifier) modifier = ptr_modif;
01043             sym->stack.num = mark;
01044         }
01045         break;
01046     case '6' : /* compiler generated static */
01047     case '7' : /* compiler generated static */
01048         ct.left = ct.right = NULL;
01049         if (!get_modifier(sym, &modifier, &ptr_modif)) goto done;
01050         if (*sym->current != '@')
01051         {
01052             char*       cls = NULL;
01053 
01054             if (!(cls = get_class_name(sym)))
01055                 goto done;
01056             ct.right = str_printf(sym, "{for `%s'}", cls);
01057         }
01058         break;
01059     case '8':
01060     case '9':
01061         modifier = ct.left = ct.right = NULL;
01062         break;
01063     default: goto done;
01064     }
01065     if (sym->flags & UNDNAME_NAME_ONLY) ct.left = ct.right = modifier = NULL;
01066 
01067     sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s", access,
01068                              member_type, ct.left,
01069                              modifier && ct.left ? " " : NULL, modifier,
01070                              modifier || ct.left ? " " : NULL, name, ct.right);
01071     ret = TRUE;
01072 done:
01073     return ret;
01074 }
01075 
01076 /******************************************************************
01077  *      handle_method
01078  * Does the final parsing and handling for a function or a method in
01079  * a class.
01080  */
01081 static BOOL handle_method(struct parsed_symbol* sym, BOOL cast_op)
01082 {
01083     char                accmem;
01084     const char*         access = NULL;
01085     const char*         member_type = NULL;
01086     struct datatype_t   ct_ret;
01087     const char*         call_conv;
01088     const char*         modifier = NULL;
01089     const char*         exported;
01090     const char*         args_str = NULL;
01091     const char*         name = NULL;
01092     BOOL                ret = FALSE;
01093     unsigned            mark;
01094     struct array        array_pmt;
01095 
01096     /* FIXME: why 2 possible letters for each option?
01097      * 'A' private:
01098      * 'B' private:
01099      * 'C' private: static
01100      * 'D' private: static
01101      * 'E' private: virtual
01102      * 'F' private: virtual
01103      * 'G' private: thunk
01104      * 'H' private: thunk
01105      * 'I' protected:
01106      * 'J' protected:
01107      * 'K' protected: static
01108      * 'L' protected: static
01109      * 'M' protected: virtual
01110      * 'N' protected: virtual
01111      * 'O' protected: thunk
01112      * 'P' protected: thunk
01113      * 'Q' public:
01114      * 'R' public:
01115      * 'S' public: static
01116      * 'T' public: static
01117      * 'U' public: virtual
01118      * 'V' public: virtual
01119      * 'W' public: thunk
01120      * 'X' public: thunk
01121      * 'Y'
01122      * 'Z'
01123      */
01124     accmem = *sym->current++;
01125     if (accmem < 'A' || accmem > 'Z') goto done;
01126 
01127     if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))
01128     {
01129         switch ((accmem - 'A') / 8)
01130         {
01131         case 0: access = "private: "; break;
01132         case 1: access = "protected: "; break;
01133         case 2: access = "public: "; break;
01134         }
01135     }
01136     if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))
01137     {
01138         if (accmem <= 'X')
01139         {
01140             switch ((accmem - 'A') % 8)
01141             {
01142             case 2: case 3: member_type = "static "; break;
01143             case 4: case 5: member_type = "virtual "; break;
01144             case 6: case 7:
01145                 access = str_printf(sym, "[thunk]:%s", access);
01146                 member_type = "virtual ";
01147                 break;
01148             }
01149         }
01150     }
01151 
01152     name = get_class_string(sym, 0);
01153 
01154     if ((accmem - 'A') % 8 == 6 || (accmem - '8') % 8 == 7) /* a thunk */
01155         name = str_printf(sym, "%s`adjustor{%s}' ", name, get_number(sym));
01156 
01157     if (accmem <= 'X')
01158     {
01159         if (((accmem - 'A') % 8) != 2 && ((accmem - 'A') % 8) != 3)
01160         {
01161             const char *ptr_modif;
01162             /* Implicit 'this' pointer */
01163             /* If there is an implicit this pointer, const modifier follows */
01164             if (!get_modifier(sym, &modifier, &ptr_modif)) goto done;
01165             if (modifier || ptr_modif) modifier = str_printf(sym, "%s %s", modifier, ptr_modif);
01166         }
01167     }
01168 
01169     if (!get_calling_convention(*sym->current++, &call_conv, &exported,
01170                                 sym->flags))
01171         goto done;
01172 
01173     str_array_init(&array_pmt);
01174 
01175     /* Return type, or @ if 'void' */
01176     if (*sym->current == '@')
01177     {
01178         ct_ret.left = "void";
01179         ct_ret.right = NULL;
01180         sym->current++;
01181     }
01182     else
01183     {
01184         if (!demangle_datatype(sym, &ct_ret, &array_pmt, FALSE))
01185             goto done;
01186     }
01187     if (sym->flags & UNDNAME_NO_FUNCTION_RETURNS)
01188         ct_ret.left = ct_ret.right = NULL;
01189     if (cast_op)
01190     {
01191         name = str_printf(sym, "%s%s%s", name, ct_ret.left, ct_ret.right);
01192         ct_ret.left = ct_ret.right = NULL;
01193     }
01194 
01195     mark = sym->stack.num;
01196     if (!(args_str = get_args(sym, &array_pmt, TRUE, '(', ')'))) goto done;
01197     if (sym->flags & UNDNAME_NAME_ONLY) args_str = modifier = NULL;
01198     sym->stack.num = mark;
01199 
01200     /* Note: '()' after 'Z' means 'throws', but we don't care here
01201      * Yet!!! FIXME
01202      */
01203     sym->result = str_printf(sym, "%s%s%s%s%s%s%s%s%s%s%s",
01204                              access, member_type, ct_ret.left,
01205                              (ct_ret.left && !ct_ret.right) ? " " : NULL,
01206                              call_conv, call_conv ? " " : NULL, exported,
01207                              name, args_str, modifier, ct_ret.right);
01208     ret = TRUE;
01209 done:
01210     return ret;
01211 }
01212 
01213 /******************************************************************
01214  *      handle_template
01215  * Does the final parsing and handling for a name with templates
01216  */
01217 static BOOL handle_template(struct parsed_symbol* sym)
01218 {
01219     const char* name;
01220     const char* args;
01221 
01222     assert(*sym->current == '$');
01223     sym->current++;
01224     if (!(name = get_literal_string(sym))) return FALSE;
01225     if (!(args = get_args(sym, NULL, FALSE, '<', '>'))) return FALSE;
01226     sym->result = str_printf(sym, "%s%s", name, args);
01227     return TRUE;
01228 }
01229 
01230 /*******************************************************************
01231  *         symbol_demangle
01232  * Demangle a C++ linker symbol
01233  */
01234 static BOOL symbol_demangle(struct parsed_symbol* sym)
01235 {
01236     BOOL                ret = FALSE;
01237     unsigned            do_after = 0;
01238     static CHAR         dashed_null[] = "--null--";
01239 
01240     /* FIXME seems wrong as name, as it demangles a simple data type */
01241     if (sym->flags & UNDNAME_NO_ARGUMENTS)
01242     {
01243         struct datatype_t   ct;
01244 
01245         if (demangle_datatype(sym, &ct, NULL, FALSE))
01246         {
01247             sym->result = str_printf(sym, "%s%s", ct.left, ct.right);
01248             ret = TRUE;
01249         }
01250         goto done;
01251     }
01252 
01253     /* MS mangled names always begin with '?' */
01254     if (*sym->current != '?') return FALSE;
01255     sym->current++;
01256 
01257     /* Then function name or operator code */
01258     if (*sym->current == '?' && (sym->current[1] != '$' || sym->current[2] == '?'))
01259     {
01260         const char* function_name = NULL;
01261 
01262         if (sym->current[1] == '$')
01263         {
01264             do_after = 6;
01265             sym->current += 2;
01266         }
01267 
01268         /* C++ operator code (one character, or two if the first is '_') */
01269         switch (*++sym->current)
01270         {
01271         case '0': do_after = 1; break;
01272         case '1': do_after = 2; break;
01273         case '2': function_name = "operator new"; break;
01274         case '3': function_name = "operator delete"; break;
01275         case '4': function_name = "operator="; break;
01276         case '5': function_name = "operator>>"; break;
01277         case '6': function_name = "operator<<"; break;
01278         case '7': function_name = "operator!"; break;
01279         case '8': function_name = "operator=="; break;
01280         case '9': function_name = "operator!="; break;
01281         case 'A': function_name = "operator[]"; break;
01282         case 'B': function_name = "operator "; do_after = 3; break;
01283         case 'C': function_name = "operator->"; break;
01284         case 'D': function_name = "operator*"; break;
01285         case 'E': function_name = "operator++"; break;
01286         case 'F': function_name = "operator--"; break;
01287         case 'G': function_name = "operator-"; break;
01288         case 'H': function_name = "operator+"; break;
01289         case 'I': function_name = "operator&"; break;
01290         case 'J': function_name = "operator->*"; break;
01291         case 'K': function_name = "operator/"; break;
01292         case 'L': function_name = "operator%"; break;
01293         case 'M': function_name = "operator<"; break;
01294         case 'N': function_name = "operator<="; break;
01295         case 'O': function_name = "operator>"; break;
01296         case 'P': function_name = "operator>="; break;
01297         case 'Q': function_name = "operator,"; break;
01298         case 'R': function_name = "operator()"; break;
01299         case 'S': function_name = "operator~"; break;
01300         case 'T': function_name = "operator^"; break;
01301         case 'U': function_name = "operator|"; break;
01302         case 'V': function_name = "operator&&"; break;
01303         case 'W': function_name = "operator||"; break;
01304         case 'X': function_name = "operator*="; break;
01305         case 'Y': function_name = "operator+="; break;
01306         case 'Z': function_name = "operator-="; break;
01307         case '_':
01308             switch (*++sym->current)
01309             {
01310             case '0': function_name = "operator/="; break;
01311             case '1': function_name = "operator%="; break;
01312             case '2': function_name = "operator>>="; break;
01313             case '3': function_name = "operator<<="; break;
01314             case '4': function_name = "operator&="; break;
01315             case '5': function_name = "operator|="; break;
01316             case '6': function_name = "operator^="; break;
01317             case '7': function_name = "`vftable'"; break;
01318             case '8': function_name = "`vbtable'"; break;
01319             case '9': function_name = "`vcall'"; break;
01320             case 'A': function_name = "`typeof'"; break;
01321             case 'B': function_name = "`local static guard'"; break;
01322             case 'C': function_name = "`string'"; do_after = 4; break;
01323             case 'D': function_name = "`vbase destructor'"; break;
01324             case 'E': function_name = "`vector deleting destructor'"; break;
01325             case 'F': function_name = "`default constructor closure'"; break;
01326             case 'G': function_name = "`scalar deleting destructor'"; break;
01327             case 'H': function_name = "`vector constructor iterator'"; break;
01328             case 'I': function_name = "`vector destructor iterator'"; break;
01329             case 'J': function_name = "`vector vbase constructor iterator'"; break;
01330             case 'K': function_name = "`virtual displacement map'"; break;
01331             case 'L': function_name = "`eh vector constructor iterator'"; break;
01332             case 'M': function_name = "`eh vector destructor iterator'"; break;
01333             case 'N': function_name = "`eh vector vbase constructor iterator'"; break;
01334             case 'O': function_name = "`copy constructor closure'"; break;
01335             case 'R':
01336                 sym->flags |= UNDNAME_NO_FUNCTION_RETURNS;
01337                 switch (*++sym->current)
01338                 {
01339                 case '0':
01340                     {
01341                         struct datatype_t       ct;
01342                         struct array pmt;
01343 
01344                         sym->current++;
01345                         str_array_init(&pmt);
01346                         demangle_datatype(sym, &ct, &pmt, FALSE);
01347                         function_name = str_printf(sym, "%s%s `RTTI Type Descriptor'",
01348                                                    ct.left, ct.right);
01349                         sym->current--;
01350                     }
01351                     break;
01352                 case '1':
01353                     {
01354                         const char* n1, *n2, *n3, *n4;
01355                         sym->current++;
01356                         n1 = get_number(sym);
01357                         n2 = get_number(sym);
01358                         n3 = get_number(sym);
01359                         n4 = get_number(sym);
01360                         sym->current--;
01361                         function_name = str_printf(sym, "`RTTI Base Class Descriptor at (%s,%s,%s,%s)'",
01362                                                    n1, n2, n3, n4);
01363                     }
01364                     break;
01365                 case '2': function_name = "`RTTI Base Class Array'"; break;
01366                 case '3': function_name = "`RTTI Class Hierarchy Descriptor'"; break;
01367                 case '4': function_name = "`RTTI Complete Object Locator'"; break;
01368                 default:
01369                     ERR("Unknown RTTI operator: _R%c\n", *sym->current);
01370                     break;
01371                 }
01372                 break;
01373             case 'S': function_name = "`local vftable'"; break;
01374             case 'T': function_name = "`local vftable constructor closure'"; break;
01375             case 'U': function_name = "operator new[]"; break;
01376             case 'V': function_name = "operator delete[]"; break;
01377             case 'X': function_name = "`placement delete closure'"; break;
01378             case 'Y': function_name = "`placement delete[] closure'"; break;
01379             default:
01380                 ERR("Unknown operator: _%c\n", *sym->current);
01381                 return FALSE;
01382             }
01383             break;
01384         default:
01385             /* FIXME: Other operators */
01386             ERR("Unknown operator: %c\n", *sym->current);
01387             return FALSE;
01388         }
01389         sym->current++;
01390         switch (do_after)
01391         {
01392         case 1: case 2:
01393             if (!str_array_push(sym, dashed_null, -1, &sym->stack))
01394                 return FALSE;
01395             break;
01396         case 4:
01397             sym->result = (char*)function_name;
01398             ret = TRUE;
01399             goto done;
01400         case 6:
01401             {
01402                 char *args;
01403                 struct array array_pmt;
01404 
01405                 str_array_init(&array_pmt);
01406                 args = get_args(sym, &array_pmt, FALSE, '<', '>');
01407                 if (args != NULL) function_name = str_printf(sym, "%s%s", function_name, args);
01408                 sym->names.num = 0;
01409             }
01410             /* fall through */
01411         default:
01412             if (!str_array_push(sym, function_name, -1, &sym->stack))
01413                 return FALSE;
01414             break;
01415         }
01416     }
01417     else if (*sym->current == '$')
01418     {
01419         /* Strange construct, it's a name with a template argument list
01420            and that's all. */
01421         sym->current++;
01422         ret = (sym->result = get_template_name(sym)) != NULL;
01423         goto done;
01424     }
01425     else if (*sym->current == '?' && sym->current[1] == '$')
01426         do_after = 5;
01427 
01428     /* Either a class name, or '@' if the symbol is not a class member */
01429     switch (*sym->current)
01430     {
01431     case '@': sym->current++; break;
01432     case '$': break;
01433     default:
01434         /* Class the function is associated with, terminated by '@@' */
01435         if (!get_class(sym)) goto done;
01436         break;
01437     }
01438 
01439     switch (do_after)
01440     {
01441     case 0: default: break;
01442     case 1: case 2:
01443         /* it's time to set the member name for ctor & dtor */
01444         if (sym->stack.num <= 1) goto done;
01445         if (do_after == 1)
01446             sym->stack.elts[0] = sym->stack.elts[1];
01447         else
01448             sym->stack.elts[0] = str_printf(sym, "~%s", sym->stack.elts[1]);
01449         /* ctors and dtors don't have return type */
01450         sym->flags |= UNDNAME_NO_FUNCTION_RETURNS;
01451         break;
01452     case 3:
01453         sym->flags &= ~UNDNAME_NO_FUNCTION_RETURNS;
01454         break;
01455     case 5:
01456         sym->names.start++;
01457         break;
01458     }
01459 
01460     /* Function/Data type and access level */
01461     if (*sym->current >= '0' && *sym->current <= '9')
01462         ret = handle_data(sym);
01463     else if (*sym->current >= 'A' && *sym->current <= 'Z')
01464         ret = handle_method(sym, do_after == 3);
01465     else if (*sym->current == '$')
01466         ret = handle_template(sym);
01467     else ret = FALSE;
01468 done:
01469     if (ret) assert(sym->result);
01470     else WARN("Failed at %s\n", sym->current);
01471 
01472     return ret;
01473 }
01474 
01475 /*********************************************************************
01476  *      __unDNameEx (MSVCRT.@)
01477  *
01478  * Demangle a C++ identifier.
01479  *
01480  * PARAMS
01481  *  buffer   [O] If not NULL, the place to put the demangled string
01482  *  mangled  [I] Mangled name of the function
01483  *  buflen   [I] Length of buffer
01484  *  memget   [I] Function to allocate memory with
01485  *  memfree  [I] Function to free memory with
01486  *  unknown  [?] Unknown, possibly a call back
01487  *  flags    [I] Flags determining demangled format
01488  *
01489  * RETURNS
01490  *  Success: A string pointing to the unmangled name, allocated with memget.
01491  *  Failure: NULL.
01492  */
01493 char* CDECL __unDNameEx(char* buffer, const char* mangled, int buflen,
01494                         malloc_func_t memget, free_func_t memfree,
01495                         void* unknown, unsigned short int flags)
01496 {
01497     struct parsed_symbol        sym;
01498     const char*                 result;
01499 
01500     TRACE("(%p,%s,%d,%p,%p,%p,%x)\n",
01501           buffer, mangled, buflen, memget, memfree, unknown, flags);
01502 
01503     /* The flags details is not documented by MS. However, it looks exactly
01504      * like the UNDNAME_ manifest constants from imagehlp.h and dbghelp.h
01505      * So, we copied those (on top of the file)
01506      */
01507     memset(&sym, 0, sizeof(struct parsed_symbol));
01508     if (flags & UNDNAME_NAME_ONLY)
01509         flags |= UNDNAME_NO_FUNCTION_RETURNS | UNDNAME_NO_ACCESS_SPECIFIERS |
01510             UNDNAME_NO_MEMBER_TYPE | UNDNAME_NO_ALLOCATION_LANGUAGE |
01511             UNDNAME_NO_COMPLEX_TYPE;
01512 
01513     sym.flags         = flags;
01514     sym.mem_alloc_ptr = memget;
01515     sym.mem_free_ptr  = memfree;
01516     sym.current       = mangled;
01517     str_array_init( &sym.names );
01518     str_array_init( &sym.stack );
01519 
01520     result = symbol_demangle(&sym) ? sym.result : mangled;
01521     if (buffer && buflen)
01522     {
01523         lstrcpynA( buffer, result, buflen);
01524     }
01525     else
01526     {
01527         buffer = memget(strlen(result) + 1);
01528         if (buffer) strcpy(buffer, result);
01529     }
01530 
01531     und_free_all(&sym);
01532 
01533     return buffer;
01534 }
01535 
01536 
01537 /*********************************************************************
01538  *      __unDName (MSVCRT.@)
01539  */
01540 char* CDECL __unDName(char* buffer, const char* mangled, int buflen,
01541                       malloc_func_t memget, free_func_t memfree,
01542                       unsigned short int flags)
01543 {
01544     return __unDNameEx(buffer, mangled, buflen, memget, memfree, NULL, flags);
01545 }

Generated on Sat May 26 2012 04:35:37 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.