Heh, I was just going to kick this thread with the code of my just written tool, when I saw your reaction. Too late
I wrote this in just a few minutes, it "parses" the .map files that you give on the command-line, and outputs the difference between the sets to standard out, while undecorating the symbol names. Alas, no comments, but it should be easy to understand as it relies heavily on the STL and it's algorithms.
.edit: some bugfixes, and eliminates all std:: stuff and literals that need memory (like strings and floats). Now sorts by identifier instead of decorated name, and displays only the part of a symbol that makes sense (identifier and function signature, no more static/virtual/__thiscall crap or function return types)
#include <iostream>
#include <fstream>
#include <set>
#include <algorithm>
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
#include <windows.h>
#include <Dbghelp.h>
#pragma comment(lib, "dbghelp.lib")
struct symbol
{
std::string name;
std::string object;
std::string nameOnly;
symbol() { }
symbol(const std::string & name, const std::string & object) : name(name), object(object)
{
static char buf[1024];
UnDecorateSymbolName(name.c_str(), buf, sizeof(buf), UNDNAME_NAME_ONLY);
nameOnly = buf;
}
bool operator < (const symbol & r) const
{
return name < r.name;
}
std::string UndecoratedName() const
{
static char buf[1024];
UnDecorateSymbolName(name.c_str(), buf, sizeof(buf), UNDNAME_NO_ALLOCATION_LANGUAGE | UNDNAME_NO_ACCESS_SPECIFIERS | UNDNAME_NO_FUNCTION_RETURNS | UNDNAME_NO_MEMBER_TYPE);
return buf;
}
};
void read(std::set<symbol> & s, const char * file)
{
std::ifstream f(file);
std::string line;
while (std::getline(f, line))
if (!line.compare(0, 9, " Address"))
break;
if (!f)
return;
std::vector<std::string> words;
while (std::getline(f, line))
{
words.clear();
std::istringstream lineStream(line);
std::copy(std::istream_iterator<std::string>(lineStream), std::istream_iterator<std::string>(), std::back_inserter(words));
if (words.size() < 4)
continue;
symbol sym(words[1], words.back());
if (sym.nameOnly.empty() ||
sym.nameOnly[0] == '$' ||
!sym.nameOnly.compare(0, 5, "std::") ||
!sym.nameOnly.compare(0, 8, "`string'"))
continue;
s.insert(sym);
}
}
bool sortbyundecoratedname(const symbol & l, const symbol & r)
{
if (l.nameOnly != r.nameOnly)
return l.nameOnly < r.nameOnly;
return l < r;
}
void outputsymbol (const symbol & s)
{
std::cout << s.UndecoratedName() << " [" << s.object << "]" << std::endl;
}
int main(int argc, char ** argv)
{
if (argc < 3)
{
std::cout << "usage: " << argv[0] << " [mapfile1] [mapfile2]" << std::endl;
return 0;
}
std::set<symbol> s1, s2;
read(s1, argv[1]);
read(s2, argv[2]);
std::vector<symbol> diff;
std::set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), std::back_inserter(diff));
std::sort(diff.begin(), diff.end(), sortbyundecoratedname);
std::for_each(diff.begin(), diff.end(), outputsymbol);
}