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