]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Tools/CCode/Source/GenFvMap/GenFvMap.cpp
1. Added a new tool GenFvMap, which is able to generate FV map files upon LOG files...
[mirror_edk2.git] / Tools / CCode / Source / GenFvMap / GenFvMap.cpp
diff --git a/Tools/CCode/Source/GenFvMap/GenFvMap.cpp b/Tools/CCode/Source/GenFvMap/GenFvMap.cpp
new file mode 100644 (file)
index 0000000..4a8c726
--- /dev/null
@@ -0,0 +1,507 @@
+//****************************************************************************\r
+//**\r
+//**  Copyright  (C) 2006 Intel Corporation. All rights reserved. \r
+//**\r
+//** The information and source code contained herein is the exclusive \r
+//** property of Intel Corporation and may not be disclosed, examined\r
+//** or reproduced in whole or in part without explicit written authorization \r
+//** from the company.\r
+//**\r
+//****************************************************************************\r
+\r
+#include <stdexcept>\r
+#include <list>\r
+#include <map>\r
+#include <iostream>\r
+#include <iomanip>\r
+#include <fstream>\r
+#include <sstream>\r
+#include <string>\r
+#include <utility>\r
+#include <algorithm>\r
+#include <functional>\r
+using namespace std;\r
+\r
+typedef unsigned __int64 ulonglong_t;\r
+\r
+template <class T>\r
+class CMemoryLeakChecker : public list<T*>\r
+{\r
+public:\r
+    static CMemoryLeakChecker<T>& GetInstance(void);\r
+\r
+private:\r
+    CMemoryLeakChecker(void)\r
+    {\r
+    }\r
+\r
+    ~CMemoryLeakChecker(void);\r
+};\r
+\r
+template <class T>\r
+CMemoryLeakChecker<T>& CMemoryLeakChecker<T>::GetInstance(void)\r
+{\r
+    static CMemoryLeakChecker<T> s_memLeakChecker;\r
+    return s_memLeakChecker;\r
+}\r
+\r
+template <class T>\r
+CMemoryLeakChecker<T>::~CMemoryLeakChecker(void)\r
+{\r
+    if (!list<T*>::empty())\r
+        throw logic_error(__FUNCTION__ ": Memory leak detected!");\r
+}\r
+\r
+class CObjRoot\r
+{\r
+protected:\r
+    CObjRoot(void);\r
+    virtual ~CObjRoot(void);\r
+};\r
+\r
+CObjRoot::CObjRoot(void)\r
+{\r
+    CMemoryLeakChecker<CObjRoot>::GetInstance().push_back(this);\r
+}\r
+\r
+CObjRoot::~CObjRoot(void)\r
+{\r
+    CMemoryLeakChecker<CObjRoot>::GetInstance().remove(this);\r
+}\r
+\r
+class CIdentity : public CObjRoot\r
+{\r
+public:\r
+    CIdentity(void);\r
+    CIdentity(const string&);\r
+    CIdentity(const CIdentity&);\r
+\r
+    bool operator < (const CIdentity&) const;\r
+    friend istream& operator >> (istream&, CIdentity&);\r
+\r
+    static const string::size_type s_nIdStrLen;\r
+\r
+protected:\r
+    ulonglong_t m_ullId[2];\r
+};\r
+\r
+const string::size_type CIdentity::s_nIdStrLen = 36;\r
+\r
+CIdentity::CIdentity(void)\r
+{\r
+    memset(m_ullId, 0, sizeof(m_ullId));\r
+}\r
+\r
+CIdentity::CIdentity(const string& strId)\r
+{\r
+    if (strId.length() != CIdentity::s_nIdStrLen ||\r
+        strId[8] != '-' ||\r
+        strId[13] != '-' ||\r
+        strId[18] != '-' ||\r
+        strId[23] != '-')\r
+        throw runtime_error(\r
+            __FUNCTION__ ": Error GUID format " + strId);\r
+\r
+    string strIdCopy(strId);\r
+    strIdCopy.erase(23, 1);\r
+    strIdCopy[18] = ' ';\r
+    strIdCopy.erase(13, 1);\r
+    strIdCopy.erase(8, 1);\r
+\r
+    istringstream is(strIdCopy);\r
+    is >> hex >> m_ullId[0] >> m_ullId[1];\r
+    if (!is)\r
+        throw runtime_error(\r
+            __FUNCTION__ ": GUID contains invalid characters" + strId);\r
+}\r
+\r
+CIdentity::CIdentity(const CIdentity& idRight)\r
+{\r
+    memmove(m_ullId, idRight.m_ullId, sizeof(m_ullId));\r
+}\r
+\r
+bool CIdentity::operator < (const CIdentity& idRight) const\r
+{\r
+    return memcmp(m_ullId, idRight.m_ullId, sizeof(m_ullId)) < 0;\r
+}\r
+\r
+istream& operator >> (istream& is, CIdentity& idRight)\r
+{\r
+    string strId;\r
+    is >> strId;\r
+    if (!!is)\r
+        idRight = CIdentity(strId);\r
+    return is;\r
+}\r
+\r
+class CInputFile : public CObjRoot\r
+{\r
+protected:\r
+    CInputFile(const string&);\r
+    CInputFile(istream&);\r
+    istream& GetLine(string&);\r
+\r
+private:\r
+    CInputFile(const CInputFile&);\r
+    CInputFile& operator = (const CInputFile&);\r
+\r
+private:\r
+    auto_ptr<istream> m_pIs;\r
+\r
+protected:\r
+    istream& m_is;\r
+};\r
+\r
+CInputFile::CInputFile(const string& strFName)\r
+: m_pIs(new ifstream(strFName.c_str()))\r
+, m_is(*m_pIs)\r
+{\r
+    if (!m_is)\r
+        throw runtime_error(__FUNCTION__ ": Error opening input file " + strFName);\r
+}\r
+\r
+CInputFile::CInputFile(istream& is)\r
+: m_is(is)\r
+{\r
+    if (!m_is)\r
+        throw runtime_error(__FUNCTION__ ": Error opening input stream");\r
+}\r
+\r
+istream& CInputFile::GetLine(string& strALine)\r
+{\r
+    if (!!m_is)\r
+        while (!!getline(m_is, strALine))\r
+        {\r
+            string::size_type pos = strALine.find_last_not_of(' ');\r
+            if (pos != string::npos)\r
+            {\r
+                strALine.erase(pos + 1);\r
+                strALine.erase(0, strALine.find_first_not_of(' '));\r
+                break;\r
+            }\r
+        }\r
+    return m_is;\r
+}\r
+\r
+class CIdAddressMap : public CInputFile, public map<CIdentity, ulonglong_t>\r
+{\r
+public:\r
+    CIdAddressMap(istream&);\r
+};\r
+\r
+CIdAddressMap::CIdAddressMap(istream& is)\r
+: CInputFile(is)\r
+{\r
+    CIdentity id;\r
+    ulonglong_t ullBase;\r
+\r
+    while (!!(m_is >> hex >> id >> ullBase))\r
+        if (!insert(value_type(id, ullBase)).second)\r
+            throw runtime_error(__FUNCTION__ ": Duplicated files");\r
+}\r
+\r
+class CIdPathMap : public CInputFile, public map<CIdentity, string>\r
+{\r
+public:\r
+    CIdPathMap(istream&);\r
+};\r
+\r
+CIdPathMap::CIdPathMap(istream& is)\r
+: CInputFile(is)\r
+{\r
+    static const char cszFileSec[] = "[files]";\r
+    static const char cszFfsFile[] = "EFI_FILE_NAME";\r
+\r
+    string strALine;\r
+\r
+    // Find the [files] section\r
+    while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszFileSec) - 1, cszFileSec));\r
+\r
+    // m_is error means no FFS files listed in this INF file\r
+    if (!m_is)\r
+        return;\r
+\r
+    // Parse FFS files one by one\r
+    while (!!GetLine(strALine))\r
+    {\r
+        // Test if this begins a new section\r
+        if (strALine[0] == '[')\r
+            break;\r
+\r
+        // Is it a line of FFS file?\r
+        if (strALine.compare(0, sizeof(cszFfsFile) - 1, cszFfsFile))\r
+            continue;\r
+\r
+        string::size_type pos = strALine.find_first_not_of(' ', sizeof(cszFfsFile) - 1);\r
+        if (pos == string::npos || strALine[pos] != '=')\r
+            throw runtime_error(__FUNCTION__ ": Invalid FV INF format");\r
+        pos = strALine.find_first_not_of(' ', pos + 1);\r
+        if (pos == string::npos)\r
+            throw runtime_error(__FUNCTION__ ": Incomplete line");\r
+\r
+        strALine.erase(0, pos);\r
+        pos = strALine.rfind('\\');\r
+        if (pos == string::npos)\r
+            pos = 0;\r
+        else pos++;\r
+\r
+        CIdentity id(strALine.substr(pos, CIdentity::s_nIdStrLen));\r
+        if (!insert(value_type(id, strALine)).second)\r
+            throw runtime_error(__FUNCTION__ ": Duplicated FFS files");\r
+    }\r
+}\r
+\r
+class CSymbol : public CObjRoot\r
+{\r
+public:\r
+    string m_strAddress;\r
+    string m_strName;\r
+    ulonglong_t m_ullRva;\r
+    string m_strFrom;\r
+    bool m_bStatic;\r
+    bool m_bFunction;\r
+\r
+    CSymbol()\r
+    {\r
+    }\r
+    CSymbol(const string&, bool = false);\r
+    friend ostream& operator << (ostream&, const CSymbol&);\r
+};\r
+\r
+CSymbol::CSymbol(const string& strALine, bool bStatic)\r
+: m_bStatic(bStatic)\r
+{\r
+    istringstream is(strALine);\r
+\r
+    is >> m_strAddress >> m_strName >> hex >> m_ullRva >> m_strFrom;\r
+    if (m_strFrom == "F" || m_strFrom == "f")\r
+    {\r
+        m_bFunction = true;\r
+        is >> m_strFrom;\r
+    } else m_bFunction = false;\r
+}\r
+\r
+ostream& operator << (ostream& os, const CSymbol& symbol)\r
+{\r
+    os << hex << setw(16) << setfill('0') << symbol.m_ullRva << setw(0);\r
+    os << ' ' << (symbol.m_bFunction ? 'F' : ' ')\r
+        << (symbol.m_bStatic ? 'S' : ' ') << ' ';\r
+    return os << symbol.m_strName << endl;\r
+}\r
+\r
+class CMapFile : public CInputFile, public list<CSymbol>\r
+{\r
+public:\r
+    CMapFile(const string&);\r
+\r
+    void SetLoadAddress(ulonglong_t);\r
+    friend ostream& operator << (ostream&, const CMapFile&);\r
+\r
+    string m_strModuleName;\r
+    ulonglong_t m_ullLoadAddr;\r
+    string m_strEntryPoint;\r
+};\r
+\r
+CMapFile::CMapFile(const string& strFName)\r
+: CInputFile(strFName)\r
+{\r
+    static const char cszLoadAddr[] = "Preferred load address is";\r
+    static const char cszGlobal[] = "Address";\r
+    static const char cszEntryPoint[] = "entry point at";\r
+    static const char cszStatic[] = "Static symbols";\r
+\r
+    string strALine;\r
+\r
+    GetLine(m_strModuleName);\r
+\r
+    while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszLoadAddr) - 1, cszLoadAddr));\r
+    if (!m_is)\r
+        throw runtime_error(__FUNCTION__ ": Load Address not listed in map file");\r
+\r
+    istringstream is(strALine.substr(sizeof(cszLoadAddr) - 1));\r
+    if (!(is >> hex >> m_ullLoadAddr))\r
+        throw runtime_error(__FUNCTION__ ": Unexpected Load Address format");\r
+\r
+    while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszGlobal) - 1, cszGlobal));\r
+    if (!m_is)\r
+        throw runtime_error(__FUNCTION__ ": Global symbols not found in map file");\r
+\r
+    while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszEntryPoint) - 1, cszEntryPoint))\r
+        push_back(CSymbol(strALine));\r
+    if (!m_is)\r
+        throw runtime_error(__FUNCTION__ ": Entry Point not listed in map file");\r
+\r
+    is.str(strALine.substr(strALine.find_first_not_of(' ', sizeof(cszEntryPoint) - 1)));\r
+    is.clear();\r
+    if (!getline(is, m_strEntryPoint))\r
+        throw runtime_error(__FUNCTION__ ": Unexpected Entry Point format");\r
+\r
+    while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszStatic) - 1, cszStatic));\r
+    while (!!GetLine(strALine))\r
+        push_back(CSymbol(strALine, true));\r
+}\r
+\r
+void CMapFile::SetLoadAddress(ulonglong_t ullLoadAddr)\r
+{\r
+    for (iterator i = begin(); i != end(); i++)\r
+        if (i->m_ullRva != 0)\r
+            i->m_ullRva += ullLoadAddr - m_ullLoadAddr;\r
+    m_ullLoadAddr = ullLoadAddr;\r
+}\r
+\r
+ostream& operator << (ostream& os, const CMapFile& mapFile)\r
+{\r
+    CMapFile::const_iterator i = mapFile.begin();\r
+    while (i != mapFile.end() && i->m_strAddress != mapFile.m_strEntryPoint)\r
+        i++;\r
+    if (i == mapFile.end())\r
+        throw runtime_error(\r
+            __FUNCTION__ ": Entry point not found for module " +\r
+            mapFile.m_strModuleName);\r
+\r
+    os << endl << hex\r
+        << mapFile.m_strModuleName << " (EP=" << i->m_ullRva\r
+        << ", BA=" << mapFile.m_ullLoadAddr << ')' << endl\r
+        << endl;\r
+\r
+    for (i = mapFile.begin(); i != mapFile.end(); i++)\r
+        os << "  " << *i;\r
+\r
+    return os << endl;\r
+}\r
+\r
+class COutputFile : public CObjRoot\r
+{\r
+protected:\r
+    COutputFile(ostream&);\r
+    ostream& m_os;\r
+\r
+private:\r
+    COutputFile(const COutputFile&);\r
+    COutputFile& operator = (const COutputFile&);\r
+};\r
+\r
+class CFvMapFile : public CObjRoot, public map<CIdentity, CMapFile*>\r
+{\r
+public:\r
+    CFvMapFile(const CIdAddressMap&, const CIdPathMap&);\r
+    ~CFvMapFile(void);\r
+\r
+    friend ostream& operator << (ostream&, const CFvMapFile&);\r
+\r
+private:\r
+    void Cleanup(void);\r
+};\r
+\r
+CFvMapFile::CFvMapFile(const CIdAddressMap& idAddr, const CIdPathMap& idPath)\r
+{\r
+    for (CIdAddressMap::const_iterator i = idAddr.begin(); i != idAddr.end(); i++)\r
+    {\r
+        CIdPathMap::const_iterator j = idPath.find(i->first);\r
+        if (j == idPath.end())\r
+            throw runtime_error(__FUNCTION__ ": Map file not found");\r
+\r
+        try\r
+        {\r
+            pair<iterator, bool> k = insert(value_type(i->first,\r
+                new CMapFile(j->second.substr(0, j->second.rfind('.')) + ".map")));\r
+            if (!k.second)\r
+                throw logic_error(__FUNCTION__ ": Duplicated file found in rebase log");\r
+\r
+            k.first->second->SetLoadAddress(i->second);\r
+        }\r
+        catch (const runtime_error& e)\r
+        {\r
+            cerr << e.what() << endl;\r
+        }\r
+    }\r
+}\r
+\r
+void CFvMapFile::Cleanup(void)\r
+{\r
+    for (iterator i = begin(); i != end(); i++)\r
+        delete i->second;\r
+}\r
+\r
+ostream& operator << (ostream& os, const CFvMapFile& fvMap)\r
+{\r
+    for (CFvMapFile::const_iterator i = fvMap.begin(); !!os && i != fvMap.end(); i++)\r
+        os << *i->second;\r
+    return os;\r
+}\r
+\r
+CFvMapFile::~CFvMapFile(void)\r
+{\r
+    Cleanup();\r
+}\r
+\r
+class CGenFvMapUsage : public invalid_argument\r
+{\r
+public:\r
+    CGenFvMapUsage(void) : invalid_argument(s_szUsage)\r
+    {\r
+    }\r
+\r
+private:\r
+    static const char s_szUsage[];\r
+};\r
+\r
+const char CGenFvMapUsage::s_szUsage[] = "Usage: GenFvMap <LOG> <INF> <MAP>";\r
+\r
+class CGenFvMapApp : public CObjRoot\r
+{\r
+public:\r
+    CGenFvMapApp(int, char *[]);\r
+    ~CGenFvMapApp(void);\r
+\r
+    int Run(void);\r
+\r
+private:\r
+    int m_cArgc;\r
+    char **m_ppszArgv;\r
+};\r
+\r
+CGenFvMapApp::CGenFvMapApp(int cArgc, char *ppszArgv[])\r
+: m_cArgc(cArgc)\r
+, m_ppszArgv(ppszArgv)\r
+{\r
+    if (cArgc != 4)\r
+        throw CGenFvMapUsage();\r
+}\r
+\r
+CGenFvMapApp::~CGenFvMapApp(void)\r
+{\r
+}\r
+\r
+int CGenFvMapApp::Run(void)\r
+{\r
+    ifstream isLog(m_ppszArgv[1]);\r
+    ifstream isInf(m_ppszArgv[2]);\r
+\r
+    CIdAddressMap idAddress(isLog);\r
+    CIdPathMap idPath(isInf);\r
+\r
+    CFvMapFile fvMap(idAddress, idPath);\r
+\r
+    ofstream osMap(m_ppszArgv[3], ios_base::out | ios_base::trunc);\r
+    osMap << fvMap;\r
+\r
+    if (!osMap)\r
+        throw runtime_error(__FUNCTION__ ": Error writing output file");\r
+\r
+    return 0;\r
+}\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+    try\r
+    {\r
+        CGenFvMapApp app(argc, argv);\r
+        return app.Run();\r
+    }\r
+    catch (const exception& e)\r
+    {\r
+        cerr << e.what() << endl;\r
+        return -1;\r
+    }\r
+}\r