summaryrefslogtreecommitdiff
path: root/TestPrograms/dump2def.cxx
blob: 4fbdd5dc4eb847c53ebfe449f318a374c67619ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// dump2def.cxx - Written and placed in public domain by Jeffrey Walton
//                Create a module definitions file from a dumpbin file.
//                dump2def can be used to create a list of exports from
//                a static library. Then, the exports can used to build
//                a dynamic link library with the same exports.
//
//    The workflow for Crypto++ is:
//
//      1. Open a Developer Prompt
//      2. CD to cryptopp/ directory
//      3. nmake /f cryptest.nmake cryptopp.dll
//
//    The cryptopp.dll recipe first builds cryptlib.lib. Then it calls
//    dumpbin.exe to export all symbols from cryptlib.lib and writes them
//    to cryptopp.dump. The recipe then calls dump2def.exe to create a
//    module definition file. Finally, the recipe builds cryptopp.dll
//    using the module definition file cryptopp.def. The linker creates
//    the import lib cryptopp.lib and export cryptopp.exp automatically.
//
//    This is only "half the problem solved" for those who wish to use
//    a DLL. The program must import the import lib cryptopp.lib. Then
//    the program must ensure the library headers export the symbol or
//    class with CRYPTOPP_DLL. CRYPTOPP_DLL is only present on some classes
//    because the FIPS module only allowed approved algorithms like AES and
//    SHA. Other classes like Base64Encoder and HexEncoder lack CRYPTOPP_DLL.
//
//    CRYPTOPP_DLL simply adds declspec(dllimport) when CRYPTOPP_IMPORTS is
//    defined. The limitation of requiring declspec(dllimport) is imposed by
//    Microsoft. Microsoft does not allow a program to "import everything".
//
//    If you would like to read more about the FIPS module and the pain it
//    causes then see https://www.cryptopp.com/wiki/FIPS_DLL. In fact we
//    recommend you delete the CryptDll and DllTest projects from the
//    Visual Studio solution file.

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <set>

// Friendly name
#define LIBRARY_NAME "Crypto++ Library"
typedef std::set<std::string> SymbolMap;

void PrintHelpAndExit(int code)
{
	std::cout << "dump2def - create a module definitions file from a dumpbin file" << std::endl;
	std::cout << "           Written and placed in public domain by Jeffrey Walton" << std::endl;
	std::cout << std::endl;

	std::cout << "Usage: " << std::endl;

	std::cout << "  dump2def <infile>" << std::endl;
	std::cout << "    - Create a def file from <infile> and write it to a file with" << std::endl;
	std::cout << "      the same name as <infile> but using the .def extension" << std::endl;

	std::cout << "  dump2def <infile> <outfile>" << std::endl;
	std::cout << "    - Create a def file from <infile> and write it to <outfile>" << std::endl;

	std::exit(code);
}

int main(int argc, char* argv[])
{
	// ******************** Handle Options ******************** //

	// Convenience item
	std::vector<std::string> opts;
	for (size_t i=0; i<argc; ++i)
		opts.push_back(argv[i]);

	// Look for help
	std::string opt = opts.size() < 3 ? "" : opts[1].substr(0,2);
	if (opt == "/h" || opt == "-h" || opt == "/?" || opt == "-?")
		PrintHelpAndExit(0);

	// Add <outfile> as needed
	if (opts.size() == 2)
	{
		std::string outfile = opts[1];
		std::string::size_type pos = outfile.length() < 5 ? std::string::npos : outfile.length() - 5;
		if (pos == std::string::npos || outfile.substr(pos) != ".dump")
			PrintHelpAndExit(1);

		outfile.replace(pos, 5, ".def");
		opts.push_back(outfile);
	}

	// Check or exit
	if (opts.size() != 3)
		PrintHelpAndExit(1);

	// ******************** Read MAP file ******************** //

	SymbolMap symbols;

	try
	{
		std::ifstream infile(opts[1].c_str());
		std::string::size_type pos;
		std::string line;

		// Find start of the symbol table
		while (std::getline(infile, line))
		{
			pos = line.find("public symbols");
			if (pos == std::string::npos) { continue; }

			// Eat the whitespace after the table heading
			infile >> std::ws;
			break;
		}

		while (std::getline(infile, line))
		{
			// End of table
			if (line.empty()) { break; }

			std::istringstream iss(line);
			std::string address, symbol;
			iss >> address >> symbol;

			symbols.insert(symbol);
		}
	}
	catch (const std::exception& ex)
	{
		std::cerr << "Unexpected exception:" << std::endl;
		std::cerr << ex.what() << std::endl;
		std::cerr << std::endl;

		PrintHelpAndExit(1);
	}

	// ******************** Write DEF file ******************** //

	try
	{
		std::ofstream outfile(opts[2].c_str());

		// Library name, cryptopp.dll
		std::string name = opts[2];
		std::string::size_type pos = name.find_last_of(".");

		if (pos != std::string::npos)
			name.erase(pos);

		outfile << "LIBRARY " << name << std::endl;
		outfile << "DESCRIPTION \"" << LIBRARY_NAME << "\"" << std::endl;
		outfile << "EXPORTS" << std::endl;
		outfile << std::endl;

		outfile << "\t;; " << symbols.size() << " symbols" << std::endl;

		// Symbols from our object files
		SymbolMap::const_iterator it = symbols.begin();
		for ( ; it != symbols.end(); ++it)
			outfile << "\t" << *it << std::endl;
	}
	catch (const std::exception& ex)
	{
		std::cerr << "Unexpected exception:" << std::endl;
		std::cerr << ex.what() << std::endl;
		std::cerr << std::endl;

		PrintHelpAndExit(1);
	}

	return 0;
}