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)
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 */
typedef struct _dll_symbol {
size_t ordinal;
char *symbol;
} dll_symbol;
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_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);
fprintf (cfile, "\t%s (__%s *pFunc)(", sym->return_text,
symbol_get_call_convention(sym));
for (i = 0; i < sym->argc; i++)
fprintf (cfile, "%s%s", i ? ", " : "", sym->arg_text [i]);
for (i = start; i < sym->argc; i++)
fprintf (cfile, "%s%s", i > start ? ", " : "", sym->arg_text [i]);
fprintf (cfile, "%s)=(void*)GetProcAddress(hDLL,\"%s\");\n%s",
sym->varargs ? ",..." : sym->argc ? "" : "void", sym->symbol,
sym->varargs ? "\tva_list valist;\n" : "");
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"))
......
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