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 |