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