|
@@ -0,0 +1,428 @@
|
|
|
+/*============================================================================
|
|
|
+ CMake - Cross Platform Makefile Generator
|
|
|
+ Copyright 2000-2015 Kitware, Inc.
|
|
|
+
|
|
|
+ Distributed under the OSI-approved BSD License (the "License");
|
|
|
+ see accompanying file Copyright.txt for details.
|
|
|
+
|
|
|
+ This software is distributed WITHOUT ANY WARRANTY; without even the
|
|
|
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
+ See the License for more information.
|
|
|
+============================================================================*/
|
|
|
+/*-------------------------------------------------------------------------
|
|
|
+ Portions of this source have been derived from the 'bindexplib' tool
|
|
|
+ provided by the CERN ROOT Data Analysis Framework project (root.cern.ch).
|
|
|
+ Permission has been granted by Pere Mato <[email protected]> to distribute
|
|
|
+ this derived work under the CMake license.
|
|
|
+-------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+/*
|
|
|
+*----------------------------------------------------------------------
|
|
|
+* 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: [email protected])
|
|
|
+*----------------------------------------------------------------------
|
|
|
+*/
|
|
|
+
|
|
|
+#include <cmsys/Encoding.hxx>
|
|
|
+#include <windows.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <string>
|
|
|
+#include <fstream>
|
|
|
+#include <iostream>
|
|
|
+
|
|
|
+typedef struct cmANON_OBJECT_HEADER_BIGOBJ {
|
|
|
+ /* same as ANON_OBJECT_HEADER_V2 */
|
|
|
+ WORD Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
|
|
|
+ WORD Sig2; // Must be 0xffff
|
|
|
+ WORD Version; // >= 2 (implies the Flags field is present)
|
|
|
+ WORD Machine; // Actual machine - IMAGE_FILE_MACHINE_xxx
|
|
|
+ DWORD TimeDateStamp;
|
|
|
+ CLSID ClassID; // {D1BAA1C7-BAEE-4ba9-AF20-FAF66AA4DCB8}
|
|
|
+ DWORD SizeOfData; // Size of data that follows the header
|
|
|
+ DWORD Flags; // 0x1 -> contains metadata
|
|
|
+ DWORD MetaDataSize; // Size of CLR metadata
|
|
|
+ DWORD MetaDataOffset; // Offset of CLR metadata
|
|
|
+
|
|
|
+ /* bigobj specifics */
|
|
|
+ DWORD NumberOfSections; // extended from WORD
|
|
|
+ DWORD PointerToSymbolTable;
|
|
|
+ DWORD NumberOfSymbols;
|
|
|
+} cmANON_OBJECT_HEADER_BIGOBJ;
|
|
|
+
|
|
|
+typedef struct _cmIMAGE_SYMBOL_EX {
|
|
|
+ union {
|
|
|
+ BYTE ShortName[8];
|
|
|
+ struct {
|
|
|
+ DWORD Short; // if 0, use LongName
|
|
|
+ DWORD Long; // offset into string table
|
|
|
+ } Name;
|
|
|
+ DWORD LongName[2]; // PBYTE [2]
|
|
|
+ } N;
|
|
|
+ DWORD Value;
|
|
|
+ LONG SectionNumber;
|
|
|
+ WORD Type;
|
|
|
+ BYTE StorageClass;
|
|
|
+ BYTE NumberOfAuxSymbols;
|
|
|
+} cmIMAGE_SYMBOL_EX;
|
|
|
+typedef cmIMAGE_SYMBOL_EX UNALIGNED *cmPIMAGE_SYMBOL_EX;
|
|
|
+
|
|
|
+PIMAGE_SECTION_HEADER GetSectionHeaderOffset(PIMAGE_FILE_HEADER
|
|
|
+ pImageFileHeader)
|
|
|
+{
|
|
|
+ return (PIMAGE_SECTION_HEADER)
|
|
|
+ ((DWORD_PTR)pImageFileHeader +
|
|
|
+ IMAGE_SIZEOF_FILE_HEADER +
|
|
|
+ pImageFileHeader->SizeOfOptionalHeader);
|
|
|
+}
|
|
|
+
|
|
|
+PIMAGE_SECTION_HEADER GetSectionHeaderOffset(cmANON_OBJECT_HEADER_BIGOBJ*
|
|
|
+ pImageFileHeader)
|
|
|
+{
|
|
|
+ return (PIMAGE_SECTION_HEADER)
|
|
|
+ ((DWORD_PTR)pImageFileHeader +
|
|
|
+ sizeof(cmANON_OBJECT_HEADER_BIGOBJ));
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
++ * 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;
|
|
|
+}
|
|
|
+
|
|
|
+template <
|
|
|
+ // cmANON_OBJECT_HEADER_BIGOBJ or IMAGE_FILE_HEADER
|
|
|
+ class ObjectHeaderType,
|
|
|
+ // cmPIMAGE_SYMBOL_EX or PIMAGE_SYMBOL
|
|
|
+ class SymbolTableType>
|
|
|
+class DumpSymbols
|
|
|
+{
|
|
|
+public:
|
|
|
+ /*
|
|
|
+ *----------------------------------------------------------------------
|
|
|
+ * Constructor --
|
|
|
+ *
|
|
|
+ * Initialize variables from pointer to object header.
|
|
|
+ *
|
|
|
+ *----------------------------------------------------------------------
|
|
|
+ */
|
|
|
+
|
|
|
+ DumpSymbols(ObjectHeaderType* ih,
|
|
|
+ FILE* fout) {
|
|
|
+ this->ObjectImageHeader = ih;
|
|
|
+ this->SymbolTable = (SymbolTableType*)
|
|
|
+ ((DWORD_PTR)this->ObjectImageHeader
|
|
|
+ + this->ObjectImageHeader->PointerToSymbolTable);
|
|
|
+ this->FileOut = fout;
|
|
|
+ this->SectionHeaders =
|
|
|
+ GetSectionHeaderOffset(this->ObjectImageHeader);
|
|
|
+ this->ImportFlag = true;
|
|
|
+ this->SymbolCount = this->ObjectImageHeader->NumberOfSymbols;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ *----------------------------------------------------------------------
|
|
|
+ * HaveExportedObjects --
|
|
|
+ *
|
|
|
+ * Returns true if export directives (declspec(dllexport)) exist.
|
|
|
+ *
|
|
|
+ *----------------------------------------------------------------------
|
|
|
+ */
|
|
|
+
|
|
|
+ bool HaveExportedObjects() {
|
|
|
+ WORD i = 0;
|
|
|
+ size_t size = 0;
|
|
|
+ const char * rawdata = 0;
|
|
|
+ PIMAGE_SECTION_HEADER pDirectivesSectionHeader = 0;
|
|
|
+ PIMAGE_SECTION_HEADER pSectionHeaders = this->SectionHeaders;
|
|
|
+ for(i = 0; (i < this->ObjectImageHeader->NumberOfSections &&
|
|
|
+ !pDirectivesSectionHeader); i++)
|
|
|
+ if (!strncmp((const char*)&pSectionHeaders[i].Name[0], ".drectve",8))
|
|
|
+ pDirectivesSectionHeader = &pSectionHeaders[i];
|
|
|
+ if (!pDirectivesSectionHeader) return 0;
|
|
|
+
|
|
|
+ rawdata=(const char*)
|
|
|
+ this->ObjectImageHeader+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;
|
|
|
+ }
|
|
|
+ if(posImportFlag) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ *----------------------------------------------------------------------
|
|
|
+ * DumpObjFile --
|
|
|
+ *
|
|
|
+ * Dump an object file's exported symbols.
|
|
|
+ *----------------------------------------------------------------------
|
|
|
+ */
|
|
|
+ void DumpObjFile() {
|
|
|
+ if(!HaveExportedObjects()) {
|
|
|
+ this->DumpExternalsObjects();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ *----------------------------------------------------------------------
|
|
|
+ * DumpExternalsObjects --
|
|
|
+ *
|
|
|
+ * Dumps a COFF symbol table from an OBJ.
|
|
|
+ *----------------------------------------------------------------------
|
|
|
+ */
|
|
|
+ void DumpExternalsObjects() {
|
|
|
+ unsigned i;
|
|
|
+ PSTR stringTable;
|
|
|
+ std::string symbol;
|
|
|
+ DWORD SectChar;
|
|
|
+ /*
|
|
|
+ * The string table apparently starts right after the symbol table
|
|
|
+ */
|
|
|
+ stringTable = (PSTR)&this->SymbolTable[this->SymbolCount];
|
|
|
+ SymbolTableType* pSymbolTable = this->SymbolTable;
|
|
|
+ for ( i=0; i < this->SymbolCount; 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ // clear out any leading spaces
|
|
|
+ while (isspace(symbol[0])) symbol.erase(0,1);
|
|
|
+ // if it starts with _ and has an @ then it is a __cdecl
|
|
|
+ // so remove the @ stuff for the export
|
|
|
+ if(symbol[0] == '_') {
|
|
|
+ std::string::size_type posAt = symbol.find('@');
|
|
|
+ if (posAt != std::string::npos) {
|
|
|
+ symbol.erase(posAt);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (symbol[0] == '_') symbol.erase(0,1);
|
|
|
+ if (this->ImportFlag) {
|
|
|
+ this->ImportFlag = false;
|
|
|
+ fprintf(this->FileOut,"EXPORTS \n");
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ Check whether it is "Scalar deleting destructor" and
|
|
|
+ "Vector deleting destructor"
|
|
|
+ */
|
|
|
+ const char *scalarPrefix = "??_G";
|
|
|
+ const char *vectorPrefix = "??_E";
|
|
|
+ // original code had a check for
|
|
|
+ // symbol.find("real@") == std::string::npos)
|
|
|
+ // but if this disallows memmber functions with the name real
|
|
|
+ // if scalarPrefix and vectorPrefix are not found then print
|
|
|
+ // the symbol
|
|
|
+ if (symbol.compare(0, 4, scalarPrefix) &&
|
|
|
+ symbol.compare(0, 4, vectorPrefix) )
|
|
|
+ {
|
|
|
+ SectChar =
|
|
|
+ this->
|
|
|
+ SectionHeaders[pSymbolTable->SectionNumber-1].Characteristics;
|
|
|
+ if (!pSymbolTable->Type && (SectChar & IMAGE_SCN_MEM_WRITE)) {
|
|
|
+ // Read only (i.e. constants) must be excluded
|
|
|
+ fprintf(this->FileOut, "\t%s \t DATA\n", symbol.c_str());
|
|
|
+ } else {
|
|
|
+ if ( pSymbolTable->Type ||
|
|
|
+ !(SectChar & IMAGE_SCN_MEM_READ)) {
|
|
|
+ fprintf(this->FileOut, "\t%s\n", symbol.c_str());
|
|
|
+ } else {
|
|
|
+ // printf(" strange symbol: %s \n",symbol.c_str());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ 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 (!this->ImportFlag) {
|
|
|
+ this->ImportFlag = true;
|
|
|
+ fprintf(this->FileOut,"IMPORTS \n");
|
|
|
+ }
|
|
|
+ fprintf(this->FileOut, "\t%s DATA \n", symbol.c_str()+1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Take into account any aux symbols
|
|
|
+ */
|
|
|
+ i += pSymbolTable->NumberOfAuxSymbols;
|
|
|
+ pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
|
|
|
+ pSymbolTable++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+private:
|
|
|
+ bool ImportFlag;
|
|
|
+ FILE* FileOut;
|
|
|
+ DWORD_PTR SymbolCount;
|
|
|
+ PIMAGE_SECTION_HEADER SectionHeaders;
|
|
|
+ ObjectHeaderType* ObjectImageHeader;
|
|
|
+ SymbolTableType* SymbolTable;
|
|
|
+};
|
|
|
+
|
|
|
+bool
|
|
|
+DumpFile(const char* filename, FILE *fout)
|
|
|
+{
|
|
|
+ HANDLE hFile;
|
|
|
+ HANDLE hFileMapping;
|
|
|
+ LPVOID lpFileBase;
|
|
|
+ PIMAGE_DOS_HEADER dosHeader;
|
|
|
+
|
|
|
+ hFile = CreateFileW(cmsys::Encoding::ToWide(filename).c_str(),
|
|
|
+ GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
|
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
|
|
+
|
|
|
+ if (hFile == INVALID_HANDLE_VALUE) {
|
|
|
+ fprintf(stderr, "Couldn't open file '%s' with CreateFile()\n", filename);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 false;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 false;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 false;
|
|
|
+ }
|
|
|
+ /* 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;
|
|
|
+ */
|
|
|
+ DumpSymbols<IMAGE_FILE_HEADER, IMAGE_SYMBOL>
|
|
|
+ symbolDumper((PIMAGE_FILE_HEADER) lpFileBase, fout);
|
|
|
+ symbolDumper.DumpObjFile();
|
|
|
+ } else {
|
|
|
+ // check for /bigobj format
|
|
|
+ cmANON_OBJECT_HEADER_BIGOBJ* h =
|
|
|
+ (cmANON_OBJECT_HEADER_BIGOBJ*) lpFileBase;
|
|
|
+ if(h->Sig1 == 0x0 && h->Sig2 == 0xffff) {
|
|
|
+ DumpSymbols<cmANON_OBJECT_HEADER_BIGOBJ, cmIMAGE_SYMBOL_EX>
|
|
|
+ symbolDumper((cmANON_OBJECT_HEADER_BIGOBJ*) lpFileBase, fout);
|
|
|
+ symbolDumper.DumpObjFile();
|
|
|
+ } else {
|
|
|
+ printf("unrecognized file format in '%s'\n", filename);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ UnmapViewOfFile(lpFileBase);
|
|
|
+ CloseHandle(hFileMapping);
|
|
|
+ CloseHandle(hFile);
|
|
|
+ return true;
|
|
|
+}
|