typedef int (*PFNOUTLINE)(FILE *, EXPORT *);
int gbMSComp = 0;
int gbImportLib = 0;
+int gbTracing = 0;
int giArch = ARCH_X86;
char *pszArchString = "i386";
char *pszArchString2;
FL_STUB = 2,
FL_NONAME = 4,
FL_ORDINAL = 8,
+ FL_NORELAY = 16,
+ FL_RET64 = 32,
+ FL_REGISTER = 64,
};
enum
OutputHeader_stub(FILE *file)
{
fprintf(file, "/* This file is autogenerated, do not edit. */\n\n"
- "#include <stubs.h>\n\n");
+ "#include <stubs.h>\n");
+
+ if (gbTracing)
+ {
+ fprintf(file, "#include <wine/debug.h>\n");
+ fprintf(file, "#include <inttypes.h>\n");
+ fprintf(file, "WINE_DECLARE_DEBUG_CHANNEL(relay);\n");
+ }
+
+ fprintf(file, "\n");
}
int
OutputLine_stub(FILE *file, EXPORT *pexp)
{
int i;
+ int bRelay = 0;
+ int bInPrototype = 0;
if (pexp->nCallingConvention != CC_STUB &&
- (pexp->uFlags & FL_STUB) == 0) return 0;
-
- fprintf(file, "int ");
- if ((giArch == ARCH_X86) &&
- pexp->nCallingConvention == CC_STDCALL)
+ (pexp->uFlags & FL_STUB) == 0)
{
- fprintf(file, "__stdcall ");
+ /* Only relay trace stdcall C functions */
+ if (!gbTracing || (pexp->nCallingConvention != CC_STDCALL)
+ || (pexp->uFlags & FL_NORELAY)
+ || (pexp->strName.buf[0] == '?'))
+ {
+ return 0;
+ }
+ bRelay = 1;
}
- /* Check for C++ */
- if (pexp->strName.buf[0] == '?')
+ /* Declare the "real" function */
+ if (bRelay)
{
- fprintf(file, "stub_function%d(", pexp->nNumber);
+ fprintf(file, "extern ");
+ bInPrototype = 1;
}
- else
+
+ do
{
- fprintf(file, "%.*s(", pexp->strName.len, pexp->strName.buf);
- }
+ if (pexp->uFlags & FL_REGISTER)
+ {
+ /* FIXME: Not sure this is right */
+ fprintf(file, "void ");
+ }
+ else if (pexp->uFlags & FL_RET64)
+ {
+ fprintf(file, "__int64 ");
+ }
+ else
+ {
+ fprintf(file, "int ");
+ }
- for (i = 0; i < pexp->nArgCount; i++)
+ if ((giArch == ARCH_X86) &&
+ pexp->nCallingConvention == CC_STDCALL)
+ {
+ fprintf(file, "__stdcall ");
+ }
+
+ /* Check for C++ */
+ if (pexp->strName.buf[0] == '?')
+ {
+ fprintf(file, "stub_function%d(", pexp->nNumber);
+ }
+ else
+ {
+ if (!bRelay || bInPrototype)
+ fprintf(file, "%.*s(", pexp->strName.len, pexp->strName.buf);
+ else
+ fprintf(file, "$relaytrace$%.*s(", pexp->strName.len, pexp->strName.buf);
+ }
+
+ for (i = 0; i < pexp->nArgCount; i++)
+ {
+ if (i != 0) fprintf(file, ", ");
+ switch (pexp->anArgs[i])
+ {
+ case ARG_LONG: fprintf(file, "long"); break;
+ case ARG_PTR: fprintf(file, "void*"); break;
+ case ARG_STR: fprintf(file, "char*"); break;
+ case ARG_WSTR: fprintf(file, "wchar_t*"); break;
+ case ARG_DBL: fprintf(file, "double"); break;
+ case ARG_INT64 : fprintf(file, "__int64"); break;
+ case ARG_INT128 : fprintf(file, "__int128"); break;
+ case ARG_FLOAT: fprintf(file, "float"); break;
+ }
+ fprintf(file, " a%d", i);
+ }
+
+ if (bInPrototype)
+ {
+ fprintf(file, ");\n\n");
+ }
+ } while (bInPrototype--);
+
+ if (!bRelay)
{
- if (i != 0) fprintf(file, ", ");
- switch (pexp->anArgs[i])
+ fprintf(file, ")\n{\n\tDbgPrint(\"WARNING: calling stub %.*s(",
+ pexp->strName.len, pexp->strName.buf);
+ }
+ else
+ {
+ fprintf(file, ")\n{\n");
+ if (pexp->uFlags & FL_REGISTER)
+ {
+ /* No return value */
+ }
+ else if (pexp->uFlags & FL_RET64)
{
- case ARG_LONG: fprintf(file, "long"); break;
- case ARG_PTR: fprintf(file, "void*"); break;
- case ARG_STR: fprintf(file, "char*"); break;
- case ARG_WSTR: fprintf(file, "wchar_t*"); break;
- case ARG_DBL:
- case ARG_INT64 : fprintf(file, "__int64"); break;
- case ARG_INT128 : fprintf(file, "__int128"); break;
- case ARG_FLOAT: fprintf(file, "float"); break;
+ fprintf(file, "\t__int64 retval;\n");
}
- fprintf(file, " a%d", i);
+ else
+ {
+ fprintf(file, "\tint retval;\n");
+ }
+ fprintf(file, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s(",
+ pszDllName, pexp->strName.len, pexp->strName.buf);
}
- fprintf(file, ")\n{\n\tDbgPrint(\"WARNING: calling stub %.*s(",
- pexp->strName.len, pexp->strName.buf);
for (i = 0; i < pexp->nArgCount; i++)
{
{
fprintf(file, "\t__wine_spec_unimplemented_stub(\"%s\", __FUNCTION__);\n", pszDllName);
}
+ else if (bRelay)
+ {
+ if (pexp->uFlags & FL_REGISTER)
+ {
+ fprintf(file,"\t");
+ }
+ else
+ {
+ fprintf(file, "\tretval = ");
+ }
+ fprintf(file, "%.*s(", pexp->strName.len, pexp->strName.buf);
- fprintf(file, "\treturn 0;\n}\n\n");
+ for (i = 0; i < pexp->nArgCount; i++)
+ {
+ if (i != 0) fprintf(file, ", ");
+ fprintf(file, "a%d", i);
+ }
+ fprintf(file, ");\n");
+ }
+
+ if (!bRelay)
+ fprintf(file, "\treturn 0;\n}\n\n");
+ else if ((pexp->uFlags & FL_REGISTER) == 0)
+ {
+ if (pexp->uFlags & FL_RET64)
+ {
+ fprintf(file, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = %%\"PRIx64\"\\n\", retval);\n",
+ pszDllName, pexp->strName.len, pexp->strName.buf);
+ }
+ else
+ {
+ fprintf(file, "\tif (TRACE_ON(relay))\n\t\tDPRINTF(\"%s: %.*s: retval = 0x%%lx\\n\", retval);\n",
+ pszDllName, pexp->strName.len, pexp->strName.buf);
+ }
+ fprintf(file, "\treturn retval;\n}\n\n");
+ }
return 1;
}
fprintf(file, "; File generated automatically, do not edit! \n\n");
if (giArch == ARCH_X86)
- fprintf(file, ".586\n.model flat\n");
+ {
+ fprintf(file, ".586\n.model flat\n.code\n");
+ }
+ else if (giArch == ARCH_AMD64)
+ {
+ fprintf(file, ".code\n");
+ }
+ else if (giArch == ARCH_ARM)
+ {
+ fprintf(file,
+ " AREA |.text|,ALIGN=2,CODE,READONLY\n\n");
+ }
+}
- fprintf(file, ".code\n");
+void
+Output_symbol(FILE *fileDest, char* pszSymbolName)
+{
+ if (giArch == ARCH_ARM)
+ {
+ fprintf(fileDest,
+ " EXPORT %s [FUNC]\n%s\n",
+ pszSymbolName,
+ pszSymbolName);
+ }
+ else
+ {
+ fprintf(fileDest,
+ "PUBLIC %s\n%s: nop\n",
+ pszSymbolName,
+ pszSymbolName);
+ }
}
int
OutputLine_asmstub(FILE *fileDest, EXPORT *pexp)
{
+ char szNameBuffer[128];
+
/* Handle autoname */
if (pexp->strName.len == 1 && pexp->strName.buf[0] == '@')
{
- fprintf(fileDest, "PUBLIC %sordinal%d\n%sordinal%d: nop\n",
+ sprintf(szNameBuffer, "%sordinal%d\n%sordinal%d: nop\n",
gpszUnderscore, pexp->nOrdinal, gpszUnderscore, pexp->nOrdinal);
}
else if (giArch != ARCH_X86)
{
- fprintf(fileDest, "PUBLIC _stub_%.*s\n_stub_%.*s: nop\n",
- pexp->strName.len, pexp->strName.buf,
+ sprintf(szNameBuffer, "_stub_%.*s",
pexp->strName.len, pexp->strName.buf);
}
else if (pexp->nCallingConvention == CC_STDCALL)
{
- fprintf(fileDest, "PUBLIC __stub_%.*s@%d\n__stub_%.*s@%d: nop\n",
- pexp->strName.len, pexp->strName.buf, pexp->nStackBytes,
+ sprintf(szNameBuffer, "__stub_%.*s@%d",
pexp->strName.len, pexp->strName.buf, pexp->nStackBytes);
}
else if (pexp->nCallingConvention == CC_FASTCALL)
{
- fprintf(fileDest, "PUBLIC @_stub_%.*s@%d\n@_stub_%.*s@%d: nop\n",
- pexp->strName.len, pexp->strName.buf, pexp->nStackBytes,
+ sprintf(szNameBuffer, "@_stub_%.*s@%d",
pexp->strName.len, pexp->strName.buf, pexp->nStackBytes);
}
else if (pexp->nCallingConvention == CC_CDECL ||
pexp->nCallingConvention == CC_STUB)
{
- fprintf(fileDest, "PUBLIC __stub_%.*s\n__stub_%.*s: nop\n",
- pexp->strName.len, pexp->strName.buf,
+ sprintf(szNameBuffer, "__stub_%.*s",
pexp->strName.len, pexp->strName.buf);
}
else if (pexp->nCallingConvention == CC_EXTERN)
{
- fprintf(fileDest, "PUBLIC __stub_%.*s\n__stub_%.*s:\n",
- pexp->strName.len, pexp->strName.buf,
+ sprintf(szNameBuffer, "__stub_%.*s",
pexp->strName.len, pexp->strName.buf);
}
+ Output_symbol(fileDest, szNameBuffer);
+
return 1;
}
/* C++ stubs are forwarded to C stubs */
fprintf(fileDest, "=stub_function%d", pexp->nNumber);
}
+ else if (gbTracing && ((pexp->uFlags & FL_NORELAY) == 0) && (pexp->nCallingConvention == CC_STDCALL) &&
+ (pexp->strName.buf[0] != '?'))
+ {
+ /* Redirect it to the relay-tracing trampoline */
+ fprintf(fileDest, "=$relaytrace$%.*s", pexp->strName.len, pexp->strName.buf);
+ }
}
void
OutputLine_def_GCC(FILE *fileDest, EXPORT *pexp)
{
+ int bTracing = 0;
/* Print the function name, with decoration for export libs */
PrintName(fileDest, pexp, &pexp->strName, gbImportLib);
DbgPrint("Generating def line for '%.*s'\n", pexp->strName.len, pexp->strName.buf);
/* C++ stubs are forwarded to C stubs */
fprintf(fileDest, "=stub_function%d", pexp->nNumber);
}
+ else if (gbTracing && ((pexp->uFlags & FL_NORELAY) == 0) && (pexp->nCallingConvention == CC_STDCALL) &&
+ (pexp->strName.buf[0] != '?'))
+ {
+ /* Redirect it to the relay-tracing trampoline */
+ char buf[256];
+ STRING strTarget;
+ fprintf(fileDest, "=");
+ sprintf(buf, "$relaytrace$%.*s", pexp->strName.len, pexp->strName.buf);
+ strTarget.buf = buf;
+ strTarget.len = pexp->strName.len + 12;
+ PrintName(fileDest, pexp, &strTarget, 1);
+ bTracing = 1;
+ }
/* Special handling for stdcall and fastcall */
if ((giArch == ARCH_X86) &&
fprintf(fileDest, "==%.*s", pexp->strName.len, pexp->strName.buf);
}
}
- else if (!pexp->strTarget.buf)
+ else if ((!pexp->strTarget.buf) && !(bTracing))
{
/* Write a forwarder to the actual decorated symbol */
fprintf(fileDest, "=");
else
{
exp.nOrdinal = atol(pc);
- exp.uFlags |= FL_ORDINAL;
+ /* The import lib should contain the ordinal only if -ordinal was specified */
+ if (!gbImportLib)
+ exp.uFlags |= FL_ORDINAL;
}
/* Go to next token (type) */
else if (CompareToken(pc, "-ordinal"))
{
exp.uFlags |= FL_ORDINAL;
+ /* GCC doesn't automatically import by ordinal if an ordinal
+ * is found in the def file. Force it. */
+ if (gbImportLib && !gbMSComp)
+ exp.uFlags |= FL_NONAME;
}
else if (CompareToken(pc, "-stub"))
{
exp.uFlags |= FL_STUB;
}
- else if (CompareToken(pc, "-norelay") ||
- CompareToken(pc, "-register") ||
- CompareToken(pc, "-ret64"))
+ else if (CompareToken(pc, "-norelay"))
+ {
+ exp.uFlags |= FL_NORELAY;
+ }
+ else if (CompareToken(pc, "-ret64"))
{
- /* silently ignore these */
+ exp.uFlags |= FL_RET64;
+ }
+ else if (CompareToken(pc, "-register"))
+ {
+ exp.uFlags |= FL_REGISTER;
}
else
{
exp.nStackBytes += 8;
exp.anArgs[exp.nArgCount] = ARG_DBL;
}
- else if (CompareToken(pc, "ptr") ||
- CompareToken(pc, "str") ||
- CompareToken(pc, "wstr"))
+ else if (CompareToken(pc, "ptr"))
{
exp.nStackBytes += 4; // sizeof(void*) on x86
- exp.anArgs[exp.nArgCount] = ARG_PTR; // FIXME: handle strings
+ exp.anArgs[exp.nArgCount] = ARG_PTR;
+ }
+ else if (CompareToken(pc, "str"))
+ {
+ exp.nStackBytes += 4; // sizeof(void*) on x86
+ exp.anArgs[exp.nArgCount] = ARG_STR;
+ }
+ else if (CompareToken(pc, "wstr"))
+ {
+ exp.nStackBytes += 4; // sizeof(void*) on x86
+ exp.anArgs[exp.nArgCount] = ARG_WSTR;
}
else if (CompareToken(pc, "int64"))
{
fprintf(stderr, "error: line %d, additional tokens after ')'\n", nLine);
return -17;
}
+
+ /* Don't relay-trace forwarded functions */
+ exp.uFlags |= FL_NORELAY;
}
else
{
void usage(void)
{
- printf("syntax: spec2pdef [<options> ...] <spec file>\n"
+ printf("syntax: spec2def [<options> ...] <spec file>\n"
"Possible options:\n"
- " -h --help prints this screen\n"
- " -l=<file> generates an asm lib stub\n"
- " -d=<file> generates a def file\n"
- " -s=<file> generates a stub file\n"
- " --ms msvc compatibility\n"
- " -n=<name> name of the dll\n"
- " --implib generate a def file for an import library\n"
- " -a=<arch> Set architecture to <arch>. (i386, x86_64, arm)\n");
+ " -h --help prints this screen\n"
+ " -l=<file> generates an asm lib stub\n"
+ " -d=<file> generates a def file\n"
+ " -s=<file> generates a stub file\n"
+ " --ms msvc compatibility\n"
+ " -n=<name> name of the dll\n"
+ " --implib generate a def file for an import library\n"
+ " -a=<arch> Set architecture to <arch>. (i386, x86_64, arm)\n"
+ " --with-tracing generates wine-like \"+relay\" trace trampolines. (necessitates -s)\n");
}
int main(int argc, char *argv[])
{
gbMSComp = 1;
}
+ else if ((strcasecmp(argv[i], "--with-tracing") == 0))
+ {
+ if (!pszStubFileName)
+ {
+ fprintf(stderr, "Error: cannot use --with-tracing without -s option.\n");
+ return -1;
+ }
+ gbTracing = 1;
+ }
else if (argv[i][1] == 'a' && argv[i][2] == '=')
{
pszArchString = argv[i] + 3;
OutputHeader_asmstub(file, pszDllName);
result = ParseFile(pszSource, file, OutputLine_asmstub);
- fprintf(file, "\nEND\n");
+ fprintf(file, "\n END\n");
fclose(file);
}