libraries/ltkutils/src/bsym.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     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 	}