bindexplib.cxx 15 KB

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