123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- /*-------------------------------------------------------------------------
- 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 <pere.mato@cern.ch> 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 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 definitions
- * The DumpExternalObject function has been introduced to generate .DEF file
- *
- * Author: Valery Fine 16/09/96 (E-mail: fine@vxcern.cern.ch)
- *----------------------------------------------------------------------
- */
- #include "bindexplib.h"
- #include "cmsys/Encoding.hxx"
- #include "cmsys/FStream.hxx"
- #include <iostream>
- #include <windows.h>
- #ifndef IMAGE_FILE_MACHINE_ARM
- #define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
- #endif
- #ifndef IMAGE_FILE_MACHINE_THUMB
- #define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
- #endif
- #ifndef IMAGE_FILE_MACHINE_ARMNT
- #define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
- #endif
- #ifndef IMAGE_FILE_MACHINE_ARM64
- #define IMAGE_FILE_MACHINE_ARM64 0xaa64 // ARM64 Little-Endian
- #endif
- 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, std::set<std::string>& symbols,
- std::set<std::string>& dataSymbols, bool isI386)
- : Symbols(symbols)
- , DataSymbols(dataSymbols)
- {
- this->ObjectImageHeader = ih;
- this->SymbolTable =
- (SymbolTableType*)((DWORD_PTR) this->ObjectImageHeader +
- this->ObjectImageHeader->PointerToSymbolTable);
- this->SectionHeaders = GetSectionHeaderOffset(this->ObjectImageHeader);
- this->SymbolCount = this->ObjectImageHeader->NumberOfSymbols;
- this->IsI386 = isI386;
- }
- /*
- *----------------------------------------------------------------------
- * DumpObjFile --
- *
- * Dump an object file's exported symbols.
- *----------------------------------------------------------------------
- */
- void DumpObjFile() { 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.clear();
- 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);
- }
- }
- // For i386 builds we need to remove _
- if (this->IsI386 && symbol[0] == '_') {
- symbol.erase(0, 1);
- }
- // Check whether it is "Scalar deleting destructor" and "Vector
- // deleting destructor"
- // if scalarPrefix and vectorPrefix are not found then print
- // the symbol
- const char* scalarPrefix = "??_G";
- const char* vectorPrefix = "??_E";
- // The original code had a check for
- // symbol.find("real@") == std::string::npos)
- // but this disallows member functions with the name "real".
- if (symbol.compare(0, 4, scalarPrefix) &&
- symbol.compare(0, 4, vectorPrefix)) {
- SectChar = this->SectionHeaders[pSymbolTable->SectionNumber - 1]
- .Characteristics;
- // skip symbols containing a dot
- if (symbol.find('.') == std::string::npos) {
- if (!pSymbolTable->Type && (SectChar & IMAGE_SCN_MEM_WRITE)) {
- // Read only (i.e. constants) must be excluded
- this->DataSymbols.insert(symbol);
- } else {
- if (pSymbolTable->Type || !(SectChar & IMAGE_SCN_MEM_READ) ||
- (SectChar & IMAGE_SCN_MEM_EXECUTE)) {
- this->Symbols.insert(symbol);
- }
- }
- }
- }
- }
- }
- /*
- * Take into account any aux symbols
- */
- i += pSymbolTable->NumberOfAuxSymbols;
- pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
- pSymbolTable++;
- }
- }
- private:
- std::set<std::string>& Symbols;
- std::set<std::string>& DataSymbols;
- DWORD_PTR SymbolCount;
- PIMAGE_SECTION_HEADER SectionHeaders;
- ObjectHeaderType* ObjectImageHeader;
- SymbolTableType* SymbolTable;
- bool IsI386;
- };
- bool DumpFile(const char* filename, std::set<std::string>& symbols,
- std::set<std::string>& dataSymbols)
- {
- HANDLE hFile;
- HANDLE hFileMapping;
- LPVOID lpFileBase;
- 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;
- }
- const PIMAGE_DOS_HEADER 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;
- } else {
- const PIMAGE_FILE_HEADER imageHeader = (PIMAGE_FILE_HEADER)lpFileBase;
- /* Does it look like a COFF OBJ file??? */
- if (((imageHeader->Machine == IMAGE_FILE_MACHINE_I386) ||
- (imageHeader->Machine == IMAGE_FILE_MACHINE_AMD64) ||
- (imageHeader->Machine == IMAGE_FILE_MACHINE_ARM) ||
- (imageHeader->Machine == IMAGE_FILE_MACHINE_ARMNT) ||
- (imageHeader->Machine == IMAGE_FILE_MACHINE_ARM64)) &&
- (imageHeader->Characteristics == 0)) {
- /*
- * The tests above are checking for IMAGE_FILE_HEADER.Machine
- * if it contains supported machine formats (currently ARM and x86)
- * and IMAGE_FILE_HEADER.Characteristics == 0 indicating that
- * this is not linked COFF OBJ file;
- */
- DumpSymbols<IMAGE_FILE_HEADER, IMAGE_SYMBOL> symbolDumper(
- (PIMAGE_FILE_HEADER)lpFileBase, symbols, dataSymbols,
- (imageHeader->Machine == IMAGE_FILE_MACHINE_I386));
- 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, symbols,
- dataSymbols, (h->Machine == IMAGE_FILE_MACHINE_I386));
- symbolDumper.DumpObjFile();
- } else {
- printf("unrecognized file format in '%s'\n", filename);
- return false;
- }
- }
- }
- UnmapViewOfFile(lpFileBase);
- CloseHandle(hFileMapping);
- CloseHandle(hFile);
- return true;
- }
- bool bindexplib::AddObjectFile(const char* filename)
- {
- return DumpFile(filename, this->Symbols, this->DataSymbols);
- }
- bool bindexplib::AddDefinitionFile(const char* filename)
- {
- cmsys::ifstream infile(filename);
- if (!infile) {
- fprintf(stderr, "Couldn't open definition file '%s'\n", filename);
- return false;
- }
- std::string str;
- while (std::getline(infile, str)) {
- // skip the LIBRAY and EXPORTS lines (if any)
- if ((str.compare(0, 7, "LIBRARY") == 0) ||
- (str.compare(0, 7, "EXPORTS") == 0)) {
- continue;
- }
- // remove leading tabs & spaces
- str.erase(0, str.find_first_not_of(" \t"));
- std::size_t found = str.find(" \t DATA");
- if (found != std::string::npos) {
- str.erase(found, std::string::npos);
- this->DataSymbols.insert(str);
- } else {
- this->Symbols.insert(str);
- }
- }
- infile.close();
- return true;
- }
- void bindexplib::WriteFile(FILE* file)
- {
- fprintf(file, "EXPORTS \n");
- for (std::string const& ds : this->DataSymbols) {
- fprintf(file, "\t%s \t DATA\n", ds.c_str());
- }
- for (std::string const& s : this->Symbols) {
- fprintf(file, "\t%s\n", s.c_str());
- }
- }
|