Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenundname.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
1.7.6.1
|