//**************************************************************************** | |
//** | |
//** 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 |