📄 undname.c
字号:
return ret;
}
/******************************************************************
* get_class
* Parses class as a list of parent-classes, separated by '@', terminated by '@@'
* and stores the result in 'a' array. Each parent-classes, as well as the inner
* element (either field/method name or class name), are stored as allocated
* strings in the array.
*/
static BOOL get_class(struct parsed_symbol* sym)
{
const char* ptr;
while (*sym->current != '@')
{
switch (*sym->current)
{
case '\0': return FALSE;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
ptr = str_array_get_ref(&sym->stack, *sym->current++ - '0');
if (!ptr) return FALSE;
str_array_push(sym, ptr, -1, &sym->stack);
break;
case '?':
if (*++sym->current == '$')
{
const char* name = ++sym->current;
char* full = NULL;
char* args = NULL;
unsigned num_mark = sym->stack.num;
unsigned start_mark = sym->stack.start;
while (*sym->current++ != '@');
sym->stack.start = sym->stack.num;
str_array_push(sym, name, sym->current - name -1, &sym->stack);
args = get_args(sym, NULL, FALSE, '<', '>');
if (args != NULL)
{
full = str_printf(sym, "%s%s", sym->stack.elts[num_mark], args);
}
if (!full) return FALSE;
sym->stack.elts[num_mark] = full;
sym->stack.num = num_mark + 1;
sym->stack.start = start_mark;
}
break;
default:
ptr = sym->current;
while (*sym->current++ != '@');
str_array_push(sym, ptr, sym->current - 1 - ptr, &sym->stack);
break;
}
}
sym->current++;
return TRUE;
}
/******************************************************************
* get_class_string
* From an array collected by get_class, constructs the corresponding (allocated)
* string
*/
static char* get_class_string(struct parsed_symbol* sym, /*const struct array* a, */int start)
{
int i;
size_t len, sz;
char* ret;
struct array *a = &sym->stack;
for (len = 0, i = start; i < a->num; i++)
{
assert(a->elts[i]);
len += 2 + strlen(a->elts[i]);
}
if (!(ret = und_alloc(sym, len - 1))) return NULL;
for (len = 0, i = a->num - 1; i >= start; i--)
{
sz = strlen(a->elts[i]);
memcpy(ret + len, a->elts[i], sz);
len += sz;
if (i > start)
{
ret[len++] = ':';
ret[len++] = ':';
}
}
ret[len] = '\0';
return ret;
}
/******************************************************************
* get_calling_convention
* Returns a static string corresponding to the calling convention described
* by char 'ch'. Sets export to TRUE iff the calling convention is exported.
*/
static BOOL get_calling_convention(struct parsed_symbol* sym, char ch,
const char** call_conv, const char** exported,
unsigned flags)
{
*call_conv = *exported = NULL;
if (!(flags & (UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ALLOCATION_LANGUAGE)))
{
if (flags & UNDNAME_NO_LEADING_UNDERSCORES)
{
if (((ch - 'A') % 2) == 1) *exported = "dll_export ";
switch (ch)
{
case 'A': case 'B': *call_conv = "cdecl"; break;
case 'C': case 'D': *call_conv = "pascal"; break;
case 'E': case 'F': *call_conv = "thiscall"; break;
case 'G': case 'H': *call_conv = "stdcall"; break;
case 'I': case 'J': *call_conv = "fastcall"; break;
case 'K': break;
default: ERR("Unknown calling convention %c\n", ch); return FALSE;
}
}
else
{
if (((ch - 'A') % 2) == 1) *exported = "__dll_export ";
switch (ch)
{
case 'A': case 'B': *call_conv = "__cdecl"; break;
case 'C': case 'D': *call_conv = "__pascal"; break;
case 'E': case 'F': *call_conv = "__thiscall"; break;
case 'G': case 'H': *call_conv = "__stdcall"; break;
case 'I': case 'J': *call_conv = "__fastcall"; break;
case 'K': break;
default: ERR("Unknown calling convention %c\n", ch); return FALSE;
}
}
}
return TRUE;
}
/*******************************************************************
* get_simple_type
* Return a string containing an allocated string for a simple data type
*/
static const char* get_simple_type(struct parsed_symbol* sym, char c)
{
const char* type_string;
switch (c)
{
case 'C': type_string = "signed char"; break;
case 'D': type_string = "char"; break;
case 'E': type_string = "unsigned char"; break;
case 'F': type_string = "short"; break;
case 'G': type_string = "unsigned short"; break;
case 'H': type_string = "int"; break;
case 'I': type_string = "unsigned int"; break;
case 'J': type_string = "long"; break;
case 'K': type_string = "unsigned long"; break;
case 'M': type_string = "float"; break;
case 'N': type_string = "double"; break;
case 'O': type_string = "long double"; break;
case 'X': type_string = "void"; break;
case 'Z': type_string = "..."; break;
default: type_string = NULL; break;
}
return type_string;
}
/*******************************************************************
* get_extented_type
* Return a string containing an allocated string for a simple data type
*/
static const char* get_extended_type(struct parsed_symbol* sym, char c)
{
const char* type_string;
switch (c)
{
case 'D': type_string = "__int8"; break;
case 'E': type_string = "unsigned __int8"; break;
case 'F': type_string = "__int16"; break;
case 'G': type_string = "unsigned __int16"; break;
case 'H': type_string = "__int32"; break;
case 'I': type_string = "unsigned __int32"; break;
case 'J': type_string = "__int64"; break;
case 'K': type_string = "unsigned __int64"; break;
case 'L': type_string = "__int128"; break;
case 'M': type_string = "unsigned __int128"; break;
case 'N': type_string = "bool"; break;
case 'W': type_string = "wchar_t"; break;
default: type_string = NULL; break;
}
return type_string;
}
/*******************************************************************
* demangle_datatype
*
* Attempt to demangle a C++ data type, which may be datatype.
* a datatype type is made up of a number of simple types. e.g:
* char** = (pointer to (pointer to (char)))
*/
static BOOL demangle_datatype(struct parsed_symbol* sym, struct datatype_t* ct,
struct array* pmt_ref, BOOL in_args)
{
char dt;
BOOL add_pmt = TRUE;
assert(ct);
ct->left = ct->right = NULL;
switch (dt = *sym->current++)
{
case '_':
/* MS type: __int8,__int16 etc */
ct->left = get_extended_type(sym, *sym->current++);
break;
case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'M':
case 'N': case 'O': case 'X': case 'Z':
/* Simple data types */
ct->left = get_simple_type(sym, dt);
add_pmt = FALSE;
break;
case 'T': /* union */
case 'U': /* struct */
case 'V': /* class */
/* Class/struct/union */
{
unsigned mark = sym->stack.num;
const char* struct_name = NULL;
const char* type_name = NULL;
if (!get_class(sym) ||
!(struct_name = get_class_string(sym, mark))) goto done;
sym->stack.num = mark;
if (!(sym->flags & UNDNAME_NO_COMPLEX_TYPE))
{
switch (dt)
{
case 'T': type_name = "union "; break;
case 'U': type_name = "struct "; break;
case 'V': type_name = "class "; break;
}
}
ct->left = str_printf(sym, "%s%s", type_name, struct_name);
}
break;
case '?':
/* not all the time is seems */
if (!(ct->left = get_modified_type(sym, '?'))) goto done;
break;
case 'A':
if (!(ct->left = get_modified_type(sym, 'A'))) goto done;
break;
case 'Q':
if (!(ct->left = get_modified_type(sym, in_args ? 'Q' : 'P'))) goto done;
break;
case 'P': /* Pointer */
if (isdigit(*sym->current))
{
/* FIXME: P6 = Function pointer, others who knows.. */
if (*sym->current++ == '6')
{
char* args = NULL;
const char* call_conv;
const char* exported;
struct datatype_t sub_ct;
unsigned mark = sym->stack.num;
if (!get_calling_convention(sym, *sym->current++,
&call_conv, &exported,
sym->flags & ~UNDNAME_NO_ALLOCATION_LANGUAGE) ||
!demangle_datatype(sym, &sub_ct, pmt_ref, FALSE))
goto done;
args = get_args(sym, pmt_ref, TRUE, '(', ')');
if (!args) goto done;
sym->stack.num = mark;
ct->left = str_printf(sym, "%s%s (%s*",
sub_ct.left, sub_ct.right, call_conv);
ct->right = str_printf(sym, ")%s", args);
}
else goto done;
}
else if (!(ct->left = get_modified_type(sym, 'P'))) goto done;
break;
case 'W':
if (*sym->current == '4')
{
char* enum_name;
unsigned mark = sym->stack.num;
sym->current++;
if (!get_class(sym) ||
!(enum_name = get_class_string(sym, mark))) goto done;
sym->stack.num = mark;
if (sym->flags & UNDNAME_NO_COMPLEX_TYPE)
ct->left = enum_name;
else
ct->left = str_printf(sym, "enum %s", enum_name);
}
else goto done;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/* Referring back to previously parsed type */
ct->left = str_array_get_ref(pmt_ref, dt - '0');
if (!ct->left) goto done;
add_pmt = FALSE;
break;
case '$':
if (sym->current[0] != '0') goto done;
if (sym->current[1] >= '0' && sym->current[1] <= '9')
{
char* ptr;
ptr = und_alloc(sym, 2);
ptr[0] = sym->current[1] + 1;
ptr[1] = 0;
ct->left = ptr;
sym->current += 2;
}
else if ((sym->current[1] >= 'A' && sym->current[1] <= 'P') &&
sym->current[2] == '@')
{
char* ptr;
ptr = und_alloc(sym, 3);
if (sym->current[1] <= 'J')
{
ptr[0] = '0' + sym->current[1] - 'A';
ptr[1] = 0;
}
else
{
ptr[0] = '1';
ptr[1] = sym->current[1] - 'K' + '0';
ptr[2] = 0;
}
ct->left = ptr;
sym->current += 3;
}
else goto done;
break;
default :
ERR("Unknown type %c\n", dt);
break;
}
if (add_pmt && pmt_ref && in_args)
str_array_push(sym, str_printf(sym, "%s%s", ct->left, ct->right),
-1, pmt_ref);
done:
return ct->left != NULL;
}
/******************************************************************
* handle_data
* Does the final parsing and handling for a variable or a field in
* a class.
*/
static BOOL handle_data(struct parsed_symbol* sym)
{
const char* access = NULL;
const char* member_type = NULL;
const char* modifier = NULL;
struct datatype_t ct;
char* name = NULL;
BOOL ret = FALSE;
char dt;
/* 0 private static
* 1 protected static
* 2 public static
* 3 private non-static
* 4 protected non-static
* 5 public non-static
* 6 ?? static
* 7 ?? static
*/
if (!(sym->flags & UNDNAME_NO_ACCESS_SPECIFIERS))
{
/* we only print the access for static members */
switch (*sym->current)
{
case '0': access = "private: "; break;
case '1': access = "protected: "; break;
case '2': access = "public: "; break;
}
}
if (!(sym->flags & UNDNAME_NO_MEMBER_TYPE))
{
if (*sym->current >= '0' && *sym->current <= '2')
member_type = "static ";
}
name = get_class_string(sym, 0);
switch (dt = *sym->current++)
{
case '0': case '1': case '2':
case '3': case '4': case '5':
{
unsigned mark = sym->stack.num;
if (!demangle_datatype(sym, &ct, NULL, FALSE)) goto done;
if (!get_modifier(*sym->current++, &modifier)) goto done;
sym->stack.num = mark;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -