|
1 // bsym.cpp |
|
2 // |
|
3 // Copyright (c) 2010 Accenture. All rights reserved. |
|
4 // This component and the accompanying materials are made available |
|
5 // under the terms of the "Eclipse Public License v1.0" |
|
6 // which accompanies this distribution, and is available |
|
7 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 // |
|
9 // Initial Contributors: |
|
10 // Accenture - Initial contribution |
|
11 // |
|
12 #include <fshell/descriptorutils.h> |
|
13 #include <fshell/bsym.h> |
|
14 |
|
15 #include <fshell/iocli.h> |
|
16 using LtkUtils::CBsymFile; |
|
17 using namespace IoUtils; |
|
18 #include "bsymtree.h" |
|
19 using LtkUtils::RNode; |
|
20 |
|
21 #ifdef ASSERT |
|
22 #undef ASSERT |
|
23 #endif |
|
24 |
|
25 _LIT(KBsymPanic, "BSym"); |
|
26 #define ASSERT(x) __ASSERT_ALWAYS(x, User::Panic(KBsymPanic, __LINE__)) |
|
27 #define DEBUG_XY(x, y) RDebug::Printf(#x " = %d " #y " = %d", (int)(x), (int)(y)) |
|
28 #define ASSERT_GE(x, y) if (!((x) >= (y))) { DEBUG_XY(x, y); ASSERT(x >= y); } |
|
29 #define ASSERT_GT(x, y) if (!((x) > (y))) { DEBUG_XY(x, y); ASSERT(x > y); } |
|
30 #define ASSERT_LE(x, y) if (!((x) <= (y))) { DEBUG_XY(x, y); ASSERT(x <= y); } |
|
31 #define ASSERT_LT(x, y) if (!((x) < (y))) { DEBUG_XY(x, y); ASSERT(x < y); } |
|
32 #define ASSERT_EQ(x, y) if (!((x) == (y))) { DEBUG_XY(x, y); ASSERT(x == y); } |
|
33 #define ASSERT_NE(x, y) if (!((x) != (y))) { DEBUG_XY(x, y); ASSERT(x != y); } |
|
34 |
|
35 #define LOG(args...) |
|
36 //#include <fshell/clogger.h> |
|
37 //#define LOG(args...) RClogger::Slog(args) |
|
38 |
|
39 enum TBsymVersion |
|
40 { |
|
41 EVersion1_0 = 0x00010000, |
|
42 EVersion2_0 = 0x00020000, |
|
43 EVersion2_1 = 0x00020001, |
|
44 }; |
|
45 static const TUint32 KMajorVersion = 0xFFFF0000; |
|
46 static const TUint32 KMinorVersion = 0x0000FFFF; |
|
47 static const TUint32 KMagic = ('B'<<24)|('S'<<16)|('Y'<<8)|'M'; |
|
48 |
|
49 inline TUint32 fromBigEndian(TUint32 aVal) |
|
50 { |
|
51 TUint8* ptr = (TUint8*)&aVal; |
|
52 return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]); |
|
53 } |
|
54 |
|
55 inline TUint32 toBigEndian(TUint32 aVal) |
|
56 { |
|
57 return fromBigEndian(aVal); // Same thing really |
|
58 } |
|
59 |
|
60 class TSymbol |
|
61 { |
|
62 public: |
|
63 TUint32 Address() const { return fromBigEndian(iData[0]); } |
|
64 TUint32 Length() const { return fromBigEndian(iData[1]) & 0xFFFF; } |
|
65 TUint32 NameOffset() const { return fromBigEndian(iData[2]); } |
|
66 TUint32 NamePrefixIndex() const { return fromBigEndian(iData[1]) >> 16; } |
|
67 |
|
68 TSymbol(TUint32 aAddress) { iData[0] = toBigEndian(aAddress); } |
|
69 |
|
70 protected: |
|
71 TUint32 iData[3]; |
|
72 }; |
|
73 |
|
74 class TCodeSeg : public TSymbol |
|
75 { |
|
76 public: |
|
77 TUint32 SymbolStart() const { return fromBigEndian(iSymbolsStartIndex); } |
|
78 TUint32 SymbolCount() const { return fromBigEndian(iData[1]); } // Code segs use the TSymbol 'length' field to store the number of symbols, *not* the length. To get the length of a codeseg, call CBsymFile::CodeSegLen(const TCodeSeg&) |
|
79 TUint32 PrefixTableOffset() const { return fromBigEndian(iPrefixTableOffset); } |
|
80 |
|
81 TCodeSeg(TUint32 aAddress) : TSymbol(aAddress) {} |
|
82 private: |
|
83 TUint32 iSymbolsStartIndex; |
|
84 TUint32 iPrefixTableOffset; |
|
85 }; |
|
86 |
|
87 class TCodeAndSym |
|
88 { |
|
89 public: |
|
90 TCodeAndSym(const TCodeSeg* aCodeSeg, const TSymbol* aSymbol); |
|
91 TCodeSeg iCodeSeg; |
|
92 TSymbol iSymbol; |
|
93 }; |
|
94 |
|
95 NONSHARABLE_CLASS(CBsymFileImpl) : public CBsymFile |
|
96 { |
|
97 public: |
|
98 CBsymFileImpl(); |
|
99 ~CBsymFileImpl(); |
|
100 void ConstructL(RFs& aFs, const TDesC& aFileName); |
|
101 TPtrC DoLookupL(TUint32 aRomAddress); |
|
102 TCodeAndSym DoLookup(TUint32 aAddress) const; // Only useful for ROM symbols files |
|
103 void LoadSymbolNameL(const TSymbol* aSymbol, const TCodeSeg* aParentCodeSeg); |
|
104 RNode* DoCreateCompletionTreeL(const TDesC& aCodesegName); |
|
105 TPtrC DoLookupL(const TDesC& aCodesegName, TInt aOffset); |
|
106 |
|
107 private: |
|
108 TUint32 UintL(TInt aOffset) const; |
|
109 TUint32 UnalignedUintL(TInt aOffset) const; |
|
110 TCodeSeg CodeSegL(TInt aIndex) const; |
|
111 TSymbol SymbolL(TInt aIndex) const; |
|
112 |
|
113 TUint32 CodesegSectionLengthL() const; |
|
114 TUint32 SymbolsSectionLengthL() const; |
|
115 TInt SymbolCountL() const; |
|
116 TInt CodeSegCountL() const; |
|
117 TInt TokenCountL() const; |
|
118 |
|
119 void CreateCodesegHashIfNeededL(); |
|
120 TCodeAndSym DoCodesegLookup(const TCodeSeg& aCodeSeg, TUint32 aAddress) const; |
|
121 HBufC* GetTokenL(TInt aToken) const; |
|
122 HBufC* GetStringL(TUint32 aLocation, TBool aExpandTokens=ETrue) const; |
|
123 TUint32 CodeSegLengthL(const TCodeSeg* aCodeSeg) const; |
|
124 |
|
125 friend class TCodeSegKey; |
|
126 friend class TSymbolKey; |
|
127 |
|
128 private: |
|
129 LtkUtils::RLtkBuf iTempString; |
|
130 LtkUtils::RStringHash<TCodeSeg> iCodeSegHash; |
|
131 TInt iFileCacheOffset; |
|
132 LtkUtils::RLtkBuf8 iFileCache; |
|
133 }; |
|
134 |
|
135 NONSHARABLE_CLASS(TCodeSegKey) : public TKey |
|
136 { |
|
137 public: |
|
138 TCodeSegKey(const CBsymFileImpl* aFile, TUint32 aAddress); |
|
139 TInt Compare(TInt aLeft, TInt aRight) const; |
|
140 |
|
141 private: |
|
142 const CBsymFileImpl* iFile; |
|
143 TUint32 iAddress; |
|
144 }; |
|
145 |
|
146 NONSHARABLE_CLASS(TSymbolKey) : public TKey |
|
147 { |
|
148 public: |
|
149 TSymbolKey(const CBsymFileImpl* aFile, const TCodeSeg& aCodeSeg, TUint32 aAddress); |
|
150 TInt Compare(TInt aLeft, TInt aRight) const; |
|
151 |
|
152 private: |
|
153 const CBsymFileImpl* iFile; |
|
154 const TCodeSeg& iCodeSeg; |
|
155 TUint32 iAddress; |
|
156 }; |
|
157 |
|
158 EXPORT_C CBsymFile* CBsymFile::NewL(RFs& aFs, const TDesC& aFileName) |
|
159 { |
|
160 CBsymFileImpl* result = new (ELeave) CBsymFileImpl; |
|
161 CleanupStack::PushL(result); |
|
162 result->ConstructL(aFs, aFileName); |
|
163 CleanupStack::Pop(result); |
|
164 return result; |
|
165 } |
|
166 |
|
167 EXPORT_C CBsymFile::~CBsymFile() |
|
168 { |
|
169 iFile.Close(); |
|
170 } |
|
171 |
|
172 EXPORT_C TPtrC CBsymFile::LookupL(TUint32 aAddress) |
|
173 { |
|
174 CBsymFileImpl* impl = static_cast<CBsymFileImpl*>(this); // We know we're actually a CBsymFileImpl |
|
175 return impl->DoLookupL(aAddress); |
|
176 } |
|
177 |
|
178 TPtrC CBsymFileImpl::DoLookupL(TUint32 aAddress) |
|
179 { |
|
180 iTempString.Zero(); |
|
181 TCodeAndSym res = DoLookup(aAddress); |
|
182 if (res.iSymbol.Address()) |
|
183 { |
|
184 LoadSymbolNameL(&res.iSymbol, &res.iCodeSeg); |
|
185 iTempString.AppendFormatL(_L(" + 0x%x"), aAddress - res.iSymbol.Address()); |
|
186 } |
|
187 return TPtrC(iTempString); |
|
188 } |
|
189 |
|
190 CBsymFile::CBsymFile() |
|
191 { |
|
192 } |
|
193 |
|
194 CBsymFileImpl::CBsymFileImpl() |
|
195 { |
|
196 } |
|
197 |
|
198 CBsymFileImpl::~CBsymFileImpl() |
|
199 { |
|
200 iTempString.Close(); |
|
201 iCodeSegHash.Close(); |
|
202 iFileCache.Close(); |
|
203 } |
|
204 |
|
205 TUint32 CBsymFileImpl::UintL(TInt aOffset) const |
|
206 { |
|
207 ASSERT((aOffset & 3) == 0); |
|
208 return UnalignedUintL(aOffset); |
|
209 } |
|
210 |
|
211 TUint32 CBsymFileImpl::UnalignedUintL(TInt aOffset) const |
|
212 { |
|
213 ASSERT_LE((TUint)aOffset+4, iFileSize); |
|
214 TBuf8<4> buf; |
|
215 TInt err = iFile.Read(aOffset, buf); |
|
216 User::LeaveIfError(err); |
|
217 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3]); |
|
218 } |
|
219 |
|
220 #undef LeaveIfErr |
|
221 #define LeaveIfErr(args...) StaticLeaveIfErr(args) |
|
222 |
|
223 void CBsymFileImpl::ConstructL(RFs& aFs, const TDesC& aFileName) |
|
224 { |
|
225 iTempString.CreateL(256); |
|
226 LeaveIfErr(iFile.Open(aFs, aFileName, EFileShareReadersOnly), _L("Couldn't open file %S"), &aFileName); |
|
227 LeaveIfErr(iFile.Size(*reinterpret_cast<TInt*>(&iFileSize)), _L("Couldn't read file size")); |
|
228 if (iFileSize < 5*4) |
|
229 { |
|
230 LeaveIfErr(KErrCorrupt, _L("%S is too small to be a bsym file"), &aFileName); |
|
231 } |
|
232 // Validate the data |
|
233 if (UintL(0) != KMagic) |
|
234 { |
|
235 LeaveIfErr(KErrCorrupt, _L("%S is not a BSYM file."), &aFileName); |
|
236 } |
|
237 iVersion = UintL(4); |
|
238 iCodesegOffset = UintL(8); |
|
239 iSymbolsOffset = UintL(0x0C); |
|
240 |
|
241 TUint32 majorVersion = (iVersion&KMajorVersion); |
|
242 if (majorVersion != EVersion1_0 && majorVersion != EVersion2_0) |
|
243 { |
|
244 LeaveIfErr(KErrNotSupported, _L("Unsupported bysm version v%d.%d in %S"), iVersion>>16, iVersion & KMinorVersion, &aFileName); |
|
245 } |
|
246 if (iVersion >= EVersion2_0) |
|
247 { |
|
248 iTokensOffset = UintL(0x10); |
|
249 if (iTokensOffset + 4 > iFileSize || TokenCountL() > 128 || iTokensOffset + 4 + TokenCountL()*4 > iFileSize) |
|
250 { |
|
251 LeaveIfErr(KErrCorrupt, _L("Bad token offset %x or count"), iTokensOffset); |
|
252 } |
|
253 } |
|
254 if (iVersion >= EVersion2_1) |
|
255 { |
|
256 TUint32 renamesOffset = UintL(0x14); |
|
257 if (renamesOffset + 4 > iFileSize || renamesOffset + UintL(renamesOffset)*8 > iFileSize) |
|
258 { |
|
259 // UintL(renamesOffset)*8 is size of renames section |
|
260 LeaveIfErr(KErrCorrupt, _L("Bad rename offset %x or count"), renamesOffset); |
|
261 } |
|
262 } |
|
263 if (iCodesegOffset+4 > iFileSize || iCodesegOffset + CodesegSectionLengthL() > iFileSize) |
|
264 { |
|
265 LeaveIfErr(KErrCorrupt, _L("Bad codeseg offset %x or count"), iCodesegOffset); |
|
266 } |
|
267 if (iSymbolsOffset+4 > iFileSize || iSymbolsOffset + SymbolsSectionLengthL() > iFileSize) |
|
268 { |
|
269 LeaveIfErr(KErrCorrupt, _L("Bad symbols offset %x or count"), iSymbolsOffset); |
|
270 } |
|
271 |
|
272 // Don't construct the codeseg hash now, it takes too long and we only need it if we need to do completions |
|
273 } |
|
274 |
|
275 TCodeSeg CBsymFileImpl::CodeSegL(TInt aIndex) const |
|
276 { |
|
277 TCodeSeg result(0); |
|
278 const TInt fileIdx = iCodesegOffset + 4 + aIndex * sizeof(TCodeSeg); |
|
279 if (fileIdx >= iFileCacheOffset && fileIdx + sizeof(TCodeSeg) <= iFileCacheOffset + iFileCache.Length()) |
|
280 { |
|
281 Mem::Copy(&result, iFileCache.Ptr() + fileIdx - iFileCacheOffset, sizeof(TCodeSeg)); |
|
282 } |
|
283 else |
|
284 { |
|
285 TPckg<TCodeSeg> pkg(result); |
|
286 User::LeaveIfError(iFile.Read(fileIdx, pkg)); |
|
287 } |
|
288 return result; |
|
289 } |
|
290 |
|
291 TSymbol CBsymFileImpl::SymbolL(TInt aIndex) const |
|
292 { |
|
293 TSymbol result(0); |
|
294 const TInt fileIdx = iSymbolsOffset + 4 + aIndex * sizeof(TSymbol); |
|
295 TPckg<TSymbol> pkg(result); |
|
296 User::LeaveIfError(iFile.Read(fileIdx, pkg)); |
|
297 return result; |
|
298 } |
|
299 |
|
300 TUint32 CBsymFileImpl::CodesegSectionLengthL() const |
|
301 { |
|
302 return 4 + CodeSegCountL() * sizeof(TCodeSeg); |
|
303 } |
|
304 |
|
305 TUint32 CBsymFileImpl::SymbolsSectionLengthL() const |
|
306 { |
|
307 return 4 + SymbolCountL() * sizeof(TSymbol); |
|
308 } |
|
309 |
|
310 TInt CBsymFileImpl::SymbolCountL() const |
|
311 { |
|
312 return UintL(iSymbolsOffset); |
|
313 } |
|
314 |
|
315 TInt CBsymFileImpl::CodeSegCountL() const |
|
316 { |
|
317 return UintL(iCodesegOffset); |
|
318 } |
|
319 |
|
320 TUint32 CBsymFileImpl::CodeSegLengthL(const TCodeSeg* aCodeSeg) const |
|
321 { |
|
322 if (aCodeSeg->SymbolCount()) |
|
323 { |
|
324 TSymbol lastSymbol = SymbolL(aCodeSeg->SymbolStart() + aCodeSeg->SymbolCount()-1); |
|
325 return lastSymbol.Address() + lastSymbol.Length() - aCodeSeg->Address(); |
|
326 } |
|
327 else |
|
328 { |
|
329 return 0; |
|
330 } |
|
331 } |
|
332 |
|
333 TCodeSegKey::TCodeSegKey(const CBsymFileImpl* aFile, TUint32 aAddress) |
|
334 : TKey(), iFile(aFile), iAddress(aAddress) |
|
335 {} |
|
336 |
|
337 TInt TCodeSegKey::Compare(TInt aLeft, TInt aRight) const |
|
338 { |
|
339 TUint32 left = aLeft == KIndexPtr ? iAddress : iFile->CodeSegL(aLeft).Address(); |
|
340 TUint32 right = aRight == KIndexPtr ? iAddress : iFile->CodeSegL(aRight).Address(); |
|
341 return (TInt)left - (TInt)right; |
|
342 } |
|
343 |
|
344 |
|
345 TSymbolKey::TSymbolKey(const CBsymFileImpl* aFile, const TCodeSeg& aCodeSeg, TUint32 aAddress) |
|
346 : TKey(), iFile(aFile), iCodeSeg(aCodeSeg), iAddress(aAddress) |
|
347 {} |
|
348 |
|
349 TInt TSymbolKey::Compare(TInt aLeft, TInt aRight) const |
|
350 { |
|
351 TUint32 left = aLeft == KIndexPtr ? iAddress : iFile->SymbolL(iCodeSeg.SymbolStart() + aLeft).Address(); |
|
352 TUint32 right = aRight == KIndexPtr ? iAddress : iFile->SymbolL(iCodeSeg.SymbolStart() + aRight).Address(); |
|
353 return (TInt)left - (TInt)right; |
|
354 } |
|
355 |
|
356 TCodeAndSym::TCodeAndSym(const TCodeSeg* aCodeSeg, const TSymbol* aSymbol) |
|
357 : iCodeSeg(0), iSymbol(0) |
|
358 { |
|
359 if (aCodeSeg) iCodeSeg = *aCodeSeg; |
|
360 if (aSymbol) iSymbol = *aSymbol; |
|
361 } |
|
362 |
|
363 TCodeAndSym CBsymFileImpl::DoLookup(TUint32 aAddress) const |
|
364 { |
|
365 // Find codeseg (need to know this if the symbol has a name prefix) |
|
366 TInt pos = 0; |
|
367 TCodeSegKey codesegKey(this, aAddress); |
|
368 TBool found = !User::BinarySearch(CodeSegCountL(), codesegKey, pos); |
|
369 if (!found && pos != 0) pos--; |
|
370 TCodeSeg codeseg = CodeSegL(pos); |
|
371 |
|
372 if (aAddress >= codeseg.Address() && aAddress < codeseg.Address() + CodeSegLengthL(&codeseg)) |
|
373 { |
|
374 return DoCodesegLookup(codeseg, aAddress); |
|
375 } |
|
376 return TCodeAndSym(NULL, NULL); |
|
377 } |
|
378 |
|
379 EXPORT_C TPtrC CBsymFile::LookupL(const TDesC& aCodesegName, TInt aOffset) |
|
380 { |
|
381 return static_cast<CBsymFileImpl*>(this)->DoLookupL(aCodesegName, aOffset); |
|
382 } |
|
383 |
|
384 TPtrC CBsymFileImpl::DoLookupL(const TDesC& aCodesegName, TInt aOffset) |
|
385 { |
|
386 CreateCodesegHashIfNeededL(); |
|
387 const TCodeSeg* codeseg = iCodeSegHash.Find(aCodesegName); |
|
388 if (!codeseg) return TPtrC(); |
|
389 TUint32 addr = codeseg->Address() + aOffset; |
|
390 TCodeAndSym res = DoCodesegLookup(*codeseg, addr); |
|
391 iTempString.Zero(); |
|
392 if (res.iSymbol.Address()) |
|
393 { |
|
394 LoadSymbolNameL(&res.iSymbol, &res.iCodeSeg); |
|
395 iTempString.AppendFormatL(_L(" + 0x%x"), addr - res.iSymbol.Address()); |
|
396 } |
|
397 return TPtrC(iTempString); |
|
398 } |
|
399 |
|
400 TCodeAndSym CBsymFileImpl::DoCodesegLookup(const TCodeSeg& aCodeSeg, TUint32 aAddress) const |
|
401 { |
|
402 TInt pos = 0; |
|
403 TSymbolKey symbolKey(this, aCodeSeg, aAddress); |
|
404 TBool found = !User::BinarySearch(aCodeSeg.SymbolCount(), symbolKey, pos); |
|
405 if (!found && pos != 0) pos--; |
|
406 TSymbol symbol = SymbolL(aCodeSeg.SymbolStart() + pos); |
|
407 |
|
408 if (aAddress >= symbol.Address() && aAddress < symbol.Address() + symbol.Length()) |
|
409 return TCodeAndSym(&aCodeSeg, &symbol); |
|
410 // TODO: Handle cases where the address falls outside of any symbol but still within the code segment, ie when symbols in the symbol file are not contiguous. This does happen, maybe because of padding/alignment. |
|
411 //qFatal("DoCodesegLookup with aAddress not within any symbol in aCodeSeg"); |
|
412 return TCodeAndSym(NULL, NULL); |
|
413 } |
|
414 |
|
415 HBufC* CBsymFileImpl::GetStringL(TUint32 aLocation, TBool aExpandTokens) const |
|
416 { |
|
417 TPckgBuf<TUint8> len8; |
|
418 User::LeaveIfError(iFile.Read(aLocation, len8)); |
|
419 |
|
420 TUint16 nameLen = (TUint16)len8(); |
|
421 aLocation++; |
|
422 if (nameLen == 255) |
|
423 { |
|
424 TPckgBuf<TUint16> len16; |
|
425 User::LeaveIfError(iFile.Read(aLocation, len16)); |
|
426 nameLen = len16() >> 8 | len16() << 8; |
|
427 aLocation += 2; |
|
428 } |
|
429 RBuf8 temp; |
|
430 CleanupClosePushL(temp); |
|
431 temp.CreateL(nameLen); |
|
432 User::LeaveIfError(iFile.Read(aLocation, temp)); |
|
433 LtkUtils::RLtkBuf res; |
|
434 res.CreateL(nameLen); |
|
435 res.Copy(temp); |
|
436 CleanupStack::PopAndDestroy(&temp); |
|
437 CleanupClosePushL(res); |
|
438 if (aExpandTokens && iVersion >= EVersion2_0) |
|
439 { |
|
440 for (TInt i = res.Length() - 1; i >= 0; i--) |
|
441 { |
|
442 TUint16 val = res[i]; |
|
443 if (val >= 128) |
|
444 { |
|
445 HBufC* token = GetTokenL(val-128); |
|
446 CleanupStack::PushL(token); |
|
447 res.ReplaceL(i, 1, *token); |
|
448 CleanupStack::PopAndDestroy(token); |
|
449 } |
|
450 } |
|
451 |
|
452 } |
|
453 CleanupStack::Pop(&res); |
|
454 return res.ToHBuf(); |
|
455 } |
|
456 |
|
457 void CBsymFileImpl::LoadSymbolNameL(const TSymbol* aSymbol, const TCodeSeg* aParentCodeSeg) |
|
458 { |
|
459 TUint32 prefixIdx = aSymbol->NamePrefixIndex(); |
|
460 if (aParentCodeSeg && prefixIdx) |
|
461 { |
|
462 // Then the symbol name has a prefix that needs looking up separately in the codeseg |
|
463 TUint32 prefixLocation = aParentCodeSeg->PrefixTableOffset() + ((prefixIdx-1) * sizeof(TUint32)); |
|
464 // This location has the offset of the relevant string |
|
465 HBufC* prefix = GetStringL(UnalignedUintL(prefixLocation)); |
|
466 CleanupStack::PushL(prefix); |
|
467 iTempString.AppendL(*prefix); |
|
468 CleanupStack::PopAndDestroy(prefix); |
|
469 iTempString.AppendL(_L("::")); |
|
470 } |
|
471 |
|
472 TUint32 nameOffset = aSymbol->NameOffset(); |
|
473 HBufC* result = GetStringL(nameOffset); |
|
474 CleanupStack::PushL(result); |
|
475 iTempString.AppendL(*result); |
|
476 CleanupStack::PopAndDestroy(result); |
|
477 } |
|
478 |
|
479 TInt CBsymFileImpl::TokenCountL() const |
|
480 { |
|
481 if (iTokensOffset != 0) |
|
482 { |
|
483 return UintL(iTokensOffset); |
|
484 } |
|
485 else |
|
486 { |
|
487 return 0; |
|
488 } |
|
489 } |
|
490 |
|
491 HBufC* CBsymFileImpl::GetTokenL(TInt aToken) const |
|
492 { |
|
493 if (aToken >= TokenCountL()) |
|
494 { |
|
495 LeaveIfErr(KErrCorrupt, _L("Request for token %d >= tokenCount %d"), aToken, TokenCountL()); |
|
496 } |
|
497 TUint32 tokenOffset = UintL(iTokensOffset + 4 + 4*aToken); |
|
498 return GetStringL(tokenOffset, EFalse); |
|
499 } |
|
500 |
|
501 RNode* CBsymFile::CreateCompletionTreeL(const TDesC& aCodesegName) |
|
502 { |
|
503 return static_cast<CBsymFileImpl*>(this)->DoCreateCompletionTreeL(aCodesegName); |
|
504 } |
|
505 |
|
506 RNode* CBsymFileImpl::DoCreateCompletionTreeL(const TDesC& aCodesegName) |
|
507 { |
|
508 CreateCodesegHashIfNeededL(); |
|
509 TCodeSeg* codeseg = iCodeSegHash.Find(aCodesegName); |
|
510 if (!codeseg) |
|
511 { |
|
512 LOG(_L("Couldn't find %S in bsym's codeseg hash"), &aCodesegName); |
|
513 return NULL; |
|
514 } |
|
515 RNode* result = RNode::NewL(); |
|
516 CleanupDeletePushL(result); |
|
517 |
|
518 const TInt symbolcount = codeseg->SymbolCount(); |
|
519 const TUint32 symbolstart = codeseg->SymbolStart(); |
|
520 LOG("Constructing RNode with %d symbols", symbolcount); |
|
521 for (TInt i = 0; i < symbolcount; i++) |
|
522 { |
|
523 TSymbol symbol = SymbolL(symbolstart + i); |
|
524 iTempString.Zero(); |
|
525 LoadSymbolNameL(&symbol, codeseg); |
|
526 iTempString.ReserveExtraL(1); |
|
527 LOG(_L("Adding symbol %S @ 0x%08x"), &iTempString, symbol.Address() - codeseg->Address()); |
|
528 result->InsertStringL(iTempString.PtrZ(), symbol.Address() - codeseg->Address()); |
|
529 } |
|
530 CleanupStack::Pop(result); |
|
531 return result; |
|
532 } |
|
533 |
|
534 void CBsymFileImpl::CreateCodesegHashIfNeededL() |
|
535 { |
|
536 if (iCodeSegHash.Count() > 0) return; // Already populated |
|
537 |
|
538 const TInt count = CodeSegCountL(); |
|
539 iCodeSegHash.ReserveL(count); |
|
540 // Cut down the number of IPC calls by preloading the whole codeseg area in one (since we know we'll need it all) |
|
541 iFileCache.CreateL(4 + count * sizeof(TCodeSeg)); |
|
542 iFileCacheOffset = iCodesegOffset; |
|
543 User::LeaveIfError(iFile.Read(iFileCacheOffset, iFileCache)); |
|
544 for (TInt i = 0; i < count; i++) |
|
545 { |
|
546 TCodeSeg codeseg = CodeSegL(i); |
|
547 iTempString.Zero(); |
|
548 LoadSymbolNameL(&codeseg, NULL); |
|
549 iTempString.Delete(0, iTempString.Length() - TParsePtrC(iTempString).NameAndExt().Length()); |
|
550 |
|
551 LOG(_L("Adding %S to codeseg hash"), &iTempString); |
|
552 iCodeSegHash.InsertL(iTempString, codeseg); |
|
553 if (iVersion < EVersion2_1) |
|
554 { |
|
555 // Fall back to some hacky guesses about possible renamed binaries |
|
556 _LIT(KEuser, "euser_"); |
|
557 if (iTempString.Length() && iTempString[0] == '_') |
|
558 { |
|
559 TInt lastUnderscore = iTempString.LocateReverse('_'); |
|
560 if (lastUnderscore > 0) |
|
561 { |
|
562 iTempString.Delete(0, lastUnderscore + 1); |
|
563 if (iTempString.Length()) iCodeSegHash.InsertL(iTempString, codeseg); |
|
564 } |
|
565 } |
|
566 else if (iTempString.Left(KEuser().Length()) == KEuser) |
|
567 { |
|
568 // EUser appears to be a special case that some platforms do differently, as euser_variant.dll |
|
569 iCodeSegHash.InsertL(_L("euser.dll"), codeseg); |
|
570 } |
|
571 } |
|
572 } |
|
573 |
|
574 if (iVersion >= EVersion2_1) |
|
575 { |
|
576 TUint32 renamesOffset = UintL(0x14); |
|
577 const TInt renamesCount = UintL(renamesOffset); |
|
578 for (TInt i = 0; i < renamesCount; i++) |
|
579 { |
|
580 TUint32 offset = renamesOffset + i*8; |
|
581 TInt codesegIdx = UintL(offset); |
|
582 TUint32 stringOffset = UintL(offset+4); |
|
583 TCodeSeg codeseg = CodeSegL(codesegIdx); |
|
584 GetStringL(stringOffset); |
|
585 iCodeSegHash.InsertL(iTempString, codeseg); |
|
586 } |
|
587 } |
|
588 |
|
589 iFileCache.Close(); |
|
590 } |