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

508 lines
13 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&);
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;
}
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 CIdAddressMap : public CInputFile, public map<CIdentity, ulonglong_t>
{
public:
CIdAddressMap(istream&);
};
CIdAddressMap::CIdAddressMap(istream& is)
: CInputFile(is)
{
CIdentity id;
ulonglong_t ullBase;
while (!!(m_is >> hex >> id >> ullBase))
if (!insert(value_type(id, ullBase)).second)
throw runtime_error(__FUNCTION__ ": Duplicated files");
}
class CIdPathMap : public CInputFile, public map<CIdentity, string>
{
public:
CIdPathMap(istream&);
};
CIdPathMap::CIdPathMap(istream& is)
: CInputFile(is)
{
static const char cszFileSec[] = "[files]";
static const char cszFfsFile[] = "EFI_FILE_NAME";
string strALine;
// Find the [files] section
while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszFileSec) - 1, cszFileSec));
// m_is error means no FFS files listed in this INF file
if (!m_is)
return;
// Parse FFS files one by one
while (!!GetLine(strALine))
{
// Test if this begins a new section
if (strALine[0] == '[')
break;
// Is it a line of FFS file?
if (strALine.compare(0, sizeof(cszFfsFile) - 1, cszFfsFile))
continue;
string::size_type pos = strALine.find_first_not_of(' ', sizeof(cszFfsFile) - 1);
if (pos == string::npos || strALine[pos] != '=')
throw runtime_error(__FUNCTION__ ": Invalid FV INF format");
pos = strALine.find_first_not_of(' ', pos + 1);
if (pos == string::npos)
throw runtime_error(__FUNCTION__ ": Incomplete line");
strALine.erase(0, pos);
pos = strALine.rfind('\\');
if (pos == string::npos)
pos = 0;
else pos++;
CIdentity id(strALine.substr(pos, CIdentity::s_nIdStrLen));
if (!insert(value_type(id, strALine)).second)
throw runtime_error(__FUNCTION__ ": Duplicated FFS 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 << endl;
}
class CMapFile : public CInputFile, public list<CSymbol>
{
public:
CMapFile(const string&);
void SetLoadAddress(ulonglong_t);
friend ostream& operator << (ostream&, const CMapFile&);
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 != 0)
i->m_ullRva += ullLoadAddr - m_ullLoadAddr;
m_ullLoadAddr = ullLoadAddr;
}
ostream& operator << (ostream& os, const CMapFile& mapFile)
{
CMapFile::const_iterator i = mapFile.begin();
while (i != mapFile.end() && i->m_strAddress != mapFile.m_strEntryPoint)
i++;
if (i == mapFile.end())
throw runtime_error(
__FUNCTION__ ": Entry point not found for module " +
mapFile.m_strModuleName);
os << endl << hex
<< mapFile.m_strModuleName << " (EP=" << i->m_ullRva
<< ", BA=" << mapFile.m_ullLoadAddr << ')' << endl
<< endl;
for (i = mapFile.begin(); i != mapFile.end(); i++)
os << " " << *i;
return os << endl;
}
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 CIdAddressMap&, const CIdPathMap&);
~CFvMapFile(void);
friend ostream& operator << (ostream&, const CFvMapFile&);
private:
void Cleanup(void);
};
CFvMapFile::CFvMapFile(const CIdAddressMap& idAddr, const CIdPathMap& idPath)
{
for (CIdAddressMap::const_iterator i = idAddr.begin(); i != idAddr.end(); i++)
{
CIdPathMap::const_iterator j = idPath.find(i->first);
if (j == idPath.end())
throw runtime_error(__FUNCTION__ ": Map file not found");
try
{
pair<iterator, bool> k = insert(value_type(i->first,
new CMapFile(j->second.substr(0, j->second.rfind('.')) + ".map")));
if (!k.second)
throw logic_error(__FUNCTION__ ": Duplicated file found in rebase log");
k.first->second->SetLoadAddress(i->second);
}
catch (const runtime_error& e)
{
cerr << e.what() << endl;
}
}
}
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++)
os << *i->second;
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> <INF> <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 != 4)
throw CGenFvMapUsage();
}
CGenFvMapApp::~CGenFvMapApp(void)
{
}
int CGenFvMapApp::Run(void)
{
ifstream isLog(m_ppszArgv[1]);
ifstream isInf(m_ppszArgv[2]);
CIdAddressMap idAddress(isLog);
CIdPathMap idPath(isInf);
CFvMapFile fvMap(idAddress, idPath);
ofstream osMap(m_ppszArgv[3], 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;
}
}