audk/Tools/CCode/Source/GenFvMap/GenFvMap.cpp

667 lines
17 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 <cstdio>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdexcept>
#include <set>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
#include "ProcessorBind.h"
class putUINT64
{
public:
putUINT64(UINT64 ullVal) : m_ull(ullVal) {}
putUINT64(const putUINT64& r) : m_ull(r.m_ull) {}
template <class _E, class _Tr>
friend basic_ostream<_E, _Tr>& operator << (basic_ostream<_E, _Tr>&, putUINT64);
private:
UINT64 m_ull;
};
template <class _E, class _Tr>
basic_ostream<_E, _Tr>& operator << (basic_ostream<_E, _Tr>& os, putUINT64 ull)
{
static const char cDigits[] = "0123456789abcdef";
UINT64 base = 10;
if (os.flags() & ios_base::hex)
base = 16;
else if (os.flags() & ios_base::oct)
base = 8;
ostringstream ostr;
UINT64 ullVal = ull.m_ull;
while (ullVal != 0)
{
ostr << cDigits[ullVal % base];
ullVal /= base;
}
string s1(ostr.str());
string s2(s1.rbegin(), s1.rend());
return os << s2;
}
class getUINT64
{
public:
getUINT64(UINT64& ullVal) : m_ull(ullVal) {}
getUINT64(const getUINT64& r) : m_ull(r.m_ull) {}
template <class _E, class _Tr>
friend basic_istream<_E, _Tr>& operator >> (basic_istream<_E, _Tr>&, getUINT64);
private:
UINT64& m_ull;
private:
getUINT64& operator = (const getUINT64&);
};
template <class _E, class _Tr>
basic_istream<_E, _Tr>& operator >> (basic_istream<_E, _Tr>& is, getUINT64 ull)
{
string strBuf;
is >> strBuf;
UINT64 base = 10;
if (is.flags() & ios_base::hex)
base = 16;
else if (is.flags() & ios_base::oct)
base = 8;
UINT64 ullVal = 0;
for (string::iterator i = strBuf.begin(); i != strBuf.end(); i++)
{
if (*i <= '9' && *i >= '0')
*i -= '0';
else if (*i <= 'F' && *i >= 'A')
*i -= 'A' - '\x0a';
else if (*i <= 'f' && *i >= 'a')
*i -= 'a' - '\x0a';
else throw runtime_error("Invalid number format");
ullVal = ullVal * base + *i;
}
ull.m_ull = ullVal;
return is;
}
class EMemoryLeak : public logic_error
{
public:
EMemoryLeak() : logic_error("Memory leak detected") {}
};
class EInvalidGuidString : public invalid_argument
{
public:
EInvalidGuidString() : invalid_argument("Unexpected format of GUID string") {}
};
class ELogFileError : public logic_error
{
public:
ELogFileError(const string& strMsg) : logic_error(strMsg) {}
};
class EDuplicatedFfsFile : public ELogFileError
{
public:
EDuplicatedFfsFile() : ELogFileError("Duplicated FFS found in LOG file") {}
};
class EUnexpectedLogFileToken : public ELogFileError
{
public:
EUnexpectedLogFileToken() : ELogFileError("Unexpected LOG file token") {}
};
class EFileNotFound : public invalid_argument
{
public:
EFileNotFound(const string& strFName) : invalid_argument("File not found - " + strFName) {}
};
class EUnexpectedMapFile : public logic_error
{
public:
EUnexpectedMapFile(const string& strKeyWord) : logic_error("Unexpected map file format - " + strKeyWord) {}
};
class EUsage : public invalid_argument
{
public:
EUsage() : invalid_argument("Usage: GenFvMap <FV.LOG> <FV.INF> <FV.MAP>") {}
};
template <class T>
class CMemoryLeakChecker : public set<T*>
{
protected:
CMemoryLeakChecker()
{
}
public:
virtual ~CMemoryLeakChecker();
static CMemoryLeakChecker<T>& GetInstance();
private:
CMemoryLeakChecker(const CMemoryLeakChecker<T>&);
};
template <class T>
CMemoryLeakChecker<T>::~CMemoryLeakChecker()
{
if (!CMemoryLeakChecker<T>::empty())
throw EMemoryLeak();
}
template <class T>
CMemoryLeakChecker<T>& CMemoryLeakChecker<T>::GetInstance()
{
static CMemoryLeakChecker<T> s_instance;
return s_instance;
}
class CObjRoot
{
protected:
CObjRoot()
{
#ifdef _CHK_MEM_LEAK
CMemoryLeakChecker<CObjRoot>::GetInstance().insert(this);
#endif
}
public:
virtual ~CObjRoot()
{
#ifdef _CHK_MEM_LEAK
CMemoryLeakChecker<CObjRoot>::GetInstance().erase(this);
#endif
}
private:
CObjRoot(const CObjRoot&);
};
class CIdentity : public CObjRoot
{
public:
CIdentity(const string&);
operator string (void) const;
bool operator < (const CIdentity& id) const
{
return memcmp(this, &id, sizeof(*this)) < 0;
}
CIdentity() : ulD1(0), wD2(0), wD3(0), wD4(0), ullD5(0)
{
}
CIdentity(const CIdentity& r) : ulD1(r.ulD1), wD2(r.wD2), wD3(r.wD3), wD4(r.wD4), ullD5(r.ullD5)
{
}
template <class _E, class _Tr>
basic_istream<_E, _Tr>& ReadId(basic_istream<_E, _Tr>&);
template <class _E, class _Tr>
basic_ostream<_E, _Tr>& WriteId(basic_ostream<_E, _Tr>&);
template <class _E, class _Tr>
friend basic_istream<_E, _Tr>& operator >> (basic_istream<_E, _Tr>&, CIdentity&);
template <class _E, class _Tr>
friend basic_ostream<_E, _Tr>& operator << (basic_ostream<_E, _Tr>&, CIdentity);
private:
UINT32 ulD1;
UINT16 wD2, wD3, wD4;
UINT64 ullD5;
};
CIdentity::CIdentity(const string& strGuid)
{
try
{
string str(strGuid);
str.erase(0, str.find_first_not_of(" {"));
str.resize(str.find_last_not_of(" }") + 1);
str[str.find('-')] = ' ';
str[str.find('-')] = ' ';
str[str.find('-')] = ' ';
str[str.find('-')] = ' ';
istringstream is(str);
is >> hex >> ulD1 >> wD2 >> wD3 >> wD4 >> getUINT64(ullD5);
}
catch (const exception&)
{
throw EInvalidGuidString();
}
}
CIdentity::operator string(void) const
{
ostringstream os;
os << hex << setfill('0')
<< setw(8) << ulD1 << '-'
<< setw(4) << wD2 << '-'
<< setw(4) << wD3 << '-'
<< setw(4) << wD4 << '-'
<< setw(12) << putUINT64(ullD5);
return os.str();
}
template <class _E, class _Tr>
basic_istream<_E, _Tr>& CIdentity::ReadId(basic_istream<_E, _Tr>& is)
{
string str;
if (!!(is >> str))
*this = CIdentity(str);
return is;
}
template <class _E, class _Tr>
basic_ostream<_E, _Tr>& CIdentity::WriteId(basic_ostream<_E, _Tr>& os)
{
return os << (string)(*this);
}
template <class _E, class _Tr>
basic_istream<_E, _Tr>& operator >> (basic_istream<_E, _Tr>& is, CIdentity& id)
{
return id.ReadId(is);
}
template <class _E, class _Tr>
basic_ostream<_E, _Tr>& operator << (basic_ostream<_E, _Tr>& os, CIdentity id)
{
return id.WriteId(os);
}
template <class T>
class IVectorContainerByReference : virtual public CObjRoot, public vector<T*>
{
};
template <class T>
class IMapContainer : virtual public CObjRoot, public map<CIdentity, T>
{
};
struct ISymbol : virtual public CObjRoot
{
string strAddress;
string strName;
string strFrom;
UINT64 ullRva;
bool bStatic;
bool bFunction;
virtual void Relocate(UINT64)=0;
};
class IModule : public IVectorContainerByReference<ISymbol>
{
public:
string strName;
CIdentity id;
virtual UINT64 BaseAddress(void) const=0;
virtual UINT64 BaseAddress(UINT64)=0;
virtual const ISymbol *EntryPoint(void) const=0;
};
class IFirmwareVolume : public IVectorContainerByReference<IModule>
{
};
class IMapFileSet : public IMapContainer<istream*>
{
};
class IFfsSet : public IMapContainer<UINT64>
{
};
class CFfsSetFromLogFile : public IFfsSet
{
public:
CFfsSetFromLogFile(const string&);
};
CFfsSetFromLogFile::CFfsSetFromLogFile(const string& strFName)
{
ifstream ifs(strFName.c_str());
if (!ifs)
throw EFileNotFound(strFName);
CIdentity ffsId;
while (!!ffsId.ReadId(ifs))
{
UINT64 ullBase;
if (!(ifs >> hex >> getUINT64(ullBase)))
throw EUnexpectedLogFileToken();
if (!insert(value_type(ffsId, ullBase)).second)
throw EDuplicatedFfsFile();
}
}
class CMapFileSetFromInfFile : public IMapFileSet
{
public:
CMapFileSetFromInfFile(const string&);
~CMapFileSetFromInfFile();
};
CMapFileSetFromInfFile::CMapFileSetFromInfFile(const string& strFName)
{
static const char cszEfiFileName[] = "EFI_FILE_NAME";
ifstream ifs(strFName.c_str());
if (!ifs)
throw EFileNotFound(strFName);
string strFile;
getline(ifs, strFile, ifstream::traits_type::to_char_type(ifstream::traits_type::eof()));
strFile.erase(0, strFile.find("[files]"));
istringstream is(strFile);
string strTmp;
while (!!getline(is, strTmp))
{
string::size_type pos = strTmp.find(cszEfiFileName);
if (pos == string::npos)
continue;
strTmp.erase(0, strTmp.find_first_not_of(" =", pos + sizeof(cszEfiFileName) - 1));
pos = strTmp.find_last_of("\\/");
string strId(
strTmp.begin() + pos + 1,
strTmp.begin() + strTmp.find('-', strTmp.find('-', strTmp.find('-', strTmp.find('-', strTmp.find('-') + 1) + 1) + 1) + 1)
);
strTmp.erase(pos + 1, strId.length() + 1);
strTmp.replace(strTmp.rfind('.'), string::npos, ".map");
istream *ifmaps = new ifstream(strTmp.c_str());
if (ifmaps && !!*ifmaps &&
!insert(value_type(CIdentity(strId), ifmaps)).second)
throw EDuplicatedFfsFile();
}
}
CMapFileSetFromInfFile::~CMapFileSetFromInfFile()
{
for (iterator i = begin(); i != end(); i++)
delete i->second;
}
class CSymbolFromString : public ISymbol
{
public:
CSymbolFromString(const string&, bool = false);
void Relocate(UINT64);
};
CSymbolFromString::CSymbolFromString(const string& strSymbol, bool b)
{
bStatic = b;
istringstream is(strSymbol);
is >> strAddress >> strName >> hex >> getUINT64(ullRva) >> strFrom;
if (strFrom == "f")
{
bFunction = true;
is >> strFrom;
}
else bFunction = false;
if (!is)
throw EUnexpectedMapFile("Symbol line format");
}
void CSymbolFromString::Relocate(UINT64 ullDelta)
{
if (ullRva > 0)
ullRva += ullDelta;
}
class CModuleFromMap : public IModule
{
public:
CModuleFromMap(istream&);
~CModuleFromMap();
UINT64 BaseAddress() const;
UINT64 BaseAddress(UINT64);
const ISymbol *EntryPoint() const;
private:
UINT64 m_ullLoadAddress;
iterator m_iEntryPoint;
static pair<string, string::size_type> FindToken(istream&, const string&);
};
pair<string, string::size_type> CModuleFromMap::FindToken(istream& is, const string& strToken)
{
for (string strTmp; !!getline(is, strTmp);)
{
string::size_type pos = strTmp.find(strToken);
if (pos != string::npos)
return pair<string, string::size_type>(strTmp, pos);
}
throw EUnexpectedMapFile(strToken);
}
CModuleFromMap::CModuleFromMap(istream& imaps)
{
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";
pair<string, string::size_type> pairTmp;
istringstream iss;
getline(imaps, strName);
strName.erase(0, strName.find_first_not_of(' '));
pairTmp = FindToken(imaps, cszLoadAddr);
iss.str(pairTmp.first.substr(pairTmp.second + sizeof(cszLoadAddr) - 1));
iss >> getUINT64(m_ullLoadAddress);
pairTmp = FindToken(imaps, cszGlobal);
while (!!getline(imaps, pairTmp.first) &&
pairTmp.first.find(cszEntryPoint) == string::npos)
if (pairTmp.first.find_first_not_of(' ') != string::npos)
push_back(new CSymbolFromString(pairTmp.first));
iss.str(pairTmp.first.substr(pairTmp.first.find(cszEntryPoint) + sizeof(cszEntryPoint) - 1));
iss.clear();
string strEntryPoint;
iss >> strEntryPoint;
pairTmp = FindToken(imaps, cszStatic);
if (pairTmp.second)
while (!!getline(imaps, pairTmp.first))
if (pairTmp.first.find_first_not_of(' ') != string::npos)
push_back(new CSymbolFromString(pairTmp.first, true));
for (m_iEntryPoint = begin();
m_iEntryPoint != end() && (*m_iEntryPoint)->strAddress != strEntryPoint;
m_iEntryPoint++);
if (m_iEntryPoint == end())
throw EUnexpectedMapFile("Entry point not found");
}
CModuleFromMap::~CModuleFromMap()
{
for (iterator i = begin(); i != end(); i++)
delete *i;
}
UINT64 CModuleFromMap::BaseAddress(void) const
{
return m_ullLoadAddress;
}
UINT64 CModuleFromMap::BaseAddress(UINT64 ullNewBase)
{
ullNewBase -= m_ullLoadAddress;
for (iterator i = begin(); i != end(); i++)
(*i)->Relocate(ullNewBase);
m_ullLoadAddress += ullNewBase;
return m_ullLoadAddress - ullNewBase;
}
const ISymbol *CModuleFromMap::EntryPoint(void) const
{
return *m_iEntryPoint;
}
class CFvMap : public IFirmwareVolume
{
public:
CFvMap(IFfsSet*, IMapFileSet*);
~CFvMap();
private:
CFvMap(const CFvMap&);
};
CFvMap::CFvMap(IFfsSet *pFfsSet, IMapFileSet *pMapSet)
{
for (IFfsSet::iterator i = pFfsSet->begin(); i != pFfsSet->end(); i++)
{
IMapFileSet::iterator j = pMapSet->find(i->first);
if (j != pMapSet->end())
{
IModule *pModule = new CModuleFromMap(*j->second);
pModule->id = i->first;
pModule->BaseAddress(i->second);
push_back(pModule);
}
}
}
CFvMap::~CFvMap()
{
for (iterator i = begin(); i != end(); i++)
delete *i;
}
class CFvMapGenerator : public CObjRoot
{
public:
CFvMapGenerator(const IFirmwareVolume *pFv) : m_pFv(pFv) {}
CFvMapGenerator(const CFvMapGenerator& r) : m_pFv(r.m_pFv) {}
template <class _E, class _Tr>
friend basic_ostream<_E, _Tr>& operator << (basic_ostream<_E, _Tr>&, CFvMapGenerator);
private:
static bool Less(const IModule*, const IModule*);
private:
const IFirmwareVolume *m_pFv;
};
template <class _E, class _Tr>
basic_ostream<_E, _Tr>& operator << (basic_ostream<_E, _Tr>& os, CFvMapGenerator fvMapFmt)
{
vector<IModule*> rgMods(fvMapFmt.m_pFv->begin(), fvMapFmt.m_pFv->end());
sort(rgMods.begin(), rgMods.end(), CFvMapGenerator::Less);
for (vector<IModule*>::iterator i = rgMods.begin(); i != rgMods.end(); i++)
{
os << (*i)->strName << hex << " (BaseAddress=" << putUINT64((*i)->BaseAddress());
os << ", EntryPoint=" << hex << putUINT64((*i)->EntryPoint()->ullRva);
os << ", GUID=";
(*i)->id.WriteId(os);
os << ")" << endl << endl;
for (IModule::iterator j = (*i)->begin(); j != (*i)->end(); j++)
{
os << hex << " " << setw(16) << setfill('0') << putUINT64((*j)->ullRva);
os << ((*j)->bFunction ? " F" : " ")
<< ((*j)->bStatic ? "S " : " ")
<< (*j)->strName << endl;
}
os << endl << endl;
}
return os;
}
bool CFvMapGenerator::Less(const IModule *pModL, const IModule *pModR)
{
return pModL->BaseAddress() < pModR->BaseAddress();
}
class CApplication : public CObjRoot
{
public:
CApplication(int, char**);
int Run(void);
private:
char **m_ppszArg;
private:
CApplication(const CApplication&);
};
CApplication::CApplication(int cArg, char *ppszArg[])
: m_ppszArg(ppszArg)
{
if (cArg != 4)
throw EUsage();
}
int CApplication::Run(void)
{
CFfsSetFromLogFile ffsSet(m_ppszArg[1]);
CMapFileSetFromInfFile mapSet(m_ppszArg[2]);
ofstream ofs(m_ppszArg[3]);
CFvMap fvMap(&ffsSet, &mapSet);
ofs << CFvMapGenerator(&fvMap);
return 0;
}
int main(int argc, char *argv[])
{
try
{
CApplication app(argc, argv);
return app.Run();
}
catch (const exception& e)
{
cerr << e.what() << endl;
return -1;
}
}
#ifdef _DDK3790x1830_WORKAROUND
extern "C" void __fastcall __security_check_cookie(int)
{
}
#endif