From 65086ad778b5d8312e4168fc5ed670e545be7d4b Mon Sep 17 00:00:00 2001 From: Bill Hoffman Date: Fri, 19 Jun 2015 16:12:43 -0400 Subject: [PATCH] bindexplib: Import original implementation from CERN Download the original implementation provided by root.cern.ch with the following session: $ wget https://raw.githubusercontent.com/gordonwatts/root-vc-port/f0ee59af/build/win/bindexplib/bindexplib.cxx $ sha1sum bindexplib.cxx fa6efafb2c58a0644bd0f6a56fe02ee0d55c7fcd bindexplib.cxx $ sed -i 's/ *$//;s/'$'\t''/ /' bindexplib.cxx --- Source/bindexplib.cxx | 739 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 739 insertions(+) create mode 100644 Source/bindexplib.cxx diff --git a/Source/bindexplib.cxx b/Source/bindexplib.cxx new file mode 100644 index 000000000..6f9605c42 --- /dev/null +++ b/Source/bindexplib.cxx @@ -0,0 +1,739 @@ +/* +*---------------------------------------------------------------------- +* Program: dumpexts.exe +* Author: Gordon Chaffee +* +* 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. +* +* 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++. +* ====================================== +* Corrections (Axel 2006-04-04): +* Conversion to C++. Mostly. +* + * Extension (Axel 2006-03-15) + * As soon as an object file contains an /EXPORT directive (which + * is generated by the compiler when a symbol is declared as + * declspec(dllexport)) no to-be-exported symbols are printed, + * as the linker will see these directives, and if those directives + * are present we only export selectively (i.e. we trust the + * programmer). + * + * ====================================== +* ====================================== +* Corrections (Valery Fine 23/02/98): +* +* The "(vector) deleting destructor" MUST not be exported +* To recognize it the following test are introduced: +* "@@UAEPAXI@Z" scalar deleting dtor +* "@@QAEPAXI@Z" vector deleting dtor +* "AEPAXI@Z" vector deleting dtor with thunk adjustor +* ====================================== +* Corrections (Valery Fine 12/02/97): +* +* It created a wrong EXPORTS for the global pointers and constants. +* The Section Header has been involved to discover the missing information +* Now the pointers are correctly supplied supplied with "DATA" descriptor +* the constants with no extra descriptor. +* +* Corrections (Valery Fine 16/09/96): +* +* It didn't work for C++ code with global variables and class definitons +* The DumpExternalObject function has been introduced to generate .DEF file +* +* Author: Valery Fine 16/09/96 (E-mail: fine@vxcern.cern.ch) +*---------------------------------------------------------------------- +*/ + +static char sccsid[] = "@(#) winDumpExts.c 1.2 95/10/03 15:27:34"; + +#include +#include +#include +#include + +/* +*---------------------------------------------------------------------- +* GetArgcArgv -- +* +* Break up a line into argc argv +*---------------------------------------------------------------------- +*/ +int +GetArgcArgv(std::string &s, char **argv) +{ + int quote = 0; + int argc = 0; + std::string::iterator bp = s.begin(); + + 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++; + } + } +} + +/* +* 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" +}; + +/* +*---------------------------------------------------------------------- +* 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 "???"; +} + +void AddHex(std::string& buf, long val, bool caps=false) +{ + buf += "0x"; + size_t len=buf.length(); + while (val) { + char hex = (char)(val & 16); + val = val >> 4; + if (hex<10) hex+='0'; + else if (caps) hex+='A'-10; + else hex+='a'-10; + buf.insert(len, hex, 1); + } +} + +/* +*---------------------------------------------------------------------- +* GetSectionName -- +* +* Used by DumpSymbolTable, it gives meaningful names to +* the non-normal section number. +* +* Results: +* A name is returned in buffer +*---------------------------------------------------------------------- +*/ +void +GetSectionName(PIMAGE_SYMBOL pSymbolTable, std::string& buffer) +{ + DWORD section; + + section = pSymbolTable->SectionNumber; + + switch ( (SHORT)section ) + { + case IMAGE_SYM_UNDEFINED: if (pSymbolTable->Value) buffer += "COMM"; else buffer += "UNDEF"; break; + case IMAGE_SYM_ABSOLUTE: buffer += "ABS "; break; + case IMAGE_SYM_DEBUG: buffer += "DEBUG"; break; + default: AddHex(buffer, section, true); + } +} + +/* +*---------------------------------------------------------------------- +* GetSectionCharacteristics -- +* +* Converts the Characteristics field of IMAGE_SECTION_HEADER +* to print. +* +* Results: +* A definiton of the section symbol type +*---------------------------------------------------------------------- +*/ +void +GetSectionCharacteristics(PIMAGE_SECTION_HEADER pSectionHeaders, int nSectNum, std::string &buffer) +{ + DWORD SectChar; + std::string TempBuf; + buffer.clear(); + if (nSectNum > 0) { + SectChar = pSectionHeaders[nSectNum-1].Characteristics; + + buffer = " "; + AddHex(buffer, SectChar); + if (SectChar & IMAGE_SCN_CNT_CODE) buffer += " Code"; + else if (SectChar & IMAGE_SCN_CNT_INITIALIZED_DATA) buffer += " Init. data"; + else if (SectChar & IMAGE_SCN_CNT_UNINITIALIZED_DATA ) buffer += " UnInit data"; + else buffer += " Unknow type"; + + if (SectChar & IMAGE_SCN_MEM_READ) { + buffer += " Read"; + if (SectChar & IMAGE_SCN_MEM_WRITE) + buffer += " and Write"; + else buffer += " only"; + } + else if (SectChar & IMAGE_SCN_MEM_WRITE) + buffer +=" Write only"; + + } +} + +/* +*---------------------------------------------------------------------- +* 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, PIMAGE_SECTION_HEADER pSectionHeaders, FILE *fout, unsigned cSymbols) +{ + unsigned i; + PSTR stringTable; + std::string sectionName; + std::string sectionCharacter; + int iSectNum; + + fprintf(fout, "Symbol Table - %X entries (* = auxillary symbol)\n", + cSymbols); + + fprintf(fout, + "Indx Name Value Section cAux Type Storage Character\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", pSymbolTable->Value); + + iSectNum = pSymbolTable->SectionNumber; + GetSectionName(pSymbolTable, sectionName); + fprintf(fout, " sect:%s aux:%X type:%02X st:%s", + sectionName.c_str(), + pSymbolTable->NumberOfAuxSymbols, + pSymbolTable->Type, + GetSZStorageClass(pSymbolTable->StorageClass) ); + + GetSectionCharacteristics(pSectionHeaders,iSectNum,sectionCharacter); + fprintf(fout," hc: %s \n",sectionCharacter.c_str()); +#if 0 + if ( pSymbolTable->NumberOfAuxSymbols ) + DumpAuxSymbols(pSymbolTable); +#endif + + /* + * 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; + PSTR stringTable; + std::string symbol; + + /* + * 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) { + symbol = ""; + symbol.insert(0, (const char *)(pSymbolTable->N.ShortName), 8); + } else { + symbol = stringTable + pSymbolTable->N.Name.Long; + } + std::string::size_type posAt = symbol.find('@'); + if (posAt != std::string::npos) symbol.erase(posAt); +#ifndef _MSC_VER + fprintf(fout, "\t%s\n", symbol.c_str()); +#else + fprintf(fout, "\t%s\n", symbol.c_str()+1); +#endif + } + } + + /* + * Take into account any aux symbols + */ + i += pSymbolTable->NumberOfAuxSymbols; + pSymbolTable += pSymbolTable->NumberOfAuxSymbols; + pSymbolTable++; + } +} + +/* ++ * Utility func, strstr with size ++ */ +const char* StrNStr(const char* start, const char* find, size_t &size) { + size_t len; + const char* hint; + + if (!start || !find || !size) { + size = 0; + return 0; + } + len = strlen(find); + + while (hint = (const char*) memchr(start, find[0], size-len+1)) { + size -= (hint - start); + if (!strncmp(hint, find, len)) + return hint; + start = hint + 1; + } + + size = 0; + return 0; +} + +/* + *---------------------------------------------------------------------- + * HaveExportedObjects -- + * + * Returns >0 if export directives (declspec(dllexport)) exist. + * + *---------------------------------------------------------------------- + */ +int +HaveExportedObjects(PIMAGE_FILE_HEADER pImageFileHeader, PIMAGE_SECTION_HEADER pSectionHeaders, FILE *fout) +{ + static int fImportFlag = 0; /* The status is nor defined yet */ + WORD i; + size_t size; + char foundExports; + const char * rawdata; + + PIMAGE_SECTION_HEADER pDirectivesSectionHeader; + + if (fImportFlag) return 1; + + i = 0; + foundExports = 0; + pDirectivesSectionHeader = 0; + for(i = 0; i < pImageFileHeader->NumberOfSections && !pDirectivesSectionHeader; i++) + if (!strncmp((const char*)&pSectionHeaders[i].Name[0], ".drectve",8)) + pDirectivesSectionHeader = &pSectionHeaders[i]; + if (!pDirectivesSectionHeader) return 0; + + rawdata=(const char*)pImageFileHeader+pDirectivesSectionHeader->PointerToRawData; + if (!pDirectivesSectionHeader->PointerToRawData || !rawdata) return 0; + + size = pDirectivesSectionHeader->SizeOfRawData; + const char* posImportFlag = rawdata; + while ((posImportFlag = StrNStr(posImportFlag, " /EXPORT:", size))) { + const char* lookingForDict = posImportFlag + 9; + if (!strncmp(lookingForDict, "_G__cpp_",8) || + !strncmp(lookingForDict, "_G__set_cpp_",12)) { + posImportFlag = lookingForDict; + continue; + } + + const char* lookingForDATA = posImportFlag + 9; + while (*(++lookingForDATA) && *lookingForDATA != ' '); + lookingForDATA -= 5; + // ignore DATA exports + if (strncmp(lookingForDATA, ",DATA", 5)) break; + posImportFlag = lookingForDATA + 5; + } + fImportFlag = (int)posImportFlag; + return fImportFlag; +} + + + +/* + *---------------------------------------------------------------------- +* DumpExternalsObjects -- +* +* Dumps a COFF symbol table from an EXE or OBJ. We only use +* it to dump tables from OBJs. +*---------------------------------------------------------------------- +*/ +void +DumpExternalsObjects(PIMAGE_SYMBOL pSymbolTable, PIMAGE_SECTION_HEADER pSectionHeaders, + FILE *fout, unsigned cSymbols, int fort) +{ + unsigned i; + PSTR stringTable; + std::string symbol; + DWORD SectChar; + static int fImportFlag = -1; /* The status is nor defined yet */ + + /* + * 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 || pSymbolTable->Type == 0x0)) { + if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) { + /* + * The name of the Function entry points + */ + if (pSymbolTable->N.Name.Short != 0) { + symbol = ""; + symbol.insert(0, (const char *)pSymbolTable->N.ShortName, 8); + } else { + symbol = stringTable + pSymbolTable->N.Name.Long; + } + + while (isspace(symbol[0])) symbol.erase(0,1); +#ifdef _MSC_VER + if (symbol[0] == '_') symbol.erase(0,1); + if (fort) { + std::string::size_type posAt = symbol.find('@'); + if (posAt != std::string::npos) symbol.erase(posAt); + } +#endif + if (fImportFlag) { + fImportFlag = 0; + fprintf(fout,"EXPORTS \n"); + } + /* + Check whether it is "Scalar deleting destructor" and + "Vector deleting destructor" + */ + /* + if (!strstr(s,"@@UAEPAXI@Z") && !strstr(s,"@@QAEPAXI@Z") && + !strstr(s,"@AEPAXI@Z") && !strstr(s,"AEPAXI@Z") && + !strstr(s,"real@")) + */ + const char *scalarPrefix = "??_G"; + const char *vectorPrefix = "??_E"; + if (symbol.compare(0, 4, scalarPrefix) && + symbol.compare(0, 4, vectorPrefix) && + symbol.find("real@") == std::string::npos) + { + SectChar = pSectionHeaders[pSymbolTable->SectionNumber-1].Characteristics; + if (!pSymbolTable->Type && (SectChar & IMAGE_SCN_MEM_WRITE)) { + // Read only (i.e. constants) must be excluded + fprintf(fout, "\t%s \t DATA\n", symbol.c_str()); + } else { + if ( pSymbolTable->Type || !(SectChar & IMAGE_SCN_MEM_READ)) { + fprintf(fout, "\t%s\n", symbol.c_str()); + } else { + // printf(" strange symbol: %s \n",s); + } + } + } + } + } + else if (pSymbolTable->SectionNumber == IMAGE_SYM_UNDEFINED && !pSymbolTable->Type && 0){ + /* + * The IMPORT global variable entry points + */ + if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) { + symbol = stringTable + pSymbolTable->N.Name.Long; + while (isspace(symbol[0])) symbol.erase(0,1); + if (symbol[0] == '_') symbol.erase(0,1); + if (!fImportFlag) { + fImportFlag = 1; + fprintf(fout,"IMPORTS \n"); + } + fprintf(fout, "\t%s DATA \n", symbol.c_str()+1); + } + } + + /* + * 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, int fort) +{ + PIMAGE_SYMBOL PCOFFSymbolTable; + PIMAGE_SECTION_HEADER PCOFFSectionHeaders; + DWORD_PTR COFFSymbolCount; + + PCOFFSymbolTable = (PIMAGE_SYMBOL) + ((DWORD_PTR)pImageFileHeader + pImageFileHeader->PointerToSymbolTable); + COFFSymbolCount = pImageFileHeader->NumberOfSymbols; + + PCOFFSectionHeaders = (PIMAGE_SECTION_HEADER) + ((DWORD_PTR)pImageFileHeader + + IMAGE_SIZEOF_FILE_HEADER + + pImageFileHeader->SizeOfOptionalHeader); + + + if (full) { + DumpSymbolTable(PCOFFSymbolTable, PCOFFSectionHeaders, fout, COFFSymbolCount); + } else { + int haveExports = HaveExportedObjects(pImageFileHeader, PCOFFSectionHeaders, fout); + if (!haveExports) + DumpExternalsObjects(PCOFFSymbolTable, PCOFFSectionHeaders, fout, COFFSymbolCount, fort); + } +} + +/* +*---------------------------------------------------------------------- +* DumpFile -- +* +* Open up a file, memory map it, and call the appropriate +* dumping routine +*---------------------------------------------------------------------- +*/ +void +DumpFile(LPSTR filename, FILE *fout, int full, int fort) +{ + 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) { +#if 0 + DumpExeFile( dosHeader ); +#else + fprintf(stderr, "File is an executable. I don't dump those.\n"); + return; +#endif + } + /* Does it look like a i386 COFF OBJ file??? */ + else if ( + ((dosHeader->e_magic == IMAGE_FILE_MACHINE_I386) || (dosHeader->e_magic == IMAGE_FILE_MACHINE_AMD64)) + && (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, fort); + } else { + printf("unrecognized file format\n"); + } + UnmapViewOfFile(lpFileBase); + CloseHandle(hFileMapping); + CloseHandle(hFile); +} + +void +main(int argc, char **argv) +{ + std::string cmdline; + int i, arg; + FILE *fout; + int full = 0; + int fort = 0; + char *dllname = ""; + char *outfile = NULL; + + if (argc < 3) { +Usage: + fprintf(stderr, "Usage: %s ?-o outfile? ?-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], "-x") == 0) { + fort = 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) { + dllname = argv[arg]; + arg++; + if (arg == argc) { + goto Usage; + } + fprintf(fout, "LIBRARY %s\n", dllname); +#ifndef _X86_ + fprintf(fout, "CODE PRELOAD MOVEABLE DISCARDABLE\n"); + fprintf(fout, "DATA PRELOAD MOVEABLE MULTIPLE\n\n"); +#endif + } + + for (; arg < argc; arg++) { + WIN32_FIND_DATA FindFileData; + HANDLE SearchFile; + if (argv[arg][0] == '@') { + std::ifstream fargs(&argv[arg][1]); + if (!fargs) { + fprintf(stderr, "Unable to open \'%s\' for reading:\n", + argv[arg]); + perror(""); + exit(1); + } + char *fargv[1000]; + for (i = 0; i < arg; i++) { + cmdline += argv[i]; + fargv[i] = argv[i]; + } + std::string line; + std::getline(fargs, line); + cmdline += line; + fprintf(stderr, "%s\n", line.c_str()); + i += GetArgcArgv(line, &fargv[i]); + argc = i; + argv = fargv; + } + /* + * Argument can contain the wildcard names + */ + SearchFile = FindFirstFile(argv[arg],&FindFileData); + if (SearchFile == INVALID_HANDLE_VALUE){ + fprintf(stderr, "Unable to find \'%s\' for reading:\n", + argv[arg]); + exit(1); + } + else { + /* + * Since WIN32_FIND_DATA has no path information one has to extract it himself. + */ + TCHAR *filename = argv[arg]; + TCHAR path[2048]; + size_t i = strlen(filename); + i--; + while( filename[i] != '\\' && filename[i] != '/' && i >=0) i--; + do + { + if (i >= 0) strncpy( path, filename, i+1); /* Generate the 'path' info */ + path[i+1] = '\0'; + DumpFile(strcat(path, FindFileData.cFileName), fout, full, fort); + } while (FindNextFile(SearchFile,&FindFileData)); + + + FindClose(SearchFile); + } + } + exit(0); +}