/*-----------------------------------------------------------------------------------*/ /* * winDumpExts.c -- * Author: Gordon Chaffee, Scott Stanton * * History: The real functionality of this file was written by * Matt Pietrek in 1993 in his pedump utility. I've * modified it to dump the externals in a bunch of object * files to create a .def file. * * 10/12/95 Modified by Scott Stanton to support Relocatable Object Module * Format files for Borland C++ 4.5. * * Notes: Visual C++ puts an underscore before each exported symbol. * This file removes them. I don't know if this is a problem * this other compilers. If _MSC_VER is defined, * the underscore is removed. If not, it isn't. To get a * full dump of an object file, use the -f option. This can * help determine the something that may be different with a * compiler other than Visual C++. */ /*-----------------------------------------------------------------------------------*/ /* Updated 2007 Win64 support (A.C) */ /* it will be interesting to use PEDUMP http://www.wheaty.net */ /* this tools is used to extract symbols from .obj */ /* used to build Scilab on Windows and dynamic link */ /*-----------------------------------------------------------------------------------*/ #include #include #include #include /*-----------------------------------------------------------------------------------*/ #ifdef _ALPHA_ #define e_magic_number IMAGE_FILE_MACHINE_ALPHA #else #ifdef _WIN64 #define e_magic_number IMAGE_FILE_MACHINE_AMD64 #else #define e_magic_number IMAGE_FILE_MACHINE_I386 #endif #endif #ifdef _WIN64 #define MakePtr(cast, ptr, addValue) (cast)( (DWORD64)(ptr) + (DWORD64)(addValue)) #else #define MakePtr(cast, ptr, addValue) (cast)( (DWORD)(ptr) + (DWORD)(addValue)) #endif #define stricmp _stricmp /*-----------------------------------------------------------------------------------*/ /* * The names of the first group of possible symbol table storage classes */ /*-----------------------------------------------------------------------------------*/ char * SzStorageClass1[] = { "NULL", "AUTOMATIC", "EXTERNAL", "STATIC", "REGISTER", "EXTERNAL_DEF", "LABEL", "UNDEFINED_LABEL", "MEMBER_OF_STRUCT", "ARGUMENT", "STRUCT_TAG", "MEMBER_OF_UNION", "UNION_TAG", "TYPE_DEFINITION", "UNDEFINED_STATIC", "ENUM_TAG", "MEMBER_OF_ENUM", "REGISTER_PARAM", "BIT_FIELD" }; /*-----------------------------------------------------------------------------------*/ /* * The names of the second group of possible symbol table storage classes */ /*-----------------------------------------------------------------------------------*/ char * SzStorageClass2[] = { "BLOCK", "FUNCTION", "END_OF_STRUCT", "FILE", "SECTION", "WEAK_EXTERNAL" }; /*-----------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------- * GetArgcArgv -- * * Break up a line into argc argv *---------------------------------------------------------------------- */ int GetArgcArgv(char *s, char **argv) { int quote = 0; int argc = 0; char *bp = NULL; bp = s; while (1) { while (isspace(*bp)) { bp++; } if (*bp == '\n' || *bp == '\0') { *bp = '\0'; return argc; } if (*bp == '\"') { quote = 1; bp++; } argv[argc++] = bp; while (*bp != '\0') { if (quote) { if (*bp == '\"') { quote = 0; *bp = '\0'; bp++; break; } bp++; continue; } if (isspace(*bp)) { *bp = '\0'; bp++; break; } bp++; } } } /*-----------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------- * GetSZStorageClass -- * * Given a symbol storage class value, return a descriptive * ASCII string *---------------------------------------------------------------------- */ PSTR GetSZStorageClass(BYTE storageClass) { if ( storageClass <= IMAGE_SYM_CLASS_BIT_FIELD ) { return SzStorageClass1[storageClass]; } else if ( (storageClass >= IMAGE_SYM_CLASS_BLOCK) && (storageClass <= IMAGE_SYM_CLASS_WEAK_EXTERNAL) ) { return SzStorageClass2[storageClass - IMAGE_SYM_CLASS_BLOCK]; } else { return "???"; } } /*-----------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------- * GetSectionName -- * * Used by DumpSymbolTable, it gives meaningful names to * the non-normal section number. * * Results: * A name is returned in buffer *---------------------------------------------------------------------- */ void GetSectionName(WORD section, PSTR buffer, unsigned cbBuffer) { char tempbuffer[10]; switch ( (SHORT)section ) { case IMAGE_SYM_UNDEFINED: strcpy(tempbuffer, "UNDEF"); break; case IMAGE_SYM_ABSOLUTE: strcpy(tempbuffer, "ABS "); break; case IMAGE_SYM_DEBUG: strcpy(tempbuffer, "DEBUG"); break; default: wsprintf(tempbuffer, "%-5X", section); } strncpy(buffer, tempbuffer, cbBuffer - 1); } /*-----------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------- * DumpSymbolTable -- * * Dumps a COFF symbol table from an EXE or OBJ. We only use * it to dump tables from OBJs. *---------------------------------------------------------------------- */ void DumpSymbolTable(PIMAGE_SYMBOL pSymbolTable, FILE *fout, unsigned cSymbols) { unsigned i = 0; PSTR stringTable = NULL; char sectionName[10]; fprintf(fout, "Symbol Table - %X entries (* = auxillary symbol)\n", cSymbols); fprintf(fout, "Indx Name Value Section cAux Type Storage\n" "---- -------------------- -------- ---------- ----- ------- --------\n"); /* * The string table apparently starts right after the symbol table */ stringTable = (PSTR)&pSymbolTable[cSymbols]; for ( i = 0; i < cSymbols; i++ ) { fprintf(fout, "%04X ", i); if ( pSymbolTable->N.Name.Short != 0 ) { fprintf(fout, "%-20.8s", pSymbolTable->N.ShortName); } else { fprintf(fout, "%-20s", stringTable + pSymbolTable->N.Name.Long); } fprintf(fout, " %08X", (unsigned int)pSymbolTable->Value); GetSectionName(pSymbolTable->SectionNumber, sectionName, sizeof(sectionName)); fprintf(fout, " sect:%s aux:%X type:%02X st:%s\n", sectionName, pSymbolTable->NumberOfAuxSymbols, pSymbolTable->Type, GetSZStorageClass(pSymbolTable->StorageClass) ); /* * Take into account any aux symbols */ i += pSymbolTable->NumberOfAuxSymbols; pSymbolTable += pSymbolTable->NumberOfAuxSymbols; pSymbolTable++; } } /*-----------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------- * DumpExternals -- * * Dumps a COFF symbol table from an EXE or OBJ. We only use * it to dump tables from OBJs. *---------------------------------------------------------------------- */ void DumpExternals(PIMAGE_SYMBOL pSymbolTable, FILE *fout, unsigned cSymbols) { unsigned i = 0; PSTR stringTable = NULL; char *s = NULL, *f = NULL; char symbol[4096]; /* * The string table apparently starts right after the symbol table */ stringTable = (PSTR)&pSymbolTable[cSymbols]; for ( i = 0; i < cSymbols; i++ ) { if (pSymbolTable->SectionNumber > 0 && pSymbolTable->Type == 0x20) { if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) { if (pSymbolTable->N.Name.Short != 0) { strncpy(symbol, (const char*)pSymbolTable->N.ShortName, 8); symbol[8] = 0; } else { s = stringTable + pSymbolTable->N.Name.Long; strcpy(symbol, s); } s = symbol; f = strchr(s, '@'); if (f) { *f = 0; } #if defined(_MSC_VER) && ( defined(_X86_) ) if (symbol[0] == '_') { s = &symbol[1]; } #endif if (( stricmp(s, "DllEntryPoint") != 0) && (stricmp(s, "DllMain") != 0)) { //remove Intel C++ 14 added symbols if ( s[0] != '?' && strncmp(s, "__sti__?", 8) != 0) { fprintf(fout, "\t%s\n", s); } } } } /* * Take into account any aux symbols */ i += pSymbolTable->NumberOfAuxSymbols; pSymbolTable += pSymbolTable->NumberOfAuxSymbols; pSymbolTable++; } } /*-----------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------- * DumpObjFile -- * * Dump an object file--either a full listing or just the exported * symbols. *---------------------------------------------------------------------- */ void DumpObjFile(PIMAGE_FILE_HEADER pImageFileHeader, FILE *fout, int full) { PIMAGE_SYMBOL PCOFFSymbolTable; DWORD COFFSymbolCount; //PCOFFSymbolTable = (PIMAGE_SYMBOL)LongToPtr( //((DWORD)PtrToLong( pImageFileHeader ) + pImageFileHeader->PointerToSymbolTable) ); PCOFFSymbolTable = MakePtr(PIMAGE_SYMBOL, pImageFileHeader, pImageFileHeader->PointerToSymbolTable); COFFSymbolCount = pImageFileHeader->NumberOfSymbols; if (full) { DumpSymbolTable(PCOFFSymbolTable, fout, COFFSymbolCount); } else { DumpExternals(PCOFFSymbolTable, fout, COFFSymbolCount); } } /*-----------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------- * SkipToNextRecord -- * * Skip over the current ROMF record and return the type of the * next record. *---------------------------------------------------------------------- */ BYTE SkipToNextRecord(BYTE **ppBuffer) { int length = 0; (*ppBuffer)++; /* Skip over the type.*/ length = *((WORD*)(*ppBuffer))++; /* Retrieve the length. */ *ppBuffer += length; /* Skip over the rest. */ return **ppBuffer; /* Return the type. */ } /*-----------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------- * DumpROMFObjFile -- * * Dump a Relocatable Object Module Format file, displaying only * the exported symbols. *---------------------------------------------------------------------- */ void DumpROMFObjFile(LPVOID pBuffer, FILE *fout) { BYTE type = 0, length = 0 ; char symbol[1024], *s = NULL; while (1) { BYTE *loc = (BYTE*)pBuffer; type = SkipToNextRecord(&loc); if (type == 0x90) { /* PUBDEF */ if (((BYTE*)pBuffer)[4] != 0) { length = ((BYTE*)pBuffer)[5]; strncpy(symbol, ((char*)pBuffer) + 6, length); symbol[length] = '\0'; s = symbol; if ((stricmp(s, "DllEntryPoint") != 0) && (stricmp(s, "DllMain") != 0)) { if (s[0] == '_') { s++; fprintf(fout, "\t_%s\n\t%s=_%s\n", s, s, s); } else if (s[0] != '?' ) { fprintf(fout, "\t%s\n", s); } } } } else if (type == 0x8B || type == 0x8A) { /* MODEND */ break; } } } /*-----------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------- * DumpFile -- * * Open up a file, memory map it, and call the appropriate * dumping routine *---------------------------------------------------------------------- */ void DumpFile(LPSTR filename, FILE *fout, int full) { HANDLE hFile; HANDLE hFileMapping; LPVOID lpFileBase; PIMAGE_DOS_HEADER dosHeader; hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) { fprintf(stderr, "Couldn't open file with CreateFile()\n"); return; } hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hFileMapping == 0) { CloseHandle(hFile); fprintf(stderr, "Couldn't open file mapping with CreateFileMapping()\n"); return; } lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0); if (lpFileBase == 0) { CloseHandle(hFileMapping); CloseHandle(hFile); fprintf(stderr, "Couldn't map view of file with MapViewOfFile()\n"); return; } dosHeader = (PIMAGE_DOS_HEADER)lpFileBase; if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) { fprintf(stderr, "File is an executable. I don't dump those.\n"); return; } /* Does it look like a i386 COFF OBJ file??? */ else if ((dosHeader->e_magic == e_magic_number) && (dosHeader->e_sp == 0)) { /* * The two tests above aren't what they look like. They're * really checking for IMAGE_FILE_HEADER.Machine == i386 (0x14C) * and IMAGE_FILE_HEADER.SizeOfOptionalHeader == 0; */ DumpObjFile((PIMAGE_FILE_HEADER) lpFileBase, fout, full); } else if (*((BYTE *)lpFileBase) == 0x80) { /* * This file looks like it might be a ROMF file. */ DumpROMFObjFile(lpFileBase, fout); } else { printf("unrecognized file format\n"); } UnmapViewOfFile(lpFileBase); CloseHandle(hFileMapping); CloseHandle(hFile); } /*-----------------------------------------------------------------------------------*/ int main(int argc, char **argv) { int noheader = 0; char *fargv[1000]; char cmdline[10000]; int i = 0, arg = 0; FILE *fout = NULL; int pos = 0; int full = 0; char *outfile = NULL; if (argc < 3) { Usage: fprintf(stderr, "Usage: %s ?-o outfile? ?-n? ?-f(ull)? ..\n", argv[0]); exit(1); } arg = 1; while (argv[arg][0] == '-') { if (strcmp(argv[arg], "--") == 0) { arg++; break; } else if (strcmp(argv[arg], "-f") == 0) { full = 1; } else if (strcmp(argv[arg], "-n") == 0) { noheader = 1; } else if (strcmp(argv[arg], "-o") == 0) { arg++; if (arg == argc) { goto Usage; } outfile = argv[arg]; } arg++; } if (arg == argc) { goto Usage; } if (outfile) { fout = fopen(outfile, "w+"); if (fout == NULL) { fprintf(stderr, "Unable to open \'%s\' for writing:\n", argv[arg]); perror(""); exit(1); } } else { fout = stdout; } if (! full) { char *dllname = argv[arg]; arg++; if (arg == argc) { goto Usage; } if (noheader != 1) { fprintf(fout, "LIBRARY %s\n", dllname); fprintf(fout, "EXPORTS\n"); } } for (; arg < argc; arg++) { if (argv[arg][0] == '@') { FILE *fargs = fopen(&argv[arg][1], "r"); if (fargs == NULL) { fprintf(stderr, "Unable to open \'%s\' for reading:\n", argv[arg]); perror(""); exit(1); } pos = 0; for (i = 0; i < arg; i++) { strcpy(&cmdline[pos], argv[i]); pos += (int)strlen(&cmdline[pos]) + 1; fargv[i] = argv[i]; } fgets(&cmdline[pos], sizeof(cmdline), fargs); fprintf(stderr, "%s\n", &cmdline[pos]); fclose(fargs); i += GetArgcArgv(&cmdline[pos], &fargv[i]); argc = i; argv = fargv; } DumpFile(argv[arg], fout, full); } exit(0); return 0; } /*-----------------------------------------------------------------------------------*/