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