bindexplib.cxx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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 <fstream>
  66. #include <iostream>
  67. #include <stdio.h>
  68. #include <string>
  69. #include <windows.h>
  70. typedef struct cmANON_OBJECT_HEADER_BIGOBJ {
  71. /* same as ANON_OBJECT_HEADER_V2 */
  72. WORD Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
  73. WORD Sig2; // Must be 0xffff
  74. WORD Version; // >= 2 (implies the Flags field is present)
  75. WORD Machine; // Actual machine - IMAGE_FILE_MACHINE_xxx
  76. DWORD TimeDateStamp;
  77. CLSID ClassID; // {D1BAA1C7-BAEE-4ba9-AF20-FAF66AA4DCB8}
  78. DWORD SizeOfData; // Size of data that follows the header
  79. DWORD Flags; // 0x1 -> contains metadata
  80. DWORD MetaDataSize; // Size of CLR metadata
  81. DWORD MetaDataOffset; // Offset of CLR metadata
  82. /* bigobj specifics */
  83. DWORD NumberOfSections; // extended from WORD
  84. DWORD PointerToSymbolTable;
  85. DWORD NumberOfSymbols;
  86. } cmANON_OBJECT_HEADER_BIGOBJ;
  87. typedef struct _cmIMAGE_SYMBOL_EX {
  88. union {
  89. BYTE ShortName[8];
  90. struct {
  91. DWORD Short; // if 0, use LongName
  92. DWORD Long; // offset into string table
  93. } Name;
  94. DWORD LongName[2]; // PBYTE [2]
  95. } N;
  96. DWORD Value;
  97. LONG SectionNumber;
  98. WORD Type;
  99. BYTE StorageClass;
  100. BYTE NumberOfAuxSymbols;
  101. } cmIMAGE_SYMBOL_EX;
  102. typedef cmIMAGE_SYMBOL_EX UNALIGNED *cmPIMAGE_SYMBOL_EX;
  103. PIMAGE_SECTION_HEADER GetSectionHeaderOffset(PIMAGE_FILE_HEADER
  104. pImageFileHeader)
  105. {
  106. return (PIMAGE_SECTION_HEADER)
  107. ((DWORD_PTR)pImageFileHeader +
  108. IMAGE_SIZEOF_FILE_HEADER +
  109. pImageFileHeader->SizeOfOptionalHeader);
  110. }
  111. PIMAGE_SECTION_HEADER GetSectionHeaderOffset(cmANON_OBJECT_HEADER_BIGOBJ*
  112. pImageFileHeader)
  113. {
  114. return (PIMAGE_SECTION_HEADER)
  115. ((DWORD_PTR)pImageFileHeader +
  116. sizeof(cmANON_OBJECT_HEADER_BIGOBJ));
  117. }
  118. /*
  119. + * Utility func, strstr with size
  120. + */
  121. const char* StrNStr(const char* start, const char* find, size_t &size) {
  122. size_t len;
  123. const char* hint;
  124. if (!start || !find || !size) {
  125. size = 0;
  126. return 0;
  127. }
  128. len = strlen(find);
  129. while ((hint = (const char*) memchr(start, find[0], size-len+1))) {
  130. size -= (hint - start);
  131. if (!strncmp(hint, find, len))
  132. return hint;
  133. start = hint + 1;
  134. }
  135. size = 0;
  136. return 0;
  137. }
  138. template <
  139. // cmANON_OBJECT_HEADER_BIGOBJ or IMAGE_FILE_HEADER
  140. class ObjectHeaderType,
  141. // cmPIMAGE_SYMBOL_EX or PIMAGE_SYMBOL
  142. class SymbolTableType>
  143. class DumpSymbols
  144. {
  145. public:
  146. /*
  147. *----------------------------------------------------------------------
  148. * Constructor --
  149. *
  150. * Initialize variables from pointer to object header.
  151. *
  152. *----------------------------------------------------------------------
  153. */
  154. DumpSymbols(ObjectHeaderType* ih,
  155. std::set<std::string>& symbols,
  156. std::set<std::string>& dataSymbols,
  157. bool is64)
  158. :Symbols(symbols), DataSymbols(dataSymbols)
  159. {
  160. this->ObjectImageHeader = ih;
  161. this->SymbolTable = (SymbolTableType*)
  162. ((DWORD_PTR)this->ObjectImageHeader
  163. + this->ObjectImageHeader->PointerToSymbolTable);
  164. this->SectionHeaders =
  165. GetSectionHeaderOffset(this->ObjectImageHeader);
  166. this->SymbolCount = this->ObjectImageHeader->NumberOfSymbols;
  167. this->Is64Bit = is64;
  168. }
  169. /*
  170. *----------------------------------------------------------------------
  171. * HaveExportedObjects --
  172. *
  173. * Returns true if export directives (declspec(dllexport)) exist.
  174. *
  175. *----------------------------------------------------------------------
  176. */
  177. bool HaveExportedObjects() {
  178. WORD i = 0;
  179. size_t size = 0;
  180. const char * rawdata = 0;
  181. PIMAGE_SECTION_HEADER pDirectivesSectionHeader = 0;
  182. PIMAGE_SECTION_HEADER pSectionHeaders = this->SectionHeaders;
  183. for(i = 0; (i < this->ObjectImageHeader->NumberOfSections &&
  184. !pDirectivesSectionHeader); i++)
  185. if (!strncmp((const char*)&pSectionHeaders[i].Name[0], ".drectve",8))
  186. pDirectivesSectionHeader = &pSectionHeaders[i];
  187. if (!pDirectivesSectionHeader) return 0;
  188. rawdata=(const char*)
  189. this->ObjectImageHeader+pDirectivesSectionHeader->PointerToRawData;
  190. if (!pDirectivesSectionHeader->PointerToRawData || !rawdata) return 0;
  191. size = pDirectivesSectionHeader->SizeOfRawData;
  192. const char* posImportFlag = rawdata;
  193. while ((posImportFlag = StrNStr(posImportFlag, " /EXPORT:", size))) {
  194. const char* lookingForDict = posImportFlag + 9;
  195. if (!strncmp(lookingForDict, "_G__cpp_",8) ||
  196. !strncmp(lookingForDict, "_G__set_cpp_",12)) {
  197. posImportFlag = lookingForDict;
  198. continue;
  199. }
  200. const char* lookingForDATA = posImportFlag + 9;
  201. while (*(++lookingForDATA) && *lookingForDATA != ' ');
  202. lookingForDATA -= 5;
  203. // ignore DATA exports
  204. if (strncmp(lookingForDATA, ",DATA", 5)) break;
  205. posImportFlag = lookingForDATA + 5;
  206. }
  207. if(posImportFlag) {
  208. return true;
  209. }
  210. return false;
  211. }
  212. /*
  213. *----------------------------------------------------------------------
  214. * DumpObjFile --
  215. *
  216. * Dump an object file's exported symbols.
  217. *----------------------------------------------------------------------
  218. */
  219. void DumpObjFile() {
  220. this->DumpExternalsObjects();
  221. }
  222. /*
  223. *----------------------------------------------------------------------
  224. * DumpExternalsObjects --
  225. *
  226. * Dumps a COFF symbol table from an OBJ.
  227. *----------------------------------------------------------------------
  228. */
  229. void DumpExternalsObjects() {
  230. unsigned i;
  231. PSTR stringTable;
  232. std::string symbol;
  233. DWORD SectChar;
  234. /*
  235. * The string table apparently starts right after the symbol table
  236. */
  237. stringTable = (PSTR)&this->SymbolTable[this->SymbolCount];
  238. SymbolTableType* pSymbolTable = this->SymbolTable;
  239. for ( i=0; i < this->SymbolCount; i++ ) {
  240. if (pSymbolTable->SectionNumber > 0 &&
  241. ( pSymbolTable->Type == 0x20 || pSymbolTable->Type == 0x0)) {
  242. if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
  243. /*
  244. * The name of the Function entry points
  245. */
  246. if (pSymbolTable->N.Name.Short != 0) {
  247. symbol = "";
  248. symbol.insert(0, (const char *)pSymbolTable->N.ShortName, 8);
  249. } else {
  250. symbol = stringTable + pSymbolTable->N.Name.Long;
  251. }
  252. // clear out any leading spaces
  253. while (isspace(symbol[0])) symbol.erase(0,1);
  254. // if it starts with _ and has an @ then it is a __cdecl
  255. // so remove the @ stuff for the export
  256. if(symbol[0] == '_') {
  257. std::string::size_type posAt = symbol.find('@');
  258. if (posAt != std::string::npos) {
  259. symbol.erase(posAt);
  260. }
  261. }
  262. // For 64 bit builds we don't need to remove _
  263. if(!this->Is64Bit)
  264. {
  265. if (symbol[0] == '_')
  266. {
  267. symbol.erase(0,1);
  268. }
  269. }
  270. /*
  271. Check whether it is "Scalar deleting destructor" and
  272. "Vector deleting destructor"
  273. */
  274. const char *scalarPrefix = "??_G";
  275. const char *vectorPrefix = "??_E";
  276. // original code had a check for
  277. // symbol.find("real@") == std::string::npos)
  278. // but if this disallows memmber functions with the name real
  279. // if scalarPrefix and vectorPrefix are not found then print
  280. // the symbol
  281. if (symbol.compare(0, 4, scalarPrefix) &&
  282. symbol.compare(0, 4, vectorPrefix) )
  283. {
  284. SectChar =
  285. this->
  286. SectionHeaders[pSymbolTable->SectionNumber-1].Characteristics;
  287. if (!pSymbolTable->Type && (SectChar & IMAGE_SCN_MEM_WRITE)) {
  288. // Read only (i.e. constants) must be excluded
  289. this->DataSymbols.insert(symbol);
  290. } else {
  291. if ( pSymbolTable->Type ||
  292. !(SectChar & IMAGE_SCN_MEM_READ)) {
  293. this->Symbols.insert(symbol);
  294. } else {
  295. // printf(" strange symbol: %s \n",symbol.c_str());
  296. }
  297. }
  298. }
  299. }
  300. }
  301. else if (pSymbolTable->SectionNumber == IMAGE_SYM_UNDEFINED &&
  302. !pSymbolTable->Type && 0) {
  303. /*
  304. * The IMPORT global variable entry points
  305. */
  306. if (pSymbolTable->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) {
  307. symbol = stringTable + pSymbolTable->N.Name.Long;
  308. while (isspace(symbol[0])) symbol.erase(0,1);
  309. if (symbol[0] == '_') symbol.erase(0,1);
  310. this->DataSymbols.insert(symbol);
  311. }
  312. }
  313. /*
  314. * Take into account any aux symbols
  315. */
  316. i += pSymbolTable->NumberOfAuxSymbols;
  317. pSymbolTable += pSymbolTable->NumberOfAuxSymbols;
  318. pSymbolTable++;
  319. }
  320. }
  321. private:
  322. std::set<std::string>& Symbols;
  323. std::set<std::string>& DataSymbols;
  324. DWORD_PTR SymbolCount;
  325. PIMAGE_SECTION_HEADER SectionHeaders;
  326. ObjectHeaderType* ObjectImageHeader;
  327. SymbolTableType* SymbolTable;
  328. bool Is64Bit;
  329. };
  330. bool
  331. DumpFile(const char* filename,
  332. std::set<std::string>& symbols,
  333. std::set<std::string>& dataSymbols)
  334. {
  335. HANDLE hFile;
  336. HANDLE hFileMapping;
  337. LPVOID lpFileBase;
  338. PIMAGE_DOS_HEADER dosHeader;
  339. hFile = CreateFileW(cmsys::Encoding::ToWide(filename).c_str(),
  340. GENERIC_READ, FILE_SHARE_READ, NULL,
  341. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  342. if (hFile == INVALID_HANDLE_VALUE) {
  343. fprintf(stderr, "Couldn't open file '%s' with CreateFile()\n", filename);
  344. return false;
  345. }
  346. hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  347. if (hFileMapping == 0) {
  348. CloseHandle(hFile);
  349. fprintf(stderr, "Couldn't open file mapping with CreateFileMapping()\n");
  350. return false;
  351. }
  352. lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
  353. if (lpFileBase == 0) {
  354. CloseHandle(hFileMapping);
  355. CloseHandle(hFile);
  356. fprintf(stderr, "Couldn't map view of file with MapViewOfFile()\n");
  357. return false;
  358. }
  359. dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
  360. if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE) {
  361. fprintf(stderr, "File is an executable. I don't dump those.\n");
  362. return false;
  363. }
  364. /* Does it look like a i386 COFF OBJ file??? */
  365. else if (
  366. ((dosHeader->e_magic == IMAGE_FILE_MACHINE_I386) ||
  367. (dosHeader->e_magic == IMAGE_FILE_MACHINE_AMD64))
  368. && (dosHeader->e_sp == 0)
  369. ) {
  370. /*
  371. * The two tests above aren't what they look like. They're
  372. * really checking for IMAGE_FILE_HEADER.Machine == i386 (0x14C)
  373. * and IMAGE_FILE_HEADER.SizeOfOptionalHeader == 0;
  374. */
  375. DumpSymbols<IMAGE_FILE_HEADER, IMAGE_SYMBOL>
  376. symbolDumper((PIMAGE_FILE_HEADER) lpFileBase, symbols, dataSymbols,
  377. (dosHeader->e_magic == IMAGE_FILE_MACHINE_AMD64));
  378. symbolDumper.DumpObjFile();
  379. } else {
  380. // check for /bigobj format
  381. cmANON_OBJECT_HEADER_BIGOBJ* h =
  382. (cmANON_OBJECT_HEADER_BIGOBJ*) lpFileBase;
  383. if(h->Sig1 == 0x0 && h->Sig2 == 0xffff) {
  384. DumpSymbols<cmANON_OBJECT_HEADER_BIGOBJ, cmIMAGE_SYMBOL_EX>
  385. symbolDumper((cmANON_OBJECT_HEADER_BIGOBJ*) lpFileBase, symbols,
  386. dataSymbols,
  387. (h->Machine == IMAGE_FILE_MACHINE_AMD64));
  388. symbolDumper.DumpObjFile();
  389. } else {
  390. printf("unrecognized file format in '%s'\n", filename);
  391. return false;
  392. }
  393. }
  394. UnmapViewOfFile(lpFileBase);
  395. CloseHandle(hFileMapping);
  396. CloseHandle(hFile);
  397. return true;
  398. }
  399. bool bindexplib::AddObjectFile(const char* filename)
  400. {
  401. if(!DumpFile(filename, this->Symbols, this->DataSymbols))
  402. {
  403. return false;
  404. }
  405. return true;
  406. }
  407. void bindexplib::WriteFile(FILE* file)
  408. {
  409. fprintf(file,"EXPORTS \n");
  410. for(std::set<std::string>::const_iterator i = this->DataSymbols.begin();
  411. i!= this->DataSymbols.end(); ++i)
  412. {
  413. fprintf(file, "\t%s \t DATA\n", i->c_str());
  414. }
  415. for(std::set<std::string>::const_iterator i = this->Symbols.begin();
  416. i!= this->Symbols.end(); ++i)
  417. {
  418. fprintf(file, "\t%s\n", i->c_str());
  419. }
  420. }