]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - 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
... / ...
CommitLineData
1//****************************************************************************\r
2//**\r
3//** Copyright (C) 2006 Intel Corporation. All rights reserved. \r
4//**\r
5//** The information and source code contained herein is the exclusive \r
6//** property of Intel Corporation and may not be disclosed, examined\r
7//** or reproduced in whole or in part without explicit written authorization \r
8//** from the company.\r
9//**\r
10//****************************************************************************\r
11\r
12#include <stdexcept>\r
13#include <list>\r
14#include <map>\r
15#include <iostream>\r
16#include <iomanip>\r
17#include <fstream>\r
18#include <sstream>\r
19#include <string>\r
20#include <utility>\r
21#include <algorithm>\r
22#include <functional>\r
23using namespace std;\r
24\r
25typedef unsigned __int64 ulonglong_t;\r
26\r
27template <class T>\r
28class CMemoryLeakChecker : public list<T*>\r
29{\r
30public:\r
31 static CMemoryLeakChecker<T>& GetInstance(void);\r
32\r
33private:\r
34 CMemoryLeakChecker(void)\r
35 {\r
36 }\r
37\r
38 ~CMemoryLeakChecker(void);\r
39};\r
40\r
41template <class T>\r
42CMemoryLeakChecker<T>& CMemoryLeakChecker<T>::GetInstance(void)\r
43{\r
44 static CMemoryLeakChecker<T> s_memLeakChecker;\r
45 return s_memLeakChecker;\r
46}\r
47\r
48template <class T>\r
49CMemoryLeakChecker<T>::~CMemoryLeakChecker(void)\r
50{\r
51 if (!list<T*>::empty())\r
52 throw logic_error(__FUNCTION__ ": Memory leak detected!");\r
53}\r
54\r
55class CObjRoot\r
56{\r
57protected:\r
58 CObjRoot(void);\r
59 virtual ~CObjRoot(void);\r
60};\r
61\r
62CObjRoot::CObjRoot(void)\r
63{\r
64 CMemoryLeakChecker<CObjRoot>::GetInstance().push_back(this);\r
65}\r
66\r
67CObjRoot::~CObjRoot(void)\r
68{\r
69 CMemoryLeakChecker<CObjRoot>::GetInstance().remove(this);\r
70}\r
71\r
72class CIdentity : public CObjRoot\r
73{\r
74public:\r
75 CIdentity(void);\r
76 CIdentity(const string&);\r
77 CIdentity(const CIdentity&);\r
78\r
79 bool operator < (const CIdentity&) const;\r
80 friend istream& operator >> (istream&, CIdentity&);\r
81\r
82 static const string::size_type s_nIdStrLen;\r
83\r
84protected:\r
85 ulonglong_t m_ullId[2];\r
86};\r
87\r
88const string::size_type CIdentity::s_nIdStrLen = 36;\r
89\r
90CIdentity::CIdentity(void)\r
91{\r
92 memset(m_ullId, 0, sizeof(m_ullId));\r
93}\r
94\r
95CIdentity::CIdentity(const string& strId)\r
96{\r
97 if (strId.length() != CIdentity::s_nIdStrLen ||\r
98 strId[8] != '-' ||\r
99 strId[13] != '-' ||\r
100 strId[18] != '-' ||\r
101 strId[23] != '-')\r
102 throw runtime_error(\r
103 __FUNCTION__ ": Error GUID format " + strId);\r
104\r
105 string strIdCopy(strId);\r
106 strIdCopy.erase(23, 1);\r
107 strIdCopy[18] = ' ';\r
108 strIdCopy.erase(13, 1);\r
109 strIdCopy.erase(8, 1);\r
110\r
111 istringstream is(strIdCopy);\r
112 is >> hex >> m_ullId[0] >> m_ullId[1];\r
113 if (!is)\r
114 throw runtime_error(\r
115 __FUNCTION__ ": GUID contains invalid characters" + strId);\r
116}\r
117\r
118CIdentity::CIdentity(const CIdentity& idRight)\r
119{\r
120 memmove(m_ullId, idRight.m_ullId, sizeof(m_ullId));\r
121}\r
122\r
123bool CIdentity::operator < (const CIdentity& idRight) const\r
124{\r
125 return memcmp(m_ullId, idRight.m_ullId, sizeof(m_ullId)) < 0;\r
126}\r
127\r
128istream& operator >> (istream& is, CIdentity& idRight)\r
129{\r
130 string strId;\r
131 is >> strId;\r
132 if (!!is)\r
133 idRight = CIdentity(strId);\r
134 return is;\r
135}\r
136\r
137class CInputFile : public CObjRoot\r
138{\r
139protected:\r
140 CInputFile(const string&);\r
141 CInputFile(istream&);\r
142 istream& GetLine(string&);\r
143\r
144private:\r
145 CInputFile(const CInputFile&);\r
146 CInputFile& operator = (const CInputFile&);\r
147\r
148private:\r
149 auto_ptr<istream> m_pIs;\r
150\r
151protected:\r
152 istream& m_is;\r
153};\r
154\r
155CInputFile::CInputFile(const string& strFName)\r
156: m_pIs(new ifstream(strFName.c_str()))\r
157, m_is(*m_pIs)\r
158{\r
159 if (!m_is)\r
160 throw runtime_error(__FUNCTION__ ": Error opening input file " + strFName);\r
161}\r
162\r
163CInputFile::CInputFile(istream& is)\r
164: m_is(is)\r
165{\r
166 if (!m_is)\r
167 throw runtime_error(__FUNCTION__ ": Error opening input stream");\r
168}\r
169\r
170istream& CInputFile::GetLine(string& strALine)\r
171{\r
172 if (!!m_is)\r
173 while (!!getline(m_is, strALine))\r
174 {\r
175 string::size_type pos = strALine.find_last_not_of(' ');\r
176 if (pos != string::npos)\r
177 {\r
178 strALine.erase(pos + 1);\r
179 strALine.erase(0, strALine.find_first_not_of(' '));\r
180 break;\r
181 }\r
182 }\r
183 return m_is;\r
184}\r
185\r
186class CIdAddressMap : public CInputFile, public map<CIdentity, ulonglong_t>\r
187{\r
188public:\r
189 CIdAddressMap(istream&);\r
190};\r
191\r
192CIdAddressMap::CIdAddressMap(istream& is)\r
193: CInputFile(is)\r
194{\r
195 CIdentity id;\r
196 ulonglong_t ullBase;\r
197\r
198 while (!!(m_is >> hex >> id >> ullBase))\r
199 if (!insert(value_type(id, ullBase)).second)\r
200 throw runtime_error(__FUNCTION__ ": Duplicated files");\r
201}\r
202\r
203class CIdPathMap : public CInputFile, public map<CIdentity, string>\r
204{\r
205public:\r
206 CIdPathMap(istream&);\r
207};\r
208\r
209CIdPathMap::CIdPathMap(istream& is)\r
210: CInputFile(is)\r
211{\r
212 static const char cszFileSec[] = "[files]";\r
213 static const char cszFfsFile[] = "EFI_FILE_NAME";\r
214\r
215 string strALine;\r
216\r
217 // Find the [files] section\r
218 while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszFileSec) - 1, cszFileSec));\r
219\r
220 // m_is error means no FFS files listed in this INF file\r
221 if (!m_is)\r
222 return;\r
223\r
224 // Parse FFS files one by one\r
225 while (!!GetLine(strALine))\r
226 {\r
227 // Test if this begins a new section\r
228 if (strALine[0] == '[')\r
229 break;\r
230\r
231 // Is it a line of FFS file?\r
232 if (strALine.compare(0, sizeof(cszFfsFile) - 1, cszFfsFile))\r
233 continue;\r
234\r
235 string::size_type pos = strALine.find_first_not_of(' ', sizeof(cszFfsFile) - 1);\r
236 if (pos == string::npos || strALine[pos] != '=')\r
237 throw runtime_error(__FUNCTION__ ": Invalid FV INF format");\r
238 pos = strALine.find_first_not_of(' ', pos + 1);\r
239 if (pos == string::npos)\r
240 throw runtime_error(__FUNCTION__ ": Incomplete line");\r
241\r
242 strALine.erase(0, pos);\r
243 pos = strALine.rfind('\\');\r
244 if (pos == string::npos)\r
245 pos = 0;\r
246 else pos++;\r
247\r
248 CIdentity id(strALine.substr(pos, CIdentity::s_nIdStrLen));\r
249 if (!insert(value_type(id, strALine)).second)\r
250 throw runtime_error(__FUNCTION__ ": Duplicated FFS files");\r
251 }\r
252}\r
253\r
254class CSymbol : public CObjRoot\r
255{\r
256public:\r
257 string m_strAddress;\r
258 string m_strName;\r
259 ulonglong_t m_ullRva;\r
260 string m_strFrom;\r
261 bool m_bStatic;\r
262 bool m_bFunction;\r
263\r
264 CSymbol()\r
265 {\r
266 }\r
267 CSymbol(const string&, bool = false);\r
268 friend ostream& operator << (ostream&, const CSymbol&);\r
269};\r
270\r
271CSymbol::CSymbol(const string& strALine, bool bStatic)\r
272: m_bStatic(bStatic)\r
273{\r
274 istringstream is(strALine);\r
275\r
276 is >> m_strAddress >> m_strName >> hex >> m_ullRva >> m_strFrom;\r
277 if (m_strFrom == "F" || m_strFrom == "f")\r
278 {\r
279 m_bFunction = true;\r
280 is >> m_strFrom;\r
281 } else m_bFunction = false;\r
282}\r
283\r
284ostream& operator << (ostream& os, const CSymbol& symbol)\r
285{\r
286 os << hex << setw(16) << setfill('0') << symbol.m_ullRva << setw(0);\r
287 os << ' ' << (symbol.m_bFunction ? 'F' : ' ')\r
288 << (symbol.m_bStatic ? 'S' : ' ') << ' ';\r
289 return os << symbol.m_strName << endl;\r
290}\r
291\r
292class CMapFile : public CInputFile, public list<CSymbol>\r
293{\r
294public:\r
295 CMapFile(const string&);\r
296\r
297 void SetLoadAddress(ulonglong_t);\r
298 friend ostream& operator << (ostream&, const CMapFile&);\r
299\r
300 string m_strModuleName;\r
301 ulonglong_t m_ullLoadAddr;\r
302 string m_strEntryPoint;\r
303};\r
304\r
305CMapFile::CMapFile(const string& strFName)\r
306: CInputFile(strFName)\r
307{\r
308 static const char cszLoadAddr[] = "Preferred load address is";\r
309 static const char cszGlobal[] = "Address";\r
310 static const char cszEntryPoint[] = "entry point at";\r
311 static const char cszStatic[] = "Static symbols";\r
312\r
313 string strALine;\r
314\r
315 GetLine(m_strModuleName);\r
316\r
317 while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszLoadAddr) - 1, cszLoadAddr));\r
318 if (!m_is)\r
319 throw runtime_error(__FUNCTION__ ": Load Address not listed in map file");\r
320\r
321 istringstream is(strALine.substr(sizeof(cszLoadAddr) - 1));\r
322 if (!(is >> hex >> m_ullLoadAddr))\r
323 throw runtime_error(__FUNCTION__ ": Unexpected Load Address format");\r
324\r
325 while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszGlobal) - 1, cszGlobal));\r
326 if (!m_is)\r
327 throw runtime_error(__FUNCTION__ ": Global symbols not found in map file");\r
328\r
329 while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszEntryPoint) - 1, cszEntryPoint))\r
330 push_back(CSymbol(strALine));\r
331 if (!m_is)\r
332 throw runtime_error(__FUNCTION__ ": Entry Point not listed in map file");\r
333\r
334 is.str(strALine.substr(strALine.find_first_not_of(' ', sizeof(cszEntryPoint) - 1)));\r
335 is.clear();\r
336 if (!getline(is, m_strEntryPoint))\r
337 throw runtime_error(__FUNCTION__ ": Unexpected Entry Point format");\r
338\r
339 while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszStatic) - 1, cszStatic));\r
340 while (!!GetLine(strALine))\r
341 push_back(CSymbol(strALine, true));\r
342}\r
343\r
344void CMapFile::SetLoadAddress(ulonglong_t ullLoadAddr)\r
345{\r
346 for (iterator i = begin(); i != end(); i++)\r
347 if (i->m_ullRva != 0)\r
348 i->m_ullRva += ullLoadAddr - m_ullLoadAddr;\r
349 m_ullLoadAddr = ullLoadAddr;\r
350}\r
351\r
352ostream& operator << (ostream& os, const CMapFile& mapFile)\r
353{\r
354 CMapFile::const_iterator i = mapFile.begin();\r
355 while (i != mapFile.end() && i->m_strAddress != mapFile.m_strEntryPoint)\r
356 i++;\r
357 if (i == mapFile.end())\r
358 throw runtime_error(\r
359 __FUNCTION__ ": Entry point not found for module " +\r
360 mapFile.m_strModuleName);\r
361\r
362 os << endl << hex\r
363 << mapFile.m_strModuleName << " (EP=" << i->m_ullRva\r
364 << ", BA=" << mapFile.m_ullLoadAddr << ')' << endl\r
365 << endl;\r
366\r
367 for (i = mapFile.begin(); i != mapFile.end(); i++)\r
368 os << " " << *i;\r
369\r
370 return os << endl;\r
371}\r
372\r
373class COutputFile : public CObjRoot\r
374{\r
375protected:\r
376 COutputFile(ostream&);\r
377 ostream& m_os;\r
378\r
379private:\r
380 COutputFile(const COutputFile&);\r
381 COutputFile& operator = (const COutputFile&);\r
382};\r
383\r
384class CFvMapFile : public CObjRoot, public map<CIdentity, CMapFile*>\r
385{\r
386public:\r
387 CFvMapFile(const CIdAddressMap&, const CIdPathMap&);\r
388 ~CFvMapFile(void);\r
389\r
390 friend ostream& operator << (ostream&, const CFvMapFile&);\r
391\r
392private:\r
393 void Cleanup(void);\r
394};\r
395\r
396CFvMapFile::CFvMapFile(const CIdAddressMap& idAddr, const CIdPathMap& idPath)\r
397{\r
398 for (CIdAddressMap::const_iterator i = idAddr.begin(); i != idAddr.end(); i++)\r
399 {\r
400 CIdPathMap::const_iterator j = idPath.find(i->first);\r
401 if (j == idPath.end())\r
402 throw runtime_error(__FUNCTION__ ": Map file not found");\r
403\r
404 try\r
405 {\r
406 pair<iterator, bool> k = insert(value_type(i->first,\r
407 new CMapFile(j->second.substr(0, j->second.rfind('.')) + ".map")));\r
408 if (!k.second)\r
409 throw logic_error(__FUNCTION__ ": Duplicated file found in rebase log");\r
410\r
411 k.first->second->SetLoadAddress(i->second);\r
412 }\r
413 catch (const runtime_error& e)\r
414 {\r
415 cerr << e.what() << endl;\r
416 }\r
417 }\r
418}\r
419\r
420void CFvMapFile::Cleanup(void)\r
421{\r
422 for (iterator i = begin(); i != end(); i++)\r
423 delete i->second;\r
424}\r
425\r
426ostream& operator << (ostream& os, const CFvMapFile& fvMap)\r
427{\r
428 for (CFvMapFile::const_iterator i = fvMap.begin(); !!os && i != fvMap.end(); i++)\r
429 os << *i->second;\r
430 return os;\r
431}\r
432\r
433CFvMapFile::~CFvMapFile(void)\r
434{\r
435 Cleanup();\r
436}\r
437\r
438class CGenFvMapUsage : public invalid_argument\r
439{\r
440public:\r
441 CGenFvMapUsage(void) : invalid_argument(s_szUsage)\r
442 {\r
443 }\r
444\r
445private:\r
446 static const char s_szUsage[];\r
447};\r
448\r
449const char CGenFvMapUsage::s_szUsage[] = "Usage: GenFvMap <LOG> <INF> <MAP>";\r
450\r
451class CGenFvMapApp : public CObjRoot\r
452{\r
453public:\r
454 CGenFvMapApp(int, char *[]);\r
455 ~CGenFvMapApp(void);\r
456\r
457 int Run(void);\r
458\r
459private:\r
460 int m_cArgc;\r
461 char **m_ppszArgv;\r
462};\r
463\r
464CGenFvMapApp::CGenFvMapApp(int cArgc, char *ppszArgv[])\r
465: m_cArgc(cArgc)\r
466, m_ppszArgv(ppszArgv)\r
467{\r
468 if (cArgc != 4)\r
469 throw CGenFvMapUsage();\r
470}\r
471\r
472CGenFvMapApp::~CGenFvMapApp(void)\r
473{\r
474}\r
475\r
476int CGenFvMapApp::Run(void)\r
477{\r
478 ifstream isLog(m_ppszArgv[1]);\r
479 ifstream isInf(m_ppszArgv[2]);\r
480\r
481 CIdAddressMap idAddress(isLog);\r
482 CIdPathMap idPath(isInf);\r
483\r
484 CFvMapFile fvMap(idAddress, idPath);\r
485\r
486 ofstream osMap(m_ppszArgv[3], ios_base::out | ios_base::trunc);\r
487 osMap << fvMap;\r
488\r
489 if (!osMap)\r
490 throw runtime_error(__FUNCTION__ ": Error writing output file");\r
491\r
492 return 0;\r
493}\r
494\r
495int main(int argc, char *argv[])\r
496{\r
497 try\r
498 {\r
499 CGenFvMapApp app(argc, argv);\r
500 return app.Run();\r
501 }\r
502 catch (const exception& e)\r
503 {\r
504 cerr << e.what() << endl;\r
505 return -1;\r
506 }\r
507}\r