bindexplib.cxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. /*-------------------------------------------------------------------------
  4. Portions of this source have been derived from the 'bindexplib' tool
  5. provided by the CERN ROOT Data Analysis Framework project (root.cern.ch).
  6. Permission has been granted by Pere Mato <[email protected]> to distribute
  7. this derived work under the CMake license.
  8. -------------------------------------------------------------------------*/
  9. /*
  10. *----------------------------------------------------------------------
  11. * Program: dumpexts.exe
  12. * Author: Gordon Chaffee
  13. *
  14. * History: The real functionality of this file was written by
  15. * Matt Pietrek in 1993 in his pedump utility. I've
  16. * modified it to dump the externals in a bunch of object
  17. * files to create a .def file.
  18. *
  19. * Notes: Visual C++ puts an underscore before each exported symbol.
  20. * This file removes them. I don't know if this is a problem
  21. * this other compilers. If _MSC_VER is defined,
  22. * the underscore is removed. If not, it isn't. To get a
  23. * full dump of an object file, use the -f option. This can
  24. * help determine the something that may be different with a
  25. * compiler other than Visual C++.
  26. * ======================================
  27. * Corrections (Axel 2006-04-04):
  28. * Conversion to C++. Mostly.
  29. *
  30. * Extension (Axel 2006-03-15)
  31. * As soon as an object file contains an /EXPORT directive (which
  32. * is generated by the compiler when a symbol is declared as
  33. * declspec(dllexport)) no to-be-exported symbols are printed,
  34. * as the linker will see these directives, and if those directives
  35. * are present we only export selectively (i.e. we trust the
  36. * programmer).
  37. *
  38. * ======================================
  39. * ======================================
  40. * Corrections (Valery Fine 23/02/98):
  41. *
  42. * The "(vector) deleting destructor" MUST not be exported
  43. * To recognize it the following test are introduced:
  44. * "@@UAEPAXI@Z" scalar deleting dtor
  45. * "@@QAEPAXI@Z" vector deleting dtor
  46. * "AEPAXI@Z" vector deleting dtor with thunk adjustor
  47. * ======================================
  48. * Corrections (Valery Fine 12/02/97):
  49. *
  50. * It created a wrong EXPORTS for the global pointers and constants.
  51. * The Section Header has been involved to discover the missing information
  52. * Now the pointers are correctly supplied supplied with "DATA" descriptor
  53. * the constants with no extra descriptor.
  54. *
  55. * Corrections (Valery Fine 16/09/96):
  56. *
  57. * It didn't work for C++ code with global variables and class definitons
  58. * The DumpExternalObject function has been introduced to generate .DEF file
  59. *
  60. * Author: Valery Fine 16/09/96 (E-mail: [email protected])
  61. *----------------------------------------------------------------------
  62. */
  63. #include "bindexplib.h"
  64. #include <cmsys/Encoding.hxx>
  65. #include <cmsys/FStream.hxx>
  66. #include <iostream>
  67. #include <windows.h>
  68. typedef struct cmANON_OBJECT_HEADER_BIGOBJ {
  69. /* same as ANON_OBJECT_HEADER_V2 */
  70. WORD Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
  71. WORD Sig2; // Must be 0xffff
  72. WORD Version; // >= 2 (implies the Flags field is present)
  73. WORD Machine; // Actual machine - IMAGE_FILE_MACHINE_xxx
  74. DWORD TimeDateStamp;
  75. CLSID ClassID; // {D1BAA1C7-BAEE-4ba9-AF20-FAF66AA4DCB8}
  76. DWORD SizeOfData; // Size of data that follows the header
  77. DWORD Flags; // 0x1 -> contains metadata
  78. DWORD MetaDataSize; // Size of CLR metadata
  79. DWORD MetaDataOffset; // Offset of CLR metadata
  80. /* bigobj specifics */
  81. DWORD NumberOfSections; // extended from WORD
  82. DWORD PointerToSymbolTable;
  83. DWORD NumberOfSymbols;
  84. } cmANON_OBJECT_HEADER_BIGOBJ;
  85. typedef struct _cmIMAGE_SYMBOL_EX {
  86. union {
  87. BYTE ShortName[8];
  88. struct {
  89. DWORD Short; // if 0, use LongName
  90. DWORD Long; // offset into string table
  91. } Name;
  92. DWORD LongName[2]; // PBYTE [2]
  93. } N;
  94. DWORD Value;
  95. LONG SectionNumber;
  96. WORD Type;
  97. BYTE StorageClass;
  98. BYTE NumberOfAuxSymbols;
  99. } cmIMAGE_SYMBOL_EX;
  100. typedef cmIMAGE_SYMBOL_EX UNALIGNED *cmPIMAGE_SYMBOL_EX;
  101. PIMAGE_SECTION_HEADER GetSectionHeaderOffset(PIMAGE_FILE_HEADER
  102. pImageFileHeader)
  103. {
  104. return (PIMAGE_SECTION_HEADER)
  105. ((DWORD_PTR)pImageFileHeader +
  106. IMAGE_SIZEOF_FILE_HEADER +
  107. pImageFileHeader->SizeOfOptionalHeader);
  108. }
  109. PIMAGE_SECTION_HEADER GetSectionHeaderOffset(cmANON_OBJECT_HEADER_BIGOBJ*
  110. pImageFileHeader)
  111. {
  112. return (PIMAGE_SECTION_HEADER)
  113. ((DWORD_PTR)pImageFileHeader +
  114. sizeof(cmANON_OBJECT_HEADER_BIGOBJ));
  115. }
  116. /*
  117. + * Utility func, strstr with size
  118. + */
  119. const char* StrNStr(const char* start, const char* find, size_t &size) {
  120. size_t len;
  121. const char* hint;
  122. if (!start || !find || !size) {
  123. size = 0;
  124. return 0;
  125. }
  126. len = strlen(find);
  127. while ((hint = (const char*) memchr(start, find[0], size-len+1))) {
  128. size -= (hint - start);
  129. if (!strncmp(hint, find, len))
  130. return hint;
  131. start = hint + 1;
  132. }
  133. size = 0;
  134. return 0;
  135. }
  136. template <
  137. // cmANON_OBJECT_HEADER_BIGOBJ or IMAGE_FILE_HEADER
  138. class ObjectHeaderType,
  139. // cmPIMAGE_SYMBOL_EX or PIMAGE_SYMBOL
  140. class SymbolTableType>
  141. class DumpSymbols
  142. {
  143. public:
  144. /*
  145. *----------------------------------------------------------------------
  146. * Constructor --
  147. *
  148. * Initialize variables from pointer to object header.
  149. *
  150. *----------------------------------------------------------------------
  151. */
  152. DumpSymbols(ObjectHeaderType* ih,
  153. std::set<std::string>& symbols,
  154. std::set<std::string>& dataSymbols,
  155. bool is64)
  156. :Symbols(symbols), DataSymbols(dataSymbols)
  157. {
  158. this->ObjectImageHeader = ih;
  159. this->SymbolTable = (SymbolTableType*)
  160. ((DWORD_PTR)this->ObjectImageHeader
  161. + this->ObjectImageHeader->PointerToSymbolTable);
  162. this->SectionHeaders =
  163. GetSectionHeaderOffset(this->ObjectImageHeader);
  164. this->SymbolCount = this->ObjectImageHeader->NumberOfSymbols;
  165. this->Is64Bit = is64;
  166. }
  167. /*
  168. *----------------------------------------------------------------------
  169. * HaveExportedObjects --
  170. *
  171. * Returns true if export directives (declspec(dllexport)) exist.
  172. *
  173. *----------------------------------------------------------------------
  174. */
  175. bool HaveExportedObjects() {
  176. WORD i = 0;
  177. size_t size = 0;
  178. const char * rawdata = 0;
  179. PIMAGE_SECTION_HEADER pDirectivesSectionHeader = 0;
  180. PIMAGE_SECTION_HEADER pSectionHeaders = this->SectionHeaders;
  181. for(i = 0; (i < this->ObjectImageHeader->NumberOfSections &&
  182. !pDirectivesSectionHeader); i++)
  183. if (!strncmp((const char*)&pSectionHeaders[i].Name[0], ".drectve",8))
  184. pDirectivesSectionHeader = &pSectionHeaders[i];
  185. if (!pDirectivesSectionHeader) return 0;
  186. rawdata=(const char*)
  187. this->ObjectImageHeader+pDirectivesSectionHeader->PointerToRawData;
  188. if (!pDirectivesSectionHeader->PointerToRawData || !rawdata) return 0;
  189. size = pDirectivesSectionHeader->SizeOfRawData;
  190. const char* posImportFlag = rawdata;
  191. while ((posImportFlag = StrNStr(posImportFlag, " /EXPORT:", size))) {
  192. const char* lookingForDict = posImportFlag + 9;
  193. if (!strncmp(lookingForDict, "_G__cpp_",8) ||
  194. !strncmp(lookingForDict, "_G__set_cpp_",12)) {
  195. posImportFlag = lookingForDict;
  196. continue;
  197. }
  198. const char* lookingForDATA = posImportFlag + 9;
  199. while (*(++lookingForDATA) && *lookingForDATA != ' ');
  200. lookingForDATA -= 5;
  201. // ignore DATA exports
  202. if (strncmp(lookingForDATA, ",DATA", 5)) break;
  203. posImportFlag = lookingForDATA + 5;
  204. }
  205. if(posImportFlag) {
  206. return true;
  207. }
  208. return false;
  209. }
  210. /*
  211. *----------------------------------------------------------------------
  212. * DumpObjFile --
  213. *
  214. * Dump an object file's exported symbols.
  215. *----------------------------------------------------------------------
  216. */
  217. void DumpObjFile() {
  218. this->DumpExternalsObjects();
  219. }
  220. /*
  221. *----------------------------------------------------------------------
  222. * DumpExternalsObjects --
  223. *
  224. * Dumps a COFF symbol table from an OBJ.
  225. *----------------------------------------------------------------------
  226. */
  227. void DumpExternalsObjects() {
  228. unsigned i;
  229. PSTR stringTable;
  230. std::string symbol;
  231. DWORD SectChar;
  232. /*
  233. * The string table apparently starts right after the symbol table
  234. */
  235. stringTable = (PSTR)&this->SymbolTable[this->SymbolCount];
  236. SymbolTableType* pSymbolTable = this->SymbolTable;
  237. for ( i=0; i < this->SymbolCount; i++ ) {
  238. if (pSymbolTable->SectionNumber > 0 &&
  239. ( pSymbolTable->Type == 0x20 || pSymbolTable->Type == 0x0)) {
  240. if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
  241. /*
  242. * The name of the Function entry points
  243. */
  244. if (pSymbolTable->N.Name.Short != 0) {
  245. symbol = "";
  246. symbol.insert(0, (const char *)pSymbolTable->N.ShortName, 8);
  247. } else {
  248. symbol = stringTable + pSymbolTable->N.Name.Long;
  249. }
  250. // clear out any leading spaces
  251. while (isspace(symbol[0])) symbol.erase(0,1);
  252. // if it starts with _ and has an @ then it is a __cdecl
  253. // so remove the @ stuff for the export
  254. if(symbol[0] == '_') {
  255. std::string::size_type posAt = symbol.find('@');
  256. if (posAt != std::string::npos) {
  257. symbol.erase(posAt);
  258. }
  259. }
  260. // For 64 bit builds we don't need to remove _
  261. if(!this->Is64Bit)
  262. {
  263. if (symbol[0] == '_')
  264. {
  265. symbol.erase(0,1);
  266. }
  267. }
  268. /*
  269. Check whether it is "Scalar deleting destructor" and
  270. "Vector deleting destructor"
  271. */
  272. const char *scalarPrefix = "??_G";
  273. const char *vectorPrefix = "??_E";
  274. // original code had a check for
  275. // symbol.find("real@") == std::string::npos)
  276. // but if this disallows memmber functions with the name real
  277. // if scalarPrefix and vectorPrefix are not found then print
  278. // the symbol
  279. if (symbol.compare(0, 4, scalarPrefix) &&
  280. symbol.compare(0, 4, vectorPrefix) )
  281. {
  282. SectChar =
  283. this->
  284. SectionHeaders[pSymbolTable->SectionNumber-1].Characteristics;
  285. if (!pSymbolTable->Type && (SectChar & IMAGE_SCN_MEM_WRITE)) {
  286. // Read only (i.e. constants) must be excluded
  287. this->DataSymbols.insert(symbol);
  288. } else {
  289. if ( pSymbolTable->Type ||
  290. !(SectChar & IMAGE_SCN_MEM_READ) ||
  291. (SectChar & IMAGE_SCN_MEM_EXECUTE)) {
  292. this->Symbols.insert(symbol);
  293. } else {
  294. // printf(" strange symbol: %s \n",symbol.c_str());
  295. }
  296. }
  297. }
  298. }
  299. }
  300. else if (pSymbolTable->SectionNumber == IMAGE_SYM_UNDEFINED &&
  301. !pSymbolTable->Type && 0) {
  302. /*
  303. * The IMPORT global variable entry points
  304. */
  305. if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
  306. symbol = stringTable + pSymbolTable->N.Name.Long;
  307. while (isspace(symbol[0])) symbol.erase(0,1);
  308. if (symbol[0] == '_') symbol.erase(0,1);
  309. this->DataSymbols.insert(symbol);
  310. }
  311. }
  312. /*
  313. * Take into account any aux symbols
  314. */
  315. i += pSymbolTable->NumberOfAuxSymbols;
  316. pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
  317. pSymbolTable++;
  318. }
  319. }
  320. private:
  321. std::set<std::string>& Symbols;
  322. std::set<std::string>& DataSymbols;
  323. DWORD_PTR SymbolCount;
  324. PIMAGE_SECTION_HEADER SectionHeaders;
  325. ObjectHeaderType* ObjectImageHeader;
  326. SymbolTableType* SymbolTable;
  327. bool Is64Bit;
  328. };
  329. bool
  330. DumpFile(const char* filename,
  331. std::set<std::string>& symbols,
  332. std::set<std::string>& dataSymbols)
  333. {
  334. HANDLE hFile;
  335. HANDLE hFileMapping;
  336. LPVOID lpFileBase;
  337. PIMAGE_DOS_HEADER dosHeader;
  338. hFile = CreateFileW(cmsys::Encoding::ToWide(filename).c_str(),
  339. GENERIC_READ, FILE_SHARE_READ, NULL,
  340. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  341. if (hFile == INVALID_HANDLE_VALUE) {
  342. fprintf(stderr, "Couldn't open file '%s' with CreateFile()\n", filename);
  343. return false;
  344. }
  345. hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  346. if (hFileMapping == 0) {
  347. CloseHandle(hFile);
  348. fprintf(stderr, "Couldn't open file mapping with CreateFileMapping()\n");
  349. return false;
  350. }
  351. lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
  352. if (lpFileBase == 0) {
  353. CloseHandle(hFileMapping);
  354. CloseHandle(hFile);
  355. fprintf(stderr, "Couldn't map view of file with MapViewOfFile()\n");
  356. return false;
  357. }
  358. dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
  359. if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
  360. fprintf(stderr, "File is an executable. I don't dump those.\n");
  361. return false;
  362. }
  363. /* Does it look like a i386 COFF OBJ file??? */
  364. else if (
  365. ((dosHeader->e_magic == IMAGE_FILE_MACHINE_I386) ||
  366. (dosHeader->e_magic == IMAGE_FILE_MACHINE_AMD64))
  367. && (dosHeader->e_sp == 0)
  368. ) {
  369. /*
  370. * The two tests above aren't what they look like. They're
  371. * really checking for IMAGE_FILE_HEADER.Machine == i386 (0x14C)
  372. * and IMAGE_FILE_HEADER.SizeOfOptionalHeader == 0;
  373. */
  374. DumpSymbols<IMAGE_FILE_HEADER, IMAGE_SYMBOL>
  375. symbolDumper((PIMAGE_FILE_HEADER) lpFileBase, symbols, dataSymbols,
  376. (dosHeader->e_magic == IMAGE_FILE_MACHINE_AMD64));
  377. symbolDumper.DumpObjFile();
  378. } else {
  379. // check for /bigobj format
  380. cmANON_OBJECT_HEADER_BIGOBJ* h =
  381. (cmANON_OBJECT_HEADER_BIGOBJ*) lpFileBase;
  382. if(h->Sig1 == 0x0 && h->Sig2 == 0xffff) {
  383. DumpSymbols<cmANON_OBJECT_HEADER_BIGOBJ, cmIMAGE_SYMBOL_EX>
  384. symbolDumper((cmANON_OBJECT_HEADER_BIGOBJ*) lpFileBase, symbols,
  385. dataSymbols,
  386. (h->Machine == IMAGE_FILE_MACHINE_AMD64));
  387. symbolDumper.DumpObjFile();
  388. } else {
  389. printf("unrecognized file format in '%s'\n", filename);
  390. return false;
  391. }
  392. }
  393. UnmapViewOfFile(lpFileBase);
  394. CloseHandle(hFileMapping);
  395. CloseHandle(hFile);
  396. return true;
  397. }
  398. bool bindexplib::AddObjectFile(const char* filename)
  399. {
  400. return DumpFile(filename, this->Symbols, this->DataSymbols);
  401. }
  402. bool bindexplib::AddDefinitionFile(const char* filename)
  403. {
  404. cmsys::ifstream infile(filename);
  405. if (!infile) {
  406. fprintf(stderr, "Couldn't open definition file '%s'\n", filename);
  407. return false;
  408. }
  409. std::string str;
  410. while (std::getline(infile, str)) {
  411. // skip the LIBRAY and EXPORTS lines (if any)
  412. if ((str.compare(0,7,"LIBRARY") == 0) ||
  413. (str.compare(0,7,"EXPORTS") == 0)) {
  414. continue;
  415. }
  416. // remove leading tabs & spaces
  417. str.erase(0, str.find_first_not_of(" \t"));
  418. std::size_t found = str.find(" \t DATA");
  419. if (found != std::string::npos) {
  420. str.erase (found, std::string::npos);
  421. this->DataSymbols.insert(str);
  422. } else {
  423. this->Symbols.insert(str);
  424. }
  425. }
  426. infile.close();
  427. return true;
  428. }
  429. void bindexplib::WriteFile(FILE* file)
  430. {
  431. fprintf(file,"EXPORTS \n");
  432. for (std::set<std::string>::const_iterator i = this->DataSymbols.begin();
  433. i != this->DataSymbols.end(); ++i) {
  434. fprintf(file, "\t%s \t DATA\n", i->c_str());
  435. }
  436. for (std::set<std::string>::const_iterator i = this->Symbols.begin();
  437. i != this->Symbols.end(); ++i) {
  438. fprintf(file, "\t%s\n", i->c_str());
  439. }
  440. }