1bd7b38f5497126e063ea212bb05d2d6a89fdb41
[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 #include "ProcessorBind.h"
12 #include <iostream>
13 #include <stdexcept>
14 #include <list>
15 #include <map>
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 UINT64 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 friend ostream& operator << (ostream&, const CIdentity&);
82
83 static const string::size_type s_nIdStrLen;
84
85 protected:
86 ulonglong_t m_ullId[2];
87 };
88
89 const string::size_type CIdentity::s_nIdStrLen = 36;
90
91 CIdentity::CIdentity(void)
92 {
93 memset(m_ullId, 0, sizeof(m_ullId));
94 }
95
96 CIdentity::CIdentity(const string& strId)
97 {
98 if (strId.length() != CIdentity::s_nIdStrLen ||
99 strId[8] != '-' ||
100 strId[13] != '-' ||
101 strId[18] != '-' ||
102 strId[23] != '-')
103 throw runtime_error(
104 __FUNCTION__ ": Error GUID format " + strId);
105
106 string strIdCopy(strId);
107 strIdCopy.erase(23, 1);
108 strIdCopy[18] = ' ';
109 strIdCopy.erase(13, 1);
110 strIdCopy.erase(8, 1);
111
112 istringstream is(strIdCopy);
113 is >> hex >> m_ullId[0] >> m_ullId[1];
114 if (!is)
115 throw runtime_error(
116 __FUNCTION__ ": GUID contains invalid characters" + strId);
117 }
118
119 CIdentity::CIdentity(const CIdentity& idRight)
120 {
121 memmove(m_ullId, idRight.m_ullId, sizeof(m_ullId));
122 }
123
124 bool CIdentity::operator < (const CIdentity& idRight) const
125 {
126 return memcmp(m_ullId, idRight.m_ullId, sizeof(m_ullId)) < 0;
127 }
128
129 istream& operator >> (istream& is, CIdentity& idRight)
130 {
131 string strId;
132 is >> strId;
133 if (!!is)
134 idRight = CIdentity(strId);
135 return is;
136 }
137
138 ostream& operator << (ostream& os, const CIdentity& idRight)
139 {
140 return os << hex << setfill('0')
141 << setw(8) << (unsigned long)(idRight.m_ullId[0] >> 32) << '-'
142 << setw(4) << (unsigned short)(idRight.m_ullId[0] >> 16) << '-'
143 << setw(4) << (unsigned short)idRight.m_ullId[0] << '-'
144 << setw(4) << (unsigned short)(idRight.m_ullId[1] >> 48) << '-'
145 << setw(12) << (idRight.m_ullId[1] & 0xffffffffffffULL);
146 }
147
148 class CInputFile : public CObjRoot
149 {
150 protected:
151 CInputFile(const string&);
152 CInputFile(istream&);
153 istream& GetLine(string&);
154
155 private:
156 CInputFile(const CInputFile&);
157 CInputFile& operator = (const CInputFile&);
158
159 private:
160 auto_ptr<istream> m_pIs;
161
162 protected:
163 istream& m_is;
164 };
165
166 CInputFile::CInputFile(const string& strFName)
167 : m_pIs(new ifstream(strFName.c_str()))
168 , m_is(*m_pIs)
169 {
170 if (!m_is)
171 throw runtime_error(__FUNCTION__ ": Error opening input file " + strFName);
172 }
173
174 CInputFile::CInputFile(istream& is)
175 : m_is(is)
176 {
177 if (!m_is)
178 throw runtime_error(__FUNCTION__ ": Error opening input stream");
179 }
180
181 istream& CInputFile::GetLine(string& strALine)
182 {
183 if (!!m_is)
184 while (!!getline(m_is, strALine))
185 {
186 string::size_type pos = strALine.find_last_not_of(' ');
187 if (pos != string::npos)
188 {
189 strALine.erase(pos + 1);
190 strALine.erase(0, strALine.find_first_not_of(' '));
191 break;
192 }
193 }
194 return m_is;
195 }
196
197 class CIdAddressPathMap : public CInputFile, public map<CIdentity, pair<ulonglong_t, string> >
198 {
199 public:
200 CIdAddressPathMap(istream&);
201 };
202
203 CIdAddressPathMap::CIdAddressPathMap(istream& is)
204 : CInputFile(is)
205 {
206 key_type k;
207 mapped_type m;
208 while (!!(m_is >> hex >> k >> m.first) && !!GetLine(m.second))
209 if (!insert(value_type(k, m)).second)
210 throw runtime_error(__FUNCTION__ ": Duplicated files");
211 }
212
213 class CSymbol : public CObjRoot
214 {
215 public:
216 string m_strAddress;
217 string m_strName;
218 ulonglong_t m_ullRva;
219 string m_strFrom;
220 bool m_bStatic;
221 bool m_bFunction;
222
223 CSymbol()
224 {
225 }
226 CSymbol(const string&, bool = false);
227 friend ostream& operator << (ostream&, const CSymbol&);
228 };
229
230 CSymbol::CSymbol(const string& strALine, bool bStatic)
231 : m_bStatic(bStatic)
232 {
233 istringstream is(strALine);
234
235 is >> m_strAddress >> m_strName >> hex >> m_ullRva >> m_strFrom;
236 if (m_strFrom == "F" || m_strFrom == "f")
237 {
238 m_bFunction = true;
239 is >> m_strFrom;
240 } else m_bFunction = false;
241 }
242
243 ostream& operator << (ostream& os, const CSymbol& symbol)
244 {
245 os << hex << setw(16) << setfill('0') << symbol.m_ullRva << setw(0);
246 os << ' ' << (symbol.m_bFunction ? 'F' : ' ')
247 << (symbol.m_bStatic ? 'S' : ' ') << ' ';
248 return os << symbol.m_strName;
249 }
250
251 class CMapFile : public CInputFile, public list<CSymbol>
252 {
253 public:
254 CMapFile(const string&);
255
256 void SetLoadAddress(ulonglong_t);
257
258 string m_strModuleName;
259 ulonglong_t m_ullLoadAddr;
260 string m_strEntryPoint;
261 };
262
263 CMapFile::CMapFile(const string& strFName)
264 : CInputFile(strFName)
265 {
266 static const char cszLoadAddr[] = "Preferred load address is";
267 static const char cszGlobal[] = "Address";
268 static const char cszEntryPoint[] = "entry point at";
269 static const char cszStatic[] = "Static symbols";
270
271 string strALine;
272
273 GetLine(m_strModuleName);
274
275 while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszLoadAddr) - 1, cszLoadAddr));
276 if (!m_is)
277 throw runtime_error(__FUNCTION__ ": Load Address not listed in map file");
278
279 istringstream is(strALine.substr(sizeof(cszLoadAddr) - 1));
280 if (!(is >> hex >> m_ullLoadAddr))
281 throw runtime_error(__FUNCTION__ ": Unexpected Load Address format");
282
283 while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszGlobal) - 1, cszGlobal));
284 if (!m_is)
285 throw runtime_error(__FUNCTION__ ": Global symbols not found in map file");
286
287 while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszEntryPoint) - 1, cszEntryPoint))
288 push_back(CSymbol(strALine));
289 if (!m_is)
290 throw runtime_error(__FUNCTION__ ": Entry Point not listed in map file");
291
292 is.str(strALine.substr(strALine.find_first_not_of(' ', sizeof(cszEntryPoint) - 1)));
293 is.clear();
294 if (!getline(is, m_strEntryPoint))
295 throw runtime_error(__FUNCTION__ ": Unexpected Entry Point format");
296
297 while (!!GetLine(strALine) && strALine.compare(0, sizeof(cszStatic) - 1, cszStatic));
298 while (!!GetLine(strALine))
299 push_back(CSymbol(strALine, true));
300 }
301
302 void CMapFile::SetLoadAddress(ulonglong_t ullLoadAddr)
303 {
304 for (iterator i = begin(); i != end(); i++)
305 if (i->m_ullRva >= m_ullLoadAddr)
306 i->m_ullRva += ullLoadAddr - m_ullLoadAddr;
307 m_ullLoadAddr = ullLoadAddr;
308 }
309
310 class COutputFile : public CObjRoot
311 {
312 protected:
313 COutputFile(ostream&);
314 ostream& m_os;
315
316 private:
317 COutputFile(const COutputFile&);
318 COutputFile& operator = (const COutputFile&);
319 };
320
321 class CFvMapFile : public CObjRoot, public map<CIdentity, CMapFile*>
322 {
323 public:
324 CFvMapFile(const CIdAddressPathMap&);
325 ~CFvMapFile(void);
326
327 friend ostream& operator << (ostream&, const CFvMapFile&);
328
329 private:
330 void Cleanup(void);
331 };
332
333 CFvMapFile::CFvMapFile(const CIdAddressPathMap& idAddrPath)
334 {
335 for (CIdAddressPathMap::const_iterator i = idAddrPath.begin(); i != idAddrPath.end(); i++)
336 {
337 if (i->second.second == "*")
338 continue;
339
340 pair<iterator, bool> r = insert(value_type(i->first,
341 new CMapFile(i->second.second.substr(0, i->second.second.rfind('.')) + ".map")));
342 r.first->second->SetLoadAddress(i->second.first);
343 }
344 }
345
346 void CFvMapFile::Cleanup(void)
347 {
348 for (iterator i = begin(); i != end(); i++)
349 delete i->second;
350 }
351
352 ostream& operator << (ostream& os, const CFvMapFile& fvMap)
353 {
354 for (CFvMapFile::const_iterator i = fvMap.begin(); !!os && i != fvMap.end(); i++)
355 {
356 CMapFile::const_iterator j = i->second->begin();
357 while (j != i->second->end() && j->m_strAddress != i->second->m_strEntryPoint) j++;
358 if (j == i->second->end())
359 throw runtime_error(
360 __FUNCTION__ ":Entry point not found for module " +
361 i->second->m_strModuleName);
362
363 os << hex
364 << i->second->m_strModuleName
365 << " (EP=" << j->m_ullRva
366 << ", BA=" << i->second->m_ullLoadAddr
367 << ", GUID=" << i->first
368 << ")" << endl << endl;
369
370 for (j = i->second->begin(); j != i->second->end(); j++)
371 os << " " << *j << endl;
372
373 os << endl << endl;
374 }
375
376 return os;
377 }
378
379 CFvMapFile::~CFvMapFile(void)
380 {
381 Cleanup();
382 }
383
384 class CGenFvMapUsage : public invalid_argument
385 {
386 public:
387 CGenFvMapUsage(void) : invalid_argument(s_szUsage)
388 {
389 }
390
391 private:
392 static const char s_szUsage[];
393 };
394
395 const char CGenFvMapUsage::s_szUsage[] = "Usage: GenFvMap <LOG> <MAP>";
396
397 class CGenFvMapApp : public CObjRoot
398 {
399 public:
400 CGenFvMapApp(int, char *[]);
401 ~CGenFvMapApp(void);
402
403 int Run(void);
404
405 private:
406 int m_cArgc;
407 char **m_ppszArgv;
408 };
409
410 CGenFvMapApp::CGenFvMapApp(int cArgc, char *ppszArgv[])
411 : m_cArgc(cArgc)
412 , m_ppszArgv(ppszArgv)
413 {
414 if (cArgc != 3)
415 throw CGenFvMapUsage();
416 }
417
418 CGenFvMapApp::~CGenFvMapApp(void)
419 {
420 }
421
422 int CGenFvMapApp::Run(void)
423 {
424 ifstream isLog(m_ppszArgv[1]);
425 CIdAddressPathMap idAddrPath(isLog);
426 CFvMapFile fvMap(idAddrPath);
427
428 ofstream osMap(m_ppszArgv[2], ios_base::out | ios_base::trunc);
429 osMap << fvMap;
430
431 if (!osMap)
432 throw runtime_error(__FUNCTION__ ": Error writing output file");
433
434 return 0;
435 }
436
437 int main(int argc, char *argv[])
438 {
439 try
440 {
441 CGenFvMapApp app(argc, argv);
442 return app.Run();
443 }
444 catch (const exception& e)
445 {
446 cerr << e.what() << endl;
447 return -1;
448 }
449 }