mirror of https://github.com/acidanthera/audk.git
450 lines
11 KiB
C++
450 lines
11 KiB
C++
//****************************************************************************
|
|
//**
|
|
//** Copyright (C) 2006 Intel Corporation. All rights reserved.
|
|
//**
|
|
//** The information and source code contained herein is the exclusive
|
|
//** property of Intel Corporation and may not be disclosed, examined
|
|
//** or reproduced in whole or in part without explicit written authorization
|
|
//** from the company.
|
|
//**
|
|
//****************************************************************************
|
|
|
|
#include <stdexcept>
|
|
#include <list>
|
|
#include <map>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <algorithm>
|
|
#include <functional>
|
|
using namespace std;
|
|
|
|
typedef unsigned __int64 ulonglong_t;
|
|
|
|
template <class T>
|
|
class CMemoryLeakChecker : public list<T*>
|
|
{
|
|
public:
|
|
static CMemoryLeakChecker<T>& GetInstance(void);
|
|
|
|
private:
|
|
CMemoryLeakChecker(void)
|
|
{
|
|
}
|
|
|
|
~CMemoryLeakChecker(void);
|
|
};
|
|
|
|
template <class T>
|
|
CMemoryLeakChecker<T>& CMemoryLeakChecker<T>::GetInstance(void)
|
|
{
|
|
static CMemoryLeakChecker<T> s_memLeakChecker;
|
|
return s_memLeakChecker;
|
|
}
|
|
|
|
template <class T>
|
|
CMemoryLeakChecker<T>::~CMemoryLeakChecker(void)
|
|
{
|
|
if (!list<T*>::empty())
|
|
throw logic_error(__FUNCTION__ ": Memory leak detected!");
|
|
}
|
|
|
|
class CObjRoot
|
|
{
|
|
protected:
|
|
CObjRoot(void);
|
|
virtual ~CObjRoot(void);
|
|
};
|
|
|
|
CObjRoot::CObjRoot(void)
|
|
{
|
|
CMemoryLeakChecker<CObjRoot>::GetInstance().push_back(this);
|
|
}
|
|
|
|
CObjRoot::~CObjRoot(void)
|
|
{
|
|
CMemoryLeakChecker<CObjRoot>::GetInstance().remove(this);
|
|
}
|
|
|
|
class CIdentity : public CObjRoot
|
|
{
|
|
public:
|
|
CIdentity(void);
|
|
CIdentity(const string&);
|
|
CIdentity(const CIdentity&);
|
|
|
|
bool operator < (const CIdentity&) const;
|
|
friend istream& operator >> (istream&, CIdentity&);
|
|
friend ostream& operator << (ostream&, const CIdentity&);
|
|
|
|
static const string::size_type s_nIdStrLen;
|
|
|
|
protected:
|
|
ulonglong_t m_ullId[2];
|
|
};
|
|
|
|
const string::size_type CIdentity::s_nIdStrLen = 36;
|
|
|
|
CIdentity::CIdentity(void)
|
|
{
|
|
memset(m_ullId, 0, sizeof(m_ullId));
|
|
}
|
|
|
|
CIdentity::CIdentity(const string& strId)
|
|
{
|
|
if (strId.length() != CIdentity::s_nIdStrLen ||
|
|
strId[8] != '-' ||
|
|
strId[13] != '-' ||
|
|
strId[18] != '-' ||
|
|
strId[23] != '-')
|
|
throw runtime_error(
|
|
__FUNCTION__ ": Error GUID format " + strId);
|
|
|
|
string strIdCopy(strId);
|
|
strIdCopy.erase(23, 1);
|
|
strIdCopy[18] = ' ';
|
|
strIdCopy.erase(13, 1);
|
|
strIdCopy.erase(8, 1);
|
|
|
|
istringstream is(strIdCopy);
|
|
is >> hex >> m_ullId[0] >> m_ullId[1];
|
|
if (!is)
|
|
throw runtime_error(
|
|
__FUNCTION__ ": GUID contains invalid characters" + strId);
|
|
}
|
|
|
|
CIdentity::CIdentity(const CIdentity& idRight)
|
|
{
|
|
memmove(m_ullId, idRight.m_ullId, sizeof(m_ullId));
|
|
}
|
|
|
|
bool CIdentity::operator < (const CIdentity& idRight) const
|
|
{
|
|
return memcmp(m_ullId, idRight.m_ullId, sizeof(m_ullId)) < 0;
|
|
}
|
|
|
|
istream& operator >> (istream& is, CIdentity& idRight)
|
|
{
|
|
string strId;
|
|
is >> strId;
|
|
if (!!is)
|
|
idRight = CIdentity(strId);
|
|
return is;
|
|
}
|
|
|
|
ostream& operator << (ostream& os, const CIdentity& idRight)
|
|
{
|
|
return os << hex << setfill('0')
|
|
<< setw(8) << (unsigned long)(idRight.m_ullId[0] >> 32) << '-'
|
|
<< setw(4) << (unsigned short)(idRight.m_ullId[0] >> 16) << '-'
|
|
<< setw(4) << (unsigned short)idRight.m_ullId[0] << '-'
|
|
<< setw(4) << (unsigned short)(idRight.m_ullId[1] >> 48) << '-'
|
|
<< setw(12) << (idRight.m_ullId[1] & 0xffffffffffff);
|
|
}
|
|
|
|
class CInputFile : public CObjRoot
|
|
{
|
|
protected:
|
|
CInputFile(const string&);
|
|
CInputFile(istream&);
|
|
istream& GetLine(string&);
|
|
|
|
private:
|
|
CInputFile(const CInputFile&);
|
|
CInputFile& operator = (const CInputFile&);
|
|
|
|
private:
|
|
auto_ptr<istream> m_pIs;
|
|
|
|
protected:
|
|
istream& m_is;
|
|
};
|
|
|
|
CInputFile::CInputFile(const string& strFName)
|
|
: m_pIs(new ifstream(strFName.c_str()))
|
|
, m_is(*m_pIs)
|
|
{
|
|
if (!m_is)
|
|
throw runtime_error(__FUNCTION__ ": Error opening input file " + strFName);
|
|
}
|
|
|
|
CInputFile::CInputFile(istream& is)
|
|
: m_is(is)
|
|
{
|
|
if (!m_is)
|
|
throw runtime_error(__FUNCTION__ ": Error opening input stream");
|
|
}
|
|
|
|
istream& CInputFile::GetLine(string& strALine)
|
|
{
|
|
if (!!m_is)
|
|
while (!!getline(m_is, strALine))
|
|
{
|
|
string::size_type pos = strALine.find_last_not_of(' ');
|
|
if (pos != string::npos)
|
|
{
|
|
strALine.erase(pos + 1);
|
|
strALine.erase(0, strALine.find_first_not_of(' '));
|
|
break;
|
|
}
|
|
}
|
|
return m_is;
|
|
}
|
|
|
|
class CIdAddressPathMap : public CInputFile, public map<CIdentity, pair<ulonglong_t, string> >
|
|
{
|
|
public:
|
|
CIdAddressPathMap(istream&);
|
|
};
|
|
|
|
CIdAddressPathMap::CIdAddressPathMap(istream& is)
|
|
: CInputFile(is)
|
|
{
|
|
key_type k;
|
|
mapped_type m;
|
|
while (!!(m_is >> hex >> k >> m.first) && !!GetLine(m.second))
|
|
if (!insert(value_type(k, m)).second)
|
|
throw runtime_error(__FUNCTION__ ": Duplicated files");
|
|
}
|
|
|
|
class CSymbol : public CObjRoot
|
|
{
|
|
public:
|
|
string m_strAddress;
|
|
string m_strName;
|
|
ulonglong_t m_ullRva;
|
|
string m_strFrom;
|
|
bool m_bStatic;
|
|
bool m_bFunction;
|
|
|
|
CSymbol()
|
|
{
|
|
}
|
|
CSymbol(const string&, bool = false);
|
|
friend ostream& operator << (ostream&, const CSymbol&);
|
|
};
|
|
|
|
CSymbol::CSymbol(const string& strALine, bool bStatic)
|
|
: m_bStatic(bStatic)
|
|
{
|
|
istringstream is(strALine);
|
|
|
|
is >> m_strAddress >> m_strName >> hex >> m_ullRva >> m_strFrom;
|
|
if (m_strFrom == "F" || m_strFrom == "f")
|
|
{
|
|
m_bFunction = true;
|
|
is >> m_strFrom;
|
|
} else m_bFunction = false;
|
|
}
|
|
|
|
ostream& operator << (ostream& os, const CSymbol& symbol)
|
|
{
|
|
os << hex << setw(16) << setfill('0') << symbol.m_ullRva << setw(0);
|
|
os << ' ' << (symbol.m_bFunction ? 'F' : ' ')
|
|
<< (symbol.m_bStatic ? 'S' : ' ') << ' ';
|
|
return os << symbol.m_strName;
|
|
}
|
|
|
|
class CMapFile : public CInputFile, public list<CSymbol>
|
|
{
|
|
public:
|
|
CMapFile(const string&);
|
|
|
|
void SetLoadAddress(ulonglong_t);
|
|
|
|
string m_strModuleName;
|
|
ulonglong_t m_ullLoadAddr;
|
|
string m_strEntryPoint;
|
|
};
|
|
|
|
CMapFile::CMapFile(const string& strFName)
|
|
: CInputFile(strFName)
|
|
{
|
|
static const char cszLoadAddr[] = "Preferred load address is";
|
|
static const char cszGlobal[] = "Address";
|
|
static const char cszEntryPoint[] = "entry point at";
|
|
static const char cszStatic[] = "Static symbols";
|
|
|
|
string strALine;
|
|
|
|
GetLine(m_strModuleName);
|
|
|
|
while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszLoadAddr) - 1, cszLoadAddr));
|
|
if (!m_is)
|
|
throw runtime_error(__FUNCTION__ ": Load Address not listed in map file");
|
|
|
|
istringstream is(strALine.substr(sizeof(cszLoadAddr) - 1));
|
|
if (!(is >> hex >> m_ullLoadAddr))
|
|
throw runtime_error(__FUNCTION__ ": Unexpected Load Address format");
|
|
|
|
while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszGlobal) - 1, cszGlobal));
|
|
if (!m_is)
|
|
throw runtime_error(__FUNCTION__ ": Global symbols not found in map file");
|
|
|
|
while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszEntryPoint) - 1, cszEntryPoint))
|
|
push_back(CSymbol(strALine));
|
|
if (!m_is)
|
|
throw runtime_error(__FUNCTION__ ": Entry Point not listed in map file");
|
|
|
|
is.str(strALine.substr(strALine.find_first_not_of(' ', sizeof(cszEntryPoint) - 1)));
|
|
is.clear();
|
|
if (!getline(is, m_strEntryPoint))
|
|
throw runtime_error(__FUNCTION__ ": Unexpected Entry Point format");
|
|
|
|
while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszStatic) - 1, cszStatic));
|
|
while (!!GetLine(strALine))
|
|
push_back(CSymbol(strALine, true));
|
|
}
|
|
|
|
void CMapFile::SetLoadAddress(ulonglong_t ullLoadAddr)
|
|
{
|
|
for (iterator i = begin(); i != end(); i++)
|
|
if (i->m_ullRva >= m_ullLoadAddr)
|
|
i->m_ullRva += ullLoadAddr - m_ullLoadAddr;
|
|
m_ullLoadAddr = ullLoadAddr;
|
|
}
|
|
|
|
class COutputFile : public CObjRoot
|
|
{
|
|
protected:
|
|
COutputFile(ostream&);
|
|
ostream& m_os;
|
|
|
|
private:
|
|
COutputFile(const COutputFile&);
|
|
COutputFile& operator = (const COutputFile&);
|
|
};
|
|
|
|
class CFvMapFile : public CObjRoot, public map<CIdentity, CMapFile*>
|
|
{
|
|
public:
|
|
CFvMapFile(const CIdAddressPathMap&);
|
|
~CFvMapFile(void);
|
|
|
|
friend ostream& operator << (ostream&, const CFvMapFile&);
|
|
|
|
private:
|
|
void Cleanup(void);
|
|
};
|
|
|
|
CFvMapFile::CFvMapFile(const CIdAddressPathMap& idAddrPath)
|
|
{
|
|
for (CIdAddressPathMap::const_iterator i = idAddrPath.begin(); i != idAddrPath.end(); i++)
|
|
{
|
|
if (i->second.second == "*")
|
|
continue;
|
|
|
|
pair<iterator, bool> r = insert(value_type(i->first,
|
|
new CMapFile(i->second.second.substr(0, i->second.second.rfind('.')) + ".map")));
|
|
r.first->second->SetLoadAddress(i->second.first);
|
|
}
|
|
}
|
|
|
|
void CFvMapFile::Cleanup(void)
|
|
{
|
|
for (iterator i = begin(); i != end(); i++)
|
|
delete i->second;
|
|
}
|
|
|
|
ostream& operator << (ostream& os, const CFvMapFile& fvMap)
|
|
{
|
|
for (CFvMapFile::const_iterator i = fvMap.begin(); !!os && i != fvMap.end(); i++)
|
|
{
|
|
CMapFile::const_iterator j = i->second->begin();
|
|
while (j != i->second->end() && j->m_strAddress != i->second->m_strEntryPoint) j++;
|
|
if (j == i->second->end())
|
|
throw runtime_error(
|
|
__FUNCTION__ ":Entry point not found for module " +
|
|
i->second->m_strModuleName);
|
|
|
|
os << hex
|
|
<< i->second->m_strModuleName
|
|
<< " (EP=" << j->m_ullRva
|
|
<< ", BA=" << i->second->m_ullLoadAddr
|
|
<< ", GUID=" << i->first
|
|
<< ")" << endl << endl;
|
|
|
|
for (j = i->second->begin(); j != i->second->end(); j++)
|
|
os << " " << *j << endl;
|
|
|
|
os << endl << endl;
|
|
}
|
|
|
|
return os;
|
|
}
|
|
|
|
CFvMapFile::~CFvMapFile(void)
|
|
{
|
|
Cleanup();
|
|
}
|
|
|
|
class CGenFvMapUsage : public invalid_argument
|
|
{
|
|
public:
|
|
CGenFvMapUsage(void) : invalid_argument(s_szUsage)
|
|
{
|
|
}
|
|
|
|
private:
|
|
static const char s_szUsage[];
|
|
};
|
|
|
|
const char CGenFvMapUsage::s_szUsage[] = "Usage: GenFvMap <LOG> <MAP>";
|
|
|
|
class CGenFvMapApp : public CObjRoot
|
|
{
|
|
public:
|
|
CGenFvMapApp(int, char *[]);
|
|
~CGenFvMapApp(void);
|
|
|
|
int Run(void);
|
|
|
|
private:
|
|
int m_cArgc;
|
|
char **m_ppszArgv;
|
|
};
|
|
|
|
CGenFvMapApp::CGenFvMapApp(int cArgc, char *ppszArgv[])
|
|
: m_cArgc(cArgc)
|
|
, m_ppszArgv(ppszArgv)
|
|
{
|
|
if (cArgc != 3)
|
|
throw CGenFvMapUsage();
|
|
}
|
|
|
|
CGenFvMapApp::~CGenFvMapApp(void)
|
|
{
|
|
}
|
|
|
|
int CGenFvMapApp::Run(void)
|
|
{
|
|
ifstream isLog(m_ppszArgv[1]);
|
|
CIdAddressPathMap idAddrPath(isLog);
|
|
CFvMapFile fvMap(idAddrPath);
|
|
|
|
ofstream osMap(m_ppszArgv[2], ios_base::out | ios_base::trunc);
|
|
osMap << fvMap;
|
|
|
|
if (!osMap)
|
|
throw runtime_error(__FUNCTION__ ": Error writing output file");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
try
|
|
{
|
|
CGenFvMapApp app(argc, argv);
|
|
return app.Run();
|
|
}
|
|
catch (const exception& e)
|
|
{
|
|
cerr << e.what() << endl;
|
|
return -1;
|
|
}
|
|
}
|