- Create entries for ordinal only exports, use ordinals if non-standard.
- Improve C++ demangler, recognise data types, fix some bugs.
This commit is contained in:
parent
d52e1c4be9
commit
dd2247817e
|
@ -148,7 +148,7 @@ specmaker -d zipextra (Note: this assumes specmaker is in your path)
|
|||
|
||||
The output will look something like the following:
|
||||
|
||||
22 exported symbols in DLL ...
|
||||
22 named symbols in DLL, 22 in total ...
|
||||
Export 1 - '_OpenZipFile' ... [Ignoring]
|
||||
Export 2 - '_UnZipFile' ... [Ignoring]
|
||||
...
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#define SECTION_ADDR_OFFSET 12
|
||||
#define SECTION_ADDR_SIZE SECTION_ADDR_OFFSET + 4
|
||||
#define SECTION_POS_OFFSET SECTION_ADDR_SIZE + 4
|
||||
#define ORDINAL_BASE_OFFSET 16
|
||||
#define ORDINAL_COUNT_OFFSET 20
|
||||
#define ORDINAL_NAME_OFFSET ORDINAL_COUNT_OFFSET + 16
|
||||
#define EXPORT_COUNT_OFFSET 24
|
||||
#define EXPORT_NAME_OFFSET EXPORT_COUNT_OFFSET + 8
|
||||
|
||||
|
@ -28,10 +31,19 @@
|
|||
#define REBASE(x) ((x) - exports)
|
||||
|
||||
/* Module globals */
|
||||
static FILE *dll_file = NULL;
|
||||
static char **dll_symbols = NULL;
|
||||
static size_t dll_num_exports = 0;
|
||||
typedef struct _dll_symbol {
|
||||
size_t ordinal;
|
||||
char *symbol;
|
||||
} dll_symbol;
|
||||
|
||||
static FILE *dll_file = NULL;
|
||||
static dll_symbol *dll_symbols = NULL;
|
||||
static size_t dll_num_exports = 0;
|
||||
static size_t dll_num_ordinals = 0;
|
||||
static int dll_ordinal_base = 0;
|
||||
|
||||
static dll_symbol *dll_current_symbol = NULL;
|
||||
static unsigned int dll_current_export = 0;
|
||||
|
||||
/* Get a short from a memory block */
|
||||
static inline size_t get_short (const char *mem)
|
||||
|
@ -47,6 +59,12 @@ static inline size_t get_int (const char *mem)
|
|||
return get_short (mem) + (get_short (mem + 2) << 16);
|
||||
}
|
||||
|
||||
/* Compare symbols by ordinal for qsort */
|
||||
static int symbol_cmp(const void *left, const void *right)
|
||||
{
|
||||
return ((dll_symbol *)left)->ordinal > ((dll_symbol *)right)->ordinal;
|
||||
}
|
||||
|
||||
static void dll_close (void);
|
||||
|
||||
|
||||
|
@ -58,6 +76,7 @@ static void dll_close (void);
|
|||
void dll_open (const char *dll_name)
|
||||
{
|
||||
size_t code = 0, code_len = 0, exports, exports_len, count, symbol_data;
|
||||
size_t ordinal_data;
|
||||
char *buff = NULL;
|
||||
dll_file = open_file (dll_name, ".dll", "r");
|
||||
|
||||
|
@ -127,37 +146,55 @@ void dll_open (const char *dll_name)
|
|||
|
||||
dll_close();
|
||||
|
||||
/* Locate symbol names */
|
||||
/* Locate symbol names/ordinals */
|
||||
symbol_data = REBASE( get_int (buff + EXPORT_NAME_OFFSET));
|
||||
ordinal_data = REBASE( get_int (buff + ORDINAL_NAME_OFFSET));
|
||||
|
||||
if (symbol_data > code_len)
|
||||
fatal ("Corrupt exports section");
|
||||
|
||||
if (!(dll_num_ordinals = get_int (buff + ORDINAL_COUNT_OFFSET)))
|
||||
fatal ("No ordinal count");
|
||||
|
||||
if (!(dll_num_exports = get_int (buff + EXPORT_COUNT_OFFSET)))
|
||||
fatal ("No export count");
|
||||
|
||||
if (!(dll_symbols = (char **) malloc (dll_num_exports * sizeof (char *))))
|
||||
if (!(dll_symbols = (dll_symbol *) malloc ((dll_num_exports + 1) * sizeof (dll_symbol))))
|
||||
fatal ("Out of memory");
|
||||
|
||||
dll_ordinal_base = get_int (buff + ORDINAL_BASE_OFFSET);
|
||||
|
||||
if (dll_num_exports != dll_num_ordinals || dll_ordinal_base > 1)
|
||||
globals.do_ordinals = 1;
|
||||
|
||||
/* Read symbol names into 'dll_symbols' */
|
||||
count = 0;
|
||||
while (count < dll_num_exports)
|
||||
{
|
||||
const int symbol_offset = get_int (buff + symbol_data + count * 4);
|
||||
const char *symbol_name_ptr = REBASE (buff + symbol_offset);
|
||||
const int ordinal_offset = get_short (buff + ordinal_data + count * 2);
|
||||
|
||||
assert(symbol_name_ptr);
|
||||
dll_symbols[count] = strdup (symbol_name_ptr);
|
||||
assert(dll_symbols[count]);
|
||||
dll_symbols[count].symbol = strdup (symbol_name_ptr);
|
||||
assert(dll_symbols[count].symbol);
|
||||
dll_symbols[count].ordinal = ordinal_offset + dll_ordinal_base;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (NORMAL)
|
||||
printf ("%d exported symbols in DLL\n", dll_num_exports);
|
||||
printf ("%d named symbols in DLL, %d total\n", dll_num_exports, dll_num_ordinals);
|
||||
|
||||
free (buff);
|
||||
|
||||
qsort( dll_symbols, dll_num_exports, sizeof(dll_symbol), symbol_cmp );
|
||||
|
||||
dll_symbols[dll_num_exports].symbol = NULL;
|
||||
|
||||
dll_current_symbol = dll_symbols;
|
||||
dll_current_export = dll_ordinal_base;
|
||||
|
||||
/* Set DLL output names */
|
||||
if ((buff = strrchr (globals.input_name, '/')))
|
||||
globals.input_name = buff + 1; /* Strip path */
|
||||
|
@ -171,19 +208,33 @@ void dll_open (const char *dll_name)
|
|||
*
|
||||
* Get next exported symbol from dll
|
||||
*/
|
||||
char* dll_next_symbol ()
|
||||
int dll_next_symbol (parsed_symbol * sym)
|
||||
{
|
||||
static unsigned int current_export = 0;
|
||||
|
||||
assert (current_export <= dll_num_exports);
|
||||
|
||||
if (current_export == dll_num_exports)
|
||||
return NULL;
|
||||
char ordinal_text[256];
|
||||
if (dll_current_export > dll_num_ordinals)
|
||||
return 1;
|
||||
|
||||
assert (dll_symbols);
|
||||
assert (dll_symbols [current_export]);
|
||||
|
||||
return strdup (dll_symbols [current_export++]);
|
||||
if (!dll_current_symbol->symbol || dll_current_export < dll_current_symbol->ordinal)
|
||||
{
|
||||
assert(globals.do_ordinals);
|
||||
|
||||
/* Ordinal only entry */
|
||||
snprintf (ordinal_text, sizeof(ordinal_text), "%s_%d",
|
||||
globals.forward_dll ? globals.forward_dll : OUTPUT_UC_DLL_NAME,
|
||||
dll_current_export);
|
||||
str_toupper(ordinal_text);
|
||||
sym->symbol = strdup (ordinal_text);
|
||||
}
|
||||
else
|
||||
{
|
||||
sym->symbol = strdup (dll_current_symbol->symbol);
|
||||
dll_current_symbol++;
|
||||
}
|
||||
sym->ordinal = dll_current_export;
|
||||
dll_current_export++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -205,8 +256,8 @@ static void dll_close (void)
|
|||
if (dll_symbols)
|
||||
{
|
||||
for (i = 0; i < dll_num_exports; i++)
|
||||
if (dll_symbols [i])
|
||||
free (dll_symbols [i]);
|
||||
if (dll_symbols [i].symbol)
|
||||
free (dll_symbols [i].symbol);
|
||||
free (dll_symbols);
|
||||
dll_symbols = NULL;
|
||||
}
|
||||
|
|
|
@ -220,9 +220,13 @@ int main (int argc, char *argv[])
|
|||
{
|
||||
int result;
|
||||
globals.uc_dll_name = "";
|
||||
VERBOSE = 1;
|
||||
symbol.symbol = strdup(globals.input_name);
|
||||
result = symbol_demangle (&symbol);
|
||||
output_prototype (stdout, &symbol);
|
||||
if (symbol.flags & SYM_DATA)
|
||||
printf (symbol.arg_text[0]);
|
||||
else
|
||||
output_prototype (stdout, &symbol);
|
||||
fputc ('\n', stdout);
|
||||
return result ? 1 : 0;
|
||||
}
|
||||
|
@ -233,7 +237,7 @@ int main (int argc, char *argv[])
|
|||
output_header_preamble ();
|
||||
output_c_preamble ();
|
||||
|
||||
while ((symbol.symbol = dll_next_symbol ()))
|
||||
while (!dll_next_symbol (&symbol))
|
||||
{
|
||||
count++;
|
||||
|
||||
|
@ -250,7 +254,7 @@ int main (int argc, char *argv[])
|
|||
if (result)
|
||||
result = symbol_search (&symbol);
|
||||
|
||||
if (!result)
|
||||
if (!result && symbol.function_name)
|
||||
/* Clean up the prototype */
|
||||
symbol_clean_string (symbol.function_name);
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ typedef struct _compound_type
|
|||
/* free the memory used by a compound structure */
|
||||
#define FREE_CT(ct) do { if (ct.expression) free (ct.expression); } while (0)
|
||||
|
||||
/* Flags for data types */
|
||||
#define DATA_VTABLE 0x1
|
||||
|
||||
/* Internal functions */
|
||||
static char *demangle_datatype (char **str, compound_type *ct,
|
||||
|
@ -49,8 +51,9 @@ int symbol_demangle (parsed_symbol *sym)
|
|||
int is_static = 0, is_const = 0;
|
||||
char *function_name = NULL;
|
||||
char *class_name = NULL;
|
||||
char *name;
|
||||
char *name, *const_status;
|
||||
static unsigned int hash = 0; /* In case of overloaded functions */
|
||||
unsigned int data_flags = 0;
|
||||
|
||||
assert (globals.do_code);
|
||||
assert (sym && sym->symbol);
|
||||
|
@ -96,6 +99,7 @@ int symbol_demangle (parsed_symbol *sym)
|
|||
case 'N': function_name = strdup ("operator_lessthanequal"); break;
|
||||
case 'O': function_name = strdup ("operator_greaterthan"); break;
|
||||
case 'P': function_name = strdup ("operator_greaterthanequal"); break;
|
||||
case 'Q': function_name = strdup ("operator_comma"); break;
|
||||
case 'R': function_name = strdup ("operator_functioncall"); break;
|
||||
case 'S': function_name = strdup ("operator_compliment"); break;
|
||||
case 'T': function_name = strdup ("operator_xor"); break;
|
||||
|
@ -115,9 +119,28 @@ int symbol_demangle (parsed_symbol *sym)
|
|||
case '4': function_name = strdup ("operator_andequals"); break;
|
||||
case '5': function_name = strdup ("operator_orequals"); break;
|
||||
case '6': function_name = strdup ("operator_xorequals"); break;
|
||||
/* FIXME: These look like static vtable/rtti information ? */
|
||||
case 'E': function_name = strdup ("_unknown_E"); break;
|
||||
case 'G': function_name = strdup ("_unknown_G"); break;
|
||||
case '7': function_name = strdup ("vftable"); data_flags = DATA_VTABLE; break;
|
||||
case '8': function_name = strdup ("vbtable"); data_flags = DATA_VTABLE; break;
|
||||
case '9': function_name = strdup ("vcall"); data_flags = DATA_VTABLE; break;
|
||||
case 'A': function_name = strdup ("typeof"); data_flags = DATA_VTABLE; break;
|
||||
case 'B': function_name = strdup ("local_static_guard"); data_flags = DATA_VTABLE; break;
|
||||
case 'C': function_name = strdup ("string"); data_flags = DATA_VTABLE; break;
|
||||
case 'D': function_name = strdup ("vbase_dtor"); data_flags = DATA_VTABLE; break;
|
||||
case 'E': function_name = strdup ("vector_dtor"); break;
|
||||
case 'G': function_name = strdup ("scalar_dtor"); break;
|
||||
case 'H': function_name = strdup ("vector_ctor_iter"); break;
|
||||
case 'I': function_name = strdup ("vector_dtor_iter"); break;
|
||||
case 'J': function_name = strdup ("vector_vbase_ctor_iter"); break;
|
||||
case 'L': function_name = strdup ("eh_vector_ctor_iter"); break;
|
||||
case 'M': function_name = strdup ("eh_vector_dtor_iter"); break;
|
||||
case 'N': function_name = strdup ("eh_vector_vbase_ctor_iter"); break;
|
||||
case 'O': function_name = strdup ("copy_ctor_closure"); break;
|
||||
case 'S': function_name = strdup ("local_vftable"); data_flags = DATA_VTABLE; break;
|
||||
case 'T': function_name = strdup ("local_vftable_ctor_closure"); break;
|
||||
case 'U': function_name = strdup ("operator_new_vector"); break;
|
||||
case 'V': function_name = strdup ("operator_delete_vector"); break;
|
||||
case 'X': function_name = strdup ("placement_new_closure"); break;
|
||||
case 'Y': function_name = strdup ("placement_delete_closure"); break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -154,22 +177,72 @@ int symbol_demangle (parsed_symbol *sym)
|
|||
class_name = str_substring (class_name, name - 2);
|
||||
}
|
||||
|
||||
/* Note: This is guesswork on my part, but it seems to work:
|
||||
* 'Q' Means the function is passed an implicit 'this' pointer.
|
||||
* 'S' Means static member function, i.e. no implicit 'this' pointer.
|
||||
* 'Y' Is used for datatypes and functions, so there is no 'this' pointer.
|
||||
* This character also implies some other things:
|
||||
* 'Y','S' = The character after the calling convention is always the
|
||||
* start of the return type code.
|
||||
* 'Q' Character after the calling convention is 'const'ness code
|
||||
* (only non static member functions can be const).
|
||||
* 'U' also occurs, it seems to behave like Q, but probably implies
|
||||
* something else.
|
||||
*/
|
||||
/* Function/Data type and access level */
|
||||
/* FIXME: why 2 possible letters for each option? */
|
||||
switch(*name++)
|
||||
{
|
||||
case 'U' :
|
||||
case 'Q' :
|
||||
/* Data */
|
||||
|
||||
case '0' : /* private static */
|
||||
case '1' : /* protected static */
|
||||
case '2' : /* public static */
|
||||
is_static = 1;
|
||||
/* Fall through */
|
||||
case '3' : /* non static */
|
||||
case '4' : /* non static */
|
||||
/* Data members need to be implemented: report */
|
||||
INIT_CT (ct);
|
||||
if (!demangle_datatype (&name, &ct, sym))
|
||||
{
|
||||
if (VERBOSE)
|
||||
printf ("/*FIXME: %s: unknown data*/\n", sym->symbol);
|
||||
return -1;
|
||||
}
|
||||
sym->flags |= SYM_DATA;
|
||||
sym->argc = 1;
|
||||
sym->arg_name[0] = str_create (5, OUTPUT_UC_DLL_NAME, "_", class_name,
|
||||
is_static ? "static_" : "_", function_name);
|
||||
sym->arg_text[0] = str_create (3, ct.expression, " ", sym->arg_name[0]);
|
||||
FREE_CT (ct);
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case '6' : /* compiler generated static */
|
||||
case '7' : /* compiler generated static */
|
||||
if (data_flags & DATA_VTABLE)
|
||||
{
|
||||
sym->flags |= SYM_DATA;
|
||||
sym->argc = 1;
|
||||
sym->arg_name[0] = str_create (5, OUTPUT_UC_DLL_NAME, "_", class_name,
|
||||
"_", function_name);
|
||||
sym->arg_text[0] = str_create (2, "void *", sym->arg_name[0]);
|
||||
|
||||
if (VERBOSE)
|
||||
puts ("Demangled symbol OK [vtable]");
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
break;
|
||||
|
||||
/* Functions */
|
||||
|
||||
case 'E' : /* private virtual */
|
||||
case 'F' : /* private virtual */
|
||||
case 'M' : /* protected virtual */
|
||||
case 'N' : /* protected virtual */
|
||||
case 'U' : /* public virtual */
|
||||
case 'V' : /* public virtual */
|
||||
/* Virtual functions need to be added to the exported vtable: report */
|
||||
if (VERBOSE)
|
||||
printf ("/*FIXME %s: %s::%s is virtual-add to vftable*/\n", sym->symbol,
|
||||
class_name, function_name);
|
||||
/* Fall through */
|
||||
case 'A' : /* private */
|
||||
case 'B' : /* private */
|
||||
case 'I' : /* protected */
|
||||
case 'J' : /* protected */
|
||||
case 'Q' : /* public */
|
||||
case 'R' : /* public */
|
||||
/* Implicit 'this' pointer */
|
||||
sym->arg_text [sym->argc] = str_create (3, "struct ", class_name, " *");
|
||||
sym->arg_type [sym->argc] = ARG_POINTER;
|
||||
|
@ -177,42 +250,67 @@ int symbol_demangle (parsed_symbol *sym)
|
|||
sym->arg_name [sym->argc++] = strdup ("_this");
|
||||
/* New struct definitions can be 'grep'ed out for making a fixup header */
|
||||
if (VERBOSE)
|
||||
printf ("struct %s { int _FIXME; };\n", class_name);
|
||||
printf ("struct %s { void **vtable; /*FIXME: class definition */ };\n", class_name);
|
||||
break;
|
||||
case 'S' :
|
||||
is_static = 1;
|
||||
case 'C' : /* private: static */
|
||||
case 'D' : /* private: static */
|
||||
case 'K' : /* protected: static */
|
||||
case 'L' : /* protected: static */
|
||||
case 'S' : /* public: static */
|
||||
case 'T' : /* public: static */
|
||||
is_static = 1; /* No implicit this pointer */
|
||||
break;
|
||||
case 'Y' :
|
||||
case 'Z' :
|
||||
break;
|
||||
/* FIXME: G,H / O,P / W,X are private / protected / public thunks */
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If there is an implicit this pointer, const status follows */
|
||||
if (sym->argc)
|
||||
{
|
||||
switch (*name++)
|
||||
{
|
||||
case 'A': break; /* non-const */
|
||||
case 'B': is_const = CT_CONST; break;
|
||||
case 'C': is_const = CT_VOLATILE; break;
|
||||
case 'D': is_const = (CT_CONST | CT_VOLATILE); break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next is the calling convention */
|
||||
switch (*name++)
|
||||
{
|
||||
case 'A':
|
||||
sym->calling_convention = strdup ("__cdecl");
|
||||
break;
|
||||
case 'B': /* FIXME: Something to do with __declspec(dllexport)? */
|
||||
case 'A': /* __cdecl */
|
||||
case 'B': /* __cdecl __declspec(dllexport) */
|
||||
if (!sym->argc)
|
||||
{
|
||||
sym->flags |= SYM_CDECL;
|
||||
break;
|
||||
}
|
||||
/* Else fall through */
|
||||
case 'C': /* __pascal */
|
||||
case 'D': /* __pascal __declspec(dllexport) */
|
||||
case 'E': /* __thiscall */
|
||||
case 'F': /* __thiscall __declspec(dllexport) */
|
||||
case 'G': /* __stdcall */
|
||||
case 'H': /* __stdcall __declspec(dllexport) */
|
||||
case 'I': /* __fastcall */
|
||||
case 'G':
|
||||
sym->calling_convention = strdup ("__stdcall");
|
||||
case 'J': /* __fastcall __declspec(dllexport)*/
|
||||
case 'K': /* default (none given) */
|
||||
if (sym->argc)
|
||||
sym->flags |= SYM_THISCALL;
|
||||
else
|
||||
sym->flags |= SYM_STDCALL;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If the symbol is associated with a class, its 'const' status follows */
|
||||
if (sym->argc)
|
||||
{
|
||||
if (*name == 'B')
|
||||
is_const = 1;
|
||||
else if (*name != 'E')
|
||||
return -1;
|
||||
name++;
|
||||
}
|
||||
|
||||
/* Return type, or @ if 'void' */
|
||||
if (*name == '@')
|
||||
{
|
||||
|
@ -272,11 +370,18 @@ int symbol_demangle (parsed_symbol *sym)
|
|||
/* Create the function name. Include a unique number because otherwise
|
||||
* overloaded functions could have the same c signature.
|
||||
*/
|
||||
switch (is_const)
|
||||
{
|
||||
case (CT_CONST | CT_VOLATILE): const_status = "_const_volatile"; break;
|
||||
case CT_CONST: const_status = "_const"; break;
|
||||
case CT_VOLATILE: const_status = "_volatile"; break;
|
||||
default: const_status = "_"; break;
|
||||
}
|
||||
sym->function_name = str_create_num (4, hash, class_name, "_",
|
||||
function_name, is_static ? "_static" : is_const ? "_const" : "_");
|
||||
function_name, is_static ? "_static" : const_status);
|
||||
|
||||
assert (sym->return_text);
|
||||
assert (sym->calling_convention);
|
||||
assert (sym->flags);
|
||||
assert (sym->function_name);
|
||||
|
||||
free (class_name);
|
||||
|
@ -312,17 +417,15 @@ static char *demangle_datatype (char **str, compound_type *ct,
|
|||
if (!get_constraints_convention_1 (&iter, ct))
|
||||
return NULL;
|
||||
|
||||
if (*iter == '_')
|
||||
{
|
||||
/* MS type: __int8,__int16 etc */
|
||||
ct->flags |= CT_EXTENDED;
|
||||
iter++;
|
||||
}
|
||||
|
||||
switch (*iter)
|
||||
{
|
||||
case '_':
|
||||
if (*++iter != 'N') /* _N = bool */
|
||||
return NULL;
|
||||
iter++;
|
||||
ct->dest_type = 'I'; /* treat as int */
|
||||
if (!get_constraints_convention_2 (&iter, ct))
|
||||
return NULL;
|
||||
ct->expression = get_type_string (ct->dest_type, ct->flags);
|
||||
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':
|
||||
|
@ -357,10 +460,10 @@ static char *demangle_datatype (char **str, compound_type *ct,
|
|||
ct->flags & CT_VOLATILE ? "volatile " : "", stripped);
|
||||
free (stripped);
|
||||
}
|
||||
else if (*iter == '_')
|
||||
else if (*iter != '@')
|
||||
{
|
||||
/* The name of the class/struct, followed by '@@' */
|
||||
char *struct_name = ++iter;
|
||||
char *struct_name = iter;
|
||||
while (*iter && *iter++ != '@') ;
|
||||
if (*iter++ != '@')
|
||||
return NULL;
|
||||
|
@ -519,26 +622,50 @@ static char *get_type_string (const char c, const int constraints)
|
|||
{
|
||||
char *type_string;
|
||||
|
||||
switch (c)
|
||||
if (constraints & CT_EXTENDED)
|
||||
{
|
||||
case 'C': /* Signed char, fall through */
|
||||
case 'D': type_string = "char"; break;
|
||||
case 'E': type_string = "unsigned char"; break;
|
||||
case 'F': type_string = "short int"; break;
|
||||
case 'G': type_string = "unsigned short int"; 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 'U':
|
||||
case 'V': type_string = "struct"; break;
|
||||
case 'X': return strdup ("void");
|
||||
case 'Z': return strdup ("...");
|
||||
default:
|
||||
return NULL;
|
||||
switch (c)
|
||||
{
|
||||
case 'D': type_string = "__int8"; break;
|
||||
case 'E': type_string = "__uint8"; break;
|
||||
case 'F': type_string = "__int16"; break;
|
||||
case 'G': type_string = "__uint16"; break;
|
||||
case 'H': type_string = "__int32"; break;
|
||||
case 'I': type_string = "__uint32"; break;
|
||||
case 'J': type_string = "__int64"; break;
|
||||
case 'K': type_string = "__uint64"; break;
|
||||
case 'L': type_string = "__int128"; break;
|
||||
case 'M': type_string = "__uint128"; break;
|
||||
case 'N': type_string = "int"; break; /* bool */
|
||||
case 'W': type_string = "WCHAR"; break; /* wchar_t */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'C': /* Signed char, fall through */
|
||||
case 'D': type_string = "char"; break;
|
||||
case 'E': type_string = "unsigned char"; break;
|
||||
case 'F': type_string = "short int"; break;
|
||||
case 'G': type_string = "unsigned short int"; 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;
|
||||
/* FIXME: T = union */
|
||||
case 'U':
|
||||
case 'V': type_string = "struct"; break;
|
||||
case 'X': return strdup ("void");
|
||||
case 'Z': return strdup ("...");
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return str_create (3, constraints & CT_CONST ? "const " :
|
||||
|
|
|
@ -52,34 +52,58 @@ void output_spec_preamble (void)
|
|||
*/
|
||||
void output_spec_symbol (const parsed_symbol *sym)
|
||||
{
|
||||
char ord_spec[16];
|
||||
|
||||
assert (specfile);
|
||||
assert (sym && sym->symbol);
|
||||
|
||||
if (globals.do_ordinals)
|
||||
snprintf(ord_spec, 8, "%d", sym->ordinal);
|
||||
else
|
||||
{
|
||||
ord_spec[0] = '@';
|
||||
ord_spec[1] = '\0';
|
||||
}
|
||||
if (sym->flags & SYM_THISCALL)
|
||||
strcat (ord_spec, " -i386"); /* For binary compatability only */
|
||||
|
||||
if (!globals.do_code || !sym->function_name)
|
||||
{
|
||||
if (sym->flags & SYM_DATA)
|
||||
{
|
||||
if (globals.forward_dll)
|
||||
fprintf (specfile, "%s forward %s %s.%s #", ord_spec, sym->symbol,
|
||||
globals.forward_dll, sym->symbol);
|
||||
|
||||
fprintf (specfile, "%s extern %s %s\n", ord_spec, sym->symbol,
|
||||
sym->arg_name[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (globals.forward_dll)
|
||||
fprintf (specfile, "@ forward %s %s.%s\n", sym->symbol,
|
||||
fprintf (specfile, "%s forward %s %s.%s\n", ord_spec, sym->symbol,
|
||||
globals.forward_dll, sym->symbol);
|
||||
else
|
||||
{
|
||||
if (!symbol_is_valid_c (sym))
|
||||
fputc ('#', specfile);
|
||||
fprintf (specfile, "@ stub %s\n", sym->symbol);
|
||||
}
|
||||
fprintf (specfile, "%s stub %s\n", ord_spec, sym->symbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i = sym->flags & SYM_THISCALL ? 1 : 0;
|
||||
|
||||
fprintf (specfile, "@ %s %s(", sym->varargs ? "varargs" :
|
||||
symbol_is_cdecl (sym) ? "cdecl" : "stdcall", sym->symbol);
|
||||
fprintf (specfile, "%s %s %s(", ord_spec, sym->varargs ? "varargs" :
|
||||
symbol_get_call_convention(sym), sym->symbol);
|
||||
|
||||
for (i = 0; i < sym->argc; i++)
|
||||
for (; i < sym->argc; i++)
|
||||
fprintf (specfile, " %s", symbol_get_spec_type(sym, i));
|
||||
|
||||
if (sym->argc)
|
||||
fputc (' ', specfile);
|
||||
fprintf (specfile, ") %s_%s\n", OUTPUT_UC_DLL_NAME, sym->function_name);
|
||||
fprintf (specfile, ") %s_%s", OUTPUT_UC_DLL_NAME, sym->function_name);
|
||||
|
||||
if (sym->flags & SYM_THISCALL)
|
||||
fputs (" # __thiscall", specfile);
|
||||
|
||||
fputc ('\n',specfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,8 +156,11 @@ void output_header_symbol (const parsed_symbol *sym)
|
|||
if (!globals.do_code)
|
||||
return;
|
||||
|
||||
if (sym->flags & SYM_DATA)
|
||||
return;
|
||||
|
||||
if (!sym->function_name)
|
||||
fprintf (hfile, "/* %s %s_%s(); */\n", CALLING_CONVENTION,
|
||||
fprintf (hfile, "/* __%s %s_%s(); */\n", symbol_get_call_convention(sym),
|
||||
OUTPUT_UC_DLL_NAME, sym->symbol);
|
||||
else
|
||||
{
|
||||
|
@ -183,9 +210,12 @@ void output_c_preamble (void)
|
|||
if (VERBOSE)
|
||||
puts ("Creating a forwarding DLL");
|
||||
|
||||
fputs ("\nHMODULE hDLL=0;\t/* DLL to call */\n\n\n", cfile);
|
||||
fputs ("\nHMODULE hDLL=0;\t/* DLL to call */\n\n", cfile);
|
||||
}
|
||||
|
||||
fputs ("#ifdef __i386__\n#define GET_THIS(t,p) t p;\\\n__asm__ __volatile__"
|
||||
" (\"movl %%ecx, %0\" : \"=m\" (p))\n#endif\n\n\n", cfile);
|
||||
|
||||
fprintf (cfile,
|
||||
"BOOL WINAPI %s_Init(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID "
|
||||
"lpvReserved)\n{\n\tTRACE(\"(0x%%08x, %%ld, %%p)\\n\",hinstDLL,"
|
||||
|
@ -219,6 +249,11 @@ void output_c_preamble (void)
|
|||
}
|
||||
|
||||
|
||||
#define CPP_END if (sym->flags & SYM_THISCALL) \
|
||||
fputs ("#endif\n", cfile); fputs ("\n\n", cfile)
|
||||
#define GET_THIS if (sym->flags & SYM_THISCALL) \
|
||||
fprintf (cfile, "\tGET_THIS(%s,%s);\n", sym->arg_text[0],sym->arg_name[0])
|
||||
|
||||
/*******************************************************************
|
||||
* output_c_symbol
|
||||
*
|
||||
|
@ -226,7 +261,7 @@ void output_c_preamble (void)
|
|||
*/
|
||||
void output_c_symbol (const parsed_symbol *sym)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i, start = sym->flags & SYM_THISCALL ? 1 : 0;
|
||||
int is_void;
|
||||
|
||||
assert (cfile);
|
||||
|
@ -235,14 +270,25 @@ void output_c_symbol (const parsed_symbol *sym)
|
|||
if (!globals.do_code)
|
||||
return;
|
||||
|
||||
if (sym->flags & SYM_DATA)
|
||||
{
|
||||
fprintf (cfile, "/* FIXME: Move to top of file */\n%s;\n\n",
|
||||
sym->arg_text[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sym->flags & SYM_THISCALL)
|
||||
fputs ("#ifdef __i386__\n", cfile);
|
||||
|
||||
output_c_banner(sym);
|
||||
|
||||
if (!sym->function_name)
|
||||
{
|
||||
/* #ifdef'd dummy */
|
||||
fprintf (cfile, "#if 0\n%s %s_%s()\n{\n\t/* %s in .spec */\n}\n#endif\n\n\n",
|
||||
CALLING_CONVENTION, OUTPUT_UC_DLL_NAME, sym->symbol,
|
||||
fprintf (cfile, "#if 0\n__%s %s_%s()\n{\n\t/* %s in .spec */\n}\n#endif\n",
|
||||
symbol_get_call_convention(sym), OUTPUT_UC_DLL_NAME, sym->symbol,
|
||||
globals.forward_dll ? "@forward" : "@stub");
|
||||
CPP_END;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -253,10 +299,12 @@ void output_c_symbol (const parsed_symbol *sym)
|
|||
|
||||
if (!globals.do_trace)
|
||||
{
|
||||
GET_THIS;
|
||||
fputs ("\tFIXME(\":stub\\n\");\n", cfile);
|
||||
if (!is_void)
|
||||
fprintf (cfile, "\treturn (%s) 0;\n", sym->return_text);
|
||||
fputs ("}\n\n\n", cfile);
|
||||
fputs ("}\n", cfile);
|
||||
CPP_END;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -264,18 +312,25 @@ void output_c_symbol (const parsed_symbol *sym)
|
|||
if (globals.forward_dll)
|
||||
{
|
||||
/* Write variables for calling */
|
||||
fprintf (cfile, "\t%s (%s *pFunc)(", sym->return_text,
|
||||
sym->calling_convention);
|
||||
if (sym->varargs)
|
||||
fputs("\tva_list valist;\n", cfile);
|
||||
|
||||
for (i = 0; i < sym->argc; i++)
|
||||
fprintf (cfile, "%s%s", i ? ", " : "", sym->arg_text [i]);
|
||||
fprintf (cfile, "\t%s (__%s *pFunc)(", sym->return_text,
|
||||
symbol_get_call_convention(sym));
|
||||
|
||||
fprintf (cfile, "%s)=(void*)GetProcAddress(hDLL,\"%s\");\n%s",
|
||||
sym->varargs ? ",..." : sym->argc ? "" : "void", sym->symbol,
|
||||
sym->varargs ? "\tva_list valist;\n" : "");
|
||||
for (i = start; i < sym->argc; i++)
|
||||
fprintf (cfile, "%s%s", i > start ? ", " : "", sym->arg_text [i]);
|
||||
|
||||
fprintf (cfile, "%s);\n", sym->varargs ? ",..." : sym->argc == 1 &&
|
||||
sym->flags & SYM_THISCALL ? "" : sym->argc ? "" : "void");
|
||||
|
||||
if (!is_void)
|
||||
fprintf (cfile, "\t%s retVal;\n", sym->return_text);
|
||||
|
||||
GET_THIS;
|
||||
|
||||
fprintf (cfile, "\tpFunc=(void*)GetProcAddress(hDLL,\"%s\");\n",
|
||||
sym->symbol);
|
||||
}
|
||||
|
||||
/* TRACE input arguments */
|
||||
|
@ -301,7 +356,8 @@ void output_c_symbol (const parsed_symbol *sym)
|
|||
{
|
||||
if (!is_void)
|
||||
fprintf (cfile, "\treturn (%s) 0;\n", sym->return_text);
|
||||
fputs ("}\n\n\n", cfile);
|
||||
fputs ("}\n", cfile);
|
||||
CPP_END;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -332,7 +388,8 @@ void output_c_symbol (const parsed_symbol *sym)
|
|||
else
|
||||
fputs (");\n", cfile);
|
||||
|
||||
fputs ("}\n\n\n", cfile);
|
||||
fputs ("}\n", cfile);
|
||||
CPP_END;
|
||||
}
|
||||
|
||||
|
||||
|
@ -436,16 +493,16 @@ void output_install_script (void)
|
|||
*/
|
||||
void output_prototype (FILE *file, const parsed_symbol *sym)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i, start = sym->flags & SYM_THISCALL ? 1 : 0;
|
||||
|
||||
fprintf (file, "%s %s %s_%s(", sym->return_text, sym->calling_convention,
|
||||
fprintf (file, "%s __%s %s_%s(", sym->return_text, symbol_get_call_convention(sym),
|
||||
OUTPUT_UC_DLL_NAME, sym->function_name);
|
||||
|
||||
if (!sym->argc)
|
||||
if (!sym->argc || (sym->argc == 1 && sym->flags & SYM_THISCALL))
|
||||
fputs ("void", file);
|
||||
else
|
||||
for (i = 0; i < sym->argc; i++)
|
||||
fprintf (file, "%s%s %s", i ? ", " : "", sym->arg_text [i],
|
||||
for (i = start; i < sym->argc; i++)
|
||||
fprintf (file, "%s%s %s", i > start ? ", " : "", sym->arg_text [i],
|
||||
sym->arg_name [i]);
|
||||
if (sym->varargs)
|
||||
fputs (", ...", file);
|
||||
|
@ -460,11 +517,20 @@ void output_prototype (FILE *file, const parsed_symbol *sym)
|
|||
*/
|
||||
void output_c_banner (const parsed_symbol *sym)
|
||||
{
|
||||
char ord_spec[16];
|
||||
size_t i;
|
||||
|
||||
if (globals.do_ordinals)
|
||||
snprintf(ord_spec, sizeof (ord_spec), "%d", sym->ordinal);
|
||||
else
|
||||
{
|
||||
ord_spec[0] = '@';
|
||||
ord_spec[1] = '\0';
|
||||
}
|
||||
|
||||
fprintf (cfile, "/*********************************************************"
|
||||
"*********\n *\t\t%s (%s.@)\n *\n", sym->symbol,
|
||||
OUTPUT_UC_DLL_NAME);
|
||||
"*********\n *\t\t%s (%s.%s)\n *\n", sym->symbol,
|
||||
OUTPUT_UC_DLL_NAME, ord_spec);
|
||||
|
||||
if (globals.do_documentation && sym->function_name)
|
||||
{
|
||||
|
@ -478,7 +544,7 @@ void output_c_banner (const parsed_symbol *sym)
|
|||
fprintf (cfile, " * %s [%s]%s\n", sym->arg_name [i],
|
||||
get_in_or_out(sym, i),
|
||||
strcmp (sym->arg_name [i], "_this") ? "" :
|
||||
" Pointer to the class object");
|
||||
" Pointer to the class object (in ECX)");
|
||||
|
||||
if (sym->varargs)
|
||||
fputs (" * ...[I]\n", cfile);
|
||||
|
@ -522,7 +588,7 @@ static const char *get_format_str (int type)
|
|||
/*******************************************************************
|
||||
* get_in_or_out
|
||||
*
|
||||
* Determin if a parameter is In or In/Out
|
||||
* Determine if a parameter is In or In/Out
|
||||
*/
|
||||
static const char *get_in_or_out (const parsed_symbol *sym, size_t arg)
|
||||
{
|
||||
|
|
|
@ -103,7 +103,7 @@ int symbol_search (parsed_symbol *sym)
|
|||
iter[strlen (sym->symbol)] == '('))
|
||||
{
|
||||
if (VERBOSE)
|
||||
puts ("Prototype looks OK, processing");
|
||||
printf ("Prototype '%s' looks OK, processing\n", grep_buff);
|
||||
|
||||
if (!symbol_from_prototype (sym, grep_buff))
|
||||
{
|
||||
|
@ -146,20 +146,30 @@ static int symbol_from_prototype (parsed_symbol *sym, const char *proto)
|
|||
|
||||
if (!found)
|
||||
{
|
||||
char *call;
|
||||
/* Calling Convention */
|
||||
iter = strchr (iter, ' ');
|
||||
if (!iter)
|
||||
return -1;
|
||||
|
||||
sym->calling_convention = str_substring (proto, iter);
|
||||
call = str_substring (proto, iter);
|
||||
|
||||
if (!strcasecmp (call, "cdecl") || !strcasecmp (call, "__cdecl"))
|
||||
sym->flags |= SYM_CDECL;
|
||||
else
|
||||
sym->flags |= SYM_STDCALL;
|
||||
free (call);
|
||||
iter = (char *)str_match (iter, sym->symbol, &found);
|
||||
|
||||
if (!found)
|
||||
return -1;
|
||||
|
||||
if (VERBOSE)
|
||||
printf ("Using %s calling convention\n",
|
||||
sym->flags & SYM_CDECL ? "cdecl" : "stdcall");
|
||||
}
|
||||
else
|
||||
sym->calling_convention = strdup (CALLING_CONVENTION);
|
||||
sym->flags = CALLING_CONVENTION;
|
||||
|
||||
sym->function_name = strdup (sym->symbol);
|
||||
proto = iter;
|
||||
|
|
|
@ -50,17 +50,25 @@
|
|||
#define CT_BY_REFERENCE 0x1
|
||||
#define CT_VOLATILE 0x2
|
||||
#define CT_CONST 0x4
|
||||
#define CT_EXTENDED 0x8
|
||||
|
||||
/* symbol flags */
|
||||
#define SYM_CDECL 0x1
|
||||
#define SYM_STDCALL 0x2
|
||||
#define SYM_THISCALL 0x4
|
||||
#define SYM_DATA 0x8 /* Data, not a function */
|
||||
|
||||
/* Structure holding a parsed symbol */
|
||||
typedef struct __parsed_symbol
|
||||
{
|
||||
char *symbol;
|
||||
int ordinal;
|
||||
char *return_text;
|
||||
char return_type;
|
||||
char *calling_convention;
|
||||
char *function_name;
|
||||
unsigned int varargs;
|
||||
unsigned int argc;
|
||||
unsigned int flags;
|
||||
char arg_type [MAX_FUNCTION_ARGS];
|
||||
char arg_flag [MAX_FUNCTION_ARGS];
|
||||
char *arg_text [MAX_FUNCTION_ARGS];
|
||||
|
@ -87,6 +95,7 @@ typedef struct __globals
|
|||
const char *forward_dll; /* -f */
|
||||
const char *dll_name; /* -o */
|
||||
char *uc_dll_name; /* -o */
|
||||
int do_ordinals;
|
||||
} _globals;
|
||||
|
||||
extern _globals globals;
|
||||
|
@ -102,13 +111,13 @@ extern _globals globals;
|
|||
#define VERBOSE (globals.do_verbose)
|
||||
|
||||
/* Default calling convention */
|
||||
#define CALLING_CONVENTION (globals.do_cdecl ? "__cdecl" : "__stdcall")
|
||||
#define CALLING_CONVENTION (globals.do_cdecl ? SYM_CDECL : SYM_STDCALL)
|
||||
|
||||
|
||||
/* DLL functions */
|
||||
void dll_open (const char *dll_name);
|
||||
|
||||
char *dll_next_symbol (void);
|
||||
int dll_next_symbol (parsed_symbol * sym);
|
||||
|
||||
/* Symbol functions */
|
||||
int symbol_demangle (parsed_symbol *symbol);
|
||||
|
@ -119,7 +128,7 @@ void symbol_clear(parsed_symbol *sym);
|
|||
|
||||
int symbol_is_valid_c(const parsed_symbol *sym);
|
||||
|
||||
int symbol_is_cdecl(const parsed_symbol *sym);
|
||||
const char *symbol_get_call_convention(const parsed_symbol *sym);
|
||||
|
||||
const char *symbol_get_spec_type (const parsed_symbol *sym, size_t arg);
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ static const char *ascii_chars[] =
|
|||
static const char *known_longs[] =
|
||||
{
|
||||
"char", "CHAR", "float", "int", "INT", "short", "SHORT", "long", "LONG",
|
||||
"WCHAR", "BOOL", "bool", "INT16", NULL
|
||||
"WCHAR", "BOOL", "bool", "INT16", "WORD", "DWORD", NULL
|
||||
};
|
||||
|
||||
|
||||
|
@ -90,9 +90,6 @@ void symbol_clear(parsed_symbol *sym)
|
|||
if (sym->return_text)
|
||||
free (sym->return_text);
|
||||
|
||||
if (sym->calling_convention)
|
||||
free (sym->calling_convention);
|
||||
|
||||
if (sym->function_name)
|
||||
free (sym->function_name);
|
||||
|
||||
|
@ -132,21 +129,20 @@ int symbol_is_valid_c(const parsed_symbol *sym)
|
|||
|
||||
|
||||
/*******************************************************************
|
||||
* symbol_is_cdecl
|
||||
* symbol_get_call_convention
|
||||
*
|
||||
* Check if a symbol is cdecl
|
||||
* Return the calling convention of a symbol
|
||||
*/
|
||||
int symbol_is_cdecl(const parsed_symbol *sym)
|
||||
const char *symbol_get_call_convention(const parsed_symbol *sym)
|
||||
{
|
||||
int call = sym->flags ? sym->flags : CALLING_CONVENTION;
|
||||
|
||||
assert (sym);
|
||||
assert (sym->symbol);
|
||||
|
||||
if (sym->calling_convention && (strstr (sym->calling_convention, "cdecl")
|
||||
|| strstr (sym->calling_convention, "CDECL")))
|
||||
return 1;
|
||||
else if (!sym->calling_convention)
|
||||
return globals.do_cdecl;
|
||||
return 0;
|
||||
if (call & SYM_CDECL)
|
||||
return "cdecl";
|
||||
return "stdcall";
|
||||
}
|
||||
|
||||
|
||||
|
@ -184,6 +180,12 @@ int symbol_get_type (const char *string)
|
|||
const char **tab;
|
||||
int ptrs = 0;
|
||||
|
||||
while (*iter && isspace(*iter))
|
||||
iter++;
|
||||
if (*iter == 'P' || *iter == 'H')
|
||||
ptrs++; /* Win32 type pointer */
|
||||
|
||||
iter = string;
|
||||
while (*iter)
|
||||
{
|
||||
if (*iter == '*' || (*iter == 'L' && iter[1] == 'P')
|
||||
|
@ -199,8 +201,8 @@ int symbol_get_type (const char *string)
|
|||
while (*tab++)
|
||||
if (strstr (string, tab[-1]))
|
||||
{
|
||||
if (!ptrs) return ARG_WIDE_STRING;
|
||||
else return ARG_POINTER;
|
||||
if (ptrs < 2) return ARG_WIDE_STRING;
|
||||
else return ARG_POINTER;
|
||||
}
|
||||
tab = wide_chars;
|
||||
while (*tab++)
|
||||
|
@ -213,8 +215,8 @@ int symbol_get_type (const char *string)
|
|||
while (*tab++)
|
||||
if (strstr (string, tab[-1]))
|
||||
{
|
||||
if (!ptrs) return ARG_STRING;
|
||||
else return ARG_POINTER;
|
||||
if (ptrs < 2) return ARG_STRING;
|
||||
else return ARG_POINTER;
|
||||
}
|
||||
tab = ascii_chars;
|
||||
while (*tab++)
|
||||
|
@ -234,7 +236,7 @@ int symbol_get_type (const char *string)
|
|||
if (strstr (string, "double"))
|
||||
return ARG_DOUBLE;
|
||||
|
||||
if (strstr (string, "void"))
|
||||
if (strstr (string, "void") || strstr (string, "VOID"))
|
||||
return ARG_VOID;
|
||||
|
||||
if (strstr (string, "struct") || strstr (string, "union"))
|
||||
|
|
Loading…
Reference in New Issue