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