Commit dd224781 authored by Jon Griffiths's avatar Jon Griffiths Committed by Alexandre Julliard

- Create entries for ordinal only exports, use ordinals if non-standard.

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