bindexplib.cxx 14 KB

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