bxing 8733430b83 1. Added a new tool GenFvMap, which is able to generate FV map files upon LOG files generated by PeiRebase.
2. Updated PeiRebase to generate LOG files while processing FV images. The original MAP feature and its corresponding option '-M' are dropped, however, they are superceded by the FV map file.
3. The FV map file are not generated yet. My next check-in will update FPD files to generate FV map files.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2157 6f19259b-4bc3-4df7-8a09-765794883524
2006-12-30 09:17:16 +00:00

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;
}
}