]>
Commit | Line | Data |
---|---|---|
8733430b | 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 | |
23 | using namespace std;\r | |
24 | \r | |
25 | typedef unsigned __int64 ulonglong_t;\r | |
26 | \r | |
27 | template <class T>\r | |
28 | class CMemoryLeakChecker : public list<T*>\r | |
29 | {\r | |
30 | public:\r | |
31 | static CMemoryLeakChecker<T>& GetInstance(void);\r | |
32 | \r | |
33 | private:\r | |
34 | CMemoryLeakChecker(void)\r | |
35 | {\r | |
36 | }\r | |
37 | \r | |
38 | ~CMemoryLeakChecker(void);\r | |
39 | };\r | |
40 | \r | |
41 | template <class T>\r | |
42 | CMemoryLeakChecker<T>& CMemoryLeakChecker<T>::GetInstance(void)\r | |
43 | {\r | |
44 | static CMemoryLeakChecker<T> s_memLeakChecker;\r | |
45 | return s_memLeakChecker;\r | |
46 | }\r | |
47 | \r | |
48 | template <class T>\r | |
49 | CMemoryLeakChecker<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 | |
55 | class CObjRoot\r | |
56 | {\r | |
57 | protected:\r | |
58 | CObjRoot(void);\r | |
59 | virtual ~CObjRoot(void);\r | |
60 | };\r | |
61 | \r | |
62 | CObjRoot::CObjRoot(void)\r | |
63 | {\r | |
64 | CMemoryLeakChecker<CObjRoot>::GetInstance().push_back(this);\r | |
65 | }\r | |
66 | \r | |
67 | CObjRoot::~CObjRoot(void)\r | |
68 | {\r | |
69 | CMemoryLeakChecker<CObjRoot>::GetInstance().remove(this);\r | |
70 | }\r | |
71 | \r | |
72 | class CIdentity : public CObjRoot\r | |
73 | {\r | |
74 | public:\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 | |
84 | protected:\r | |
85 | ulonglong_t m_ullId[2];\r | |
86 | };\r | |
87 | \r | |
88 | const string::size_type CIdentity::s_nIdStrLen = 36;\r | |
89 | \r | |
90 | CIdentity::CIdentity(void)\r | |
91 | {\r | |
92 | memset(m_ullId, 0, sizeof(m_ullId));\r | |
93 | }\r | |
94 | \r | |
95 | CIdentity::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 | |
118 | CIdentity::CIdentity(const CIdentity& idRight)\r | |
119 | {\r | |
120 | memmove(m_ullId, idRight.m_ullId, sizeof(m_ullId));\r | |
121 | }\r | |
122 | \r | |
123 | bool 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 | |
128 | istream& 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 | |
137 | class CInputFile : public CObjRoot\r | |
138 | {\r | |
139 | protected:\r | |
140 | CInputFile(const string&);\r | |
141 | CInputFile(istream&);\r | |
142 | istream& GetLine(string&);\r | |
143 | \r | |
144 | private:\r | |
145 | CInputFile(const CInputFile&);\r | |
146 | CInputFile& operator = (const CInputFile&);\r | |
147 | \r | |
148 | private:\r | |
149 | auto_ptr<istream> m_pIs;\r | |
150 | \r | |
151 | protected:\r | |
152 | istream& m_is;\r | |
153 | };\r | |
154 | \r | |
155 | CInputFile::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 | |
163 | CInputFile::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 | |
170 | istream& 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 | |
186 | class CIdAddressMap : public CInputFile, public map<CIdentity, ulonglong_t>\r | |
187 | {\r | |
188 | public:\r | |
189 | CIdAddressMap(istream&);\r | |
190 | };\r | |
191 | \r | |
192 | CIdAddressMap::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 | |
203 | class CIdPathMap : public CInputFile, public map<CIdentity, string>\r | |
204 | {\r | |
205 | public:\r | |
206 | CIdPathMap(istream&);\r | |
207 | };\r | |
208 | \r | |
209 | CIdPathMap::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 | |
254 | class CSymbol : public CObjRoot\r | |
255 | {\r | |
256 | public:\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 | |
271 | CSymbol::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 | |
284 | ostream& 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 | |
292 | class CMapFile : public CInputFile, public list<CSymbol>\r | |
293 | {\r | |
294 | public:\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 | |
305 | CMapFile::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 | |
344 | void 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 | |
352 | ostream& 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 | |
373 | class COutputFile : public CObjRoot\r | |
374 | {\r | |
375 | protected:\r | |
376 | COutputFile(ostream&);\r | |
377 | ostream& m_os;\r | |
378 | \r | |
379 | private:\r | |
380 | COutputFile(const COutputFile&);\r | |
381 | COutputFile& operator = (const COutputFile&);\r | |
382 | };\r | |
383 | \r | |
384 | class CFvMapFile : public CObjRoot, public map<CIdentity, CMapFile*>\r | |
385 | {\r | |
386 | public:\r | |
387 | CFvMapFile(const CIdAddressMap&, const CIdPathMap&);\r | |
388 | ~CFvMapFile(void);\r | |
389 | \r | |
390 | friend ostream& operator << (ostream&, const CFvMapFile&);\r | |
391 | \r | |
392 | private:\r | |
393 | void Cleanup(void);\r | |
394 | };\r | |
395 | \r | |
396 | CFvMapFile::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 | |
420 | void CFvMapFile::Cleanup(void)\r | |
421 | {\r | |
422 | for (iterator i = begin(); i != end(); i++)\r | |
423 | delete i->second;\r | |
424 | }\r | |
425 | \r | |
426 | ostream& 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 | |
433 | CFvMapFile::~CFvMapFile(void)\r | |
434 | {\r | |
435 | Cleanup();\r | |
436 | }\r | |
437 | \r | |
438 | class CGenFvMapUsage : public invalid_argument\r | |
439 | {\r | |
440 | public:\r | |
441 | CGenFvMapUsage(void) : invalid_argument(s_szUsage)\r | |
442 | {\r | |
443 | }\r | |
444 | \r | |
445 | private:\r | |
446 | static const char s_szUsage[];\r | |
447 | };\r | |
448 | \r | |
449 | const char CGenFvMapUsage::s_szUsage[] = "Usage: GenFvMap <LOG> <INF> <MAP>";\r | |
450 | \r | |
451 | class CGenFvMapApp : public CObjRoot\r | |
452 | {\r | |
453 | public:\r | |
454 | CGenFvMapApp(int, char *[]);\r | |
455 | ~CGenFvMapApp(void);\r | |
456 | \r | |
457 | int Run(void);\r | |
458 | \r | |
459 | private:\r | |
460 | int m_cArgc;\r | |
461 | char **m_ppszArgv;\r | |
462 | };\r | |
463 | \r | |
464 | CGenFvMapApp::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 | |
472 | CGenFvMapApp::~CGenFvMapApp(void)\r | |
473 | {\r | |
474 | }\r | |
475 | \r | |
476 | int 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 | |
495 | int 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 |