From dd2247817ecf89ac3dcfe480927b81d33856c470 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 16 Feb 2001 19:06:05 +0000 Subject: [PATCH] - Create entries for ordinal only exports, use ordinals if non-standard. - Improve C++ demangler, recognise data types, fix some bugs. --- tools/specmaker/README | 2 +- tools/specmaker/dll.c | 85 +++++++++++--- tools/specmaker/main.c | 10 +- tools/specmaker/msmangle.c | 265 ++++++++++++++++++++++++++++++++------------ tools/specmaker/output.c | 136 +++++++++++++++++------ tools/specmaker/search.c | 16 ++- tools/specmaker/specmaker.h | 17 ++- tools/specmaker/symbol.c | 38 ++++--- 8 files changed, 419 insertions(+), 150 deletions(-) diff --git a/tools/specmaker/README b/tools/specmaker/README index 6eb630134d4..7c820cc1a69 100644 --- a/tools/specmaker/README +++ b/tools/specmaker/README @@ -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] ... diff --git a/tools/specmaker/dll.c b/tools/specmaker/dll.c index 52ef299c2ce..840690bd0f9 100644 --- a/tools/specmaker/dll.c +++ b/tools/specmaker/dll.c @@ -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; } diff --git a/tools/specmaker/main.c b/tools/specmaker/main.c index 9afe59bc068..2f9edd2d6d0 100644 --- a/tools/specmaker/main.c +++ b/tools/specmaker/main.c @@ -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); diff --git a/tools/specmaker/msmangle.c b/tools/specmaker/msmangle.c index a418efcd83c..d5f3f6b7bde 100644 --- a/tools/specmaker/msmangle.c +++ b/tools/specmaker/msmangle.c @@ -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 " : diff --git a/tools/specmaker/output.c b/tools/specmaker/output.c index c4cfb9d6ac6..0513cece17b 100644 --- a/tools/specmaker/output.c +++ b/tools/specmaker/output.c @@ -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) { diff --git a/tools/specmaker/search.c b/tools/specmaker/search.c index 289b8721230..1b0cdef33c0 100644 --- a/tools/specmaker/search.c +++ b/tools/specmaker/search.c @@ -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; diff --git a/tools/specmaker/specmaker.h b/tools/specmaker/specmaker.h index 54b2279e586..8d952fc0782 100644 --- a/tools/specmaker/specmaker.h +++ b/tools/specmaker/specmaker.h @@ -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); diff --git a/tools/specmaker/symbol.c b/tools/specmaker/symbol.c index 225312878ca..50d9843786e 100644 --- a/tools/specmaker/symbol.c +++ b/tools/specmaker/symbol.c @@ -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")) -- 2.11.4.GIT