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);
......
......@@ -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