mirror of https://github.com/acidanthera/audk.git
667 lines
17 KiB
C++
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
|