|
1 // mapfile.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/bsym.h> |
|
13 #include <fshell/ltkutils.h> |
|
14 #include "bsymtree.h" |
|
15 #include <fshell/descriptorutils.h> |
|
16 |
|
17 #include <fshell/iocli.h> |
|
18 using namespace LtkUtils; |
|
19 using namespace IoUtils; |
|
20 |
|
21 const TInt KSymbolGranularity = 256; // I have no idea... |
|
22 |
|
23 struct SSymbol |
|
24 { |
|
25 TUint iAddress; |
|
26 TUint iLength; |
|
27 HBufC8* iName; |
|
28 }; |
|
29 |
|
30 NONSHARABLE_CLASS(CMapFileImpl) : public CMapFile |
|
31 { |
|
32 public: |
|
33 CMapFileImpl(); |
|
34 ~CMapFileImpl(); |
|
35 void ConstructL(RFs& aFs, const TDesC& aFileName); |
|
36 void DoLookup(TUint32 aOffsetInCodeSeg, TDes& aResult); |
|
37 RNode* DoCreateCompletionTreeL(); |
|
38 |
|
39 private: |
|
40 RArray<SSymbol> iSymbols; |
|
41 }; |
|
42 |
|
43 EXPORT_C CMapFile* CMapFile::NewL(RFs& aFs, const TDesC& aFileName) |
|
44 { |
|
45 CMapFileImpl* result = new (ELeave) CMapFileImpl; |
|
46 CleanupStack::PushL(result); |
|
47 //CleanupStack::PushL((CBase*)1); //DEBUG |
|
48 result->ConstructL(aFs, aFileName); |
|
49 //CleanupStack::Pop(); //DEBUG |
|
50 CleanupStack::Pop(result); |
|
51 return result; |
|
52 } |
|
53 |
|
54 CMapFile::CMapFile() |
|
55 { |
|
56 } |
|
57 |
|
58 CMapFileImpl::CMapFileImpl() |
|
59 : iSymbols(KSymbolGranularity, _FOFF(SSymbol, iAddress)) |
|
60 { |
|
61 } |
|
62 |
|
63 CMapFileImpl::~CMapFileImpl() |
|
64 { |
|
65 const TInt count = iSymbols.Count(); |
|
66 for (TInt i = 0; i < count; i++) |
|
67 { |
|
68 delete iSymbols[i].iName; |
|
69 } |
|
70 iSymbols.Close(); |
|
71 } |
|
72 |
|
73 EXPORT_C CMapFile::~CMapFile() |
|
74 { |
|
75 iReadBuf.Close(); |
|
76 delete iFileName; |
|
77 } |
|
78 |
|
79 #undef LeaveIfErr |
|
80 #define LeaveIfErr(args...) StaticLeaveIfErr(args) |
|
81 |
|
82 void CMapFileImpl::ConstructL(RFs& aFs, const TDesC& aFileName) |
|
83 { |
|
84 iFileName = aFileName.AllocL(); |
|
85 iReadBuf.CreateL(4096); |
|
86 LeaveIfErr(iFile.Open(aFs, aFileName, EFileShareReadersOnly), _L("Couldn't open file %S"), &aFileName); |
|
87 |
|
88 TPtrC8 line; |
|
89 TBool rvct = EFalse; |
|
90 _LIT8(KRvct, "ARM Linker, RVCT"); |
|
91 if (GetNextLine(line) && HasPrefix(line, KRvct)) rvct = ETrue; |
|
92 TBool foundOffset = EFalse; |
|
93 TInt linenum = 0; // for debugging |
|
94 |
|
95 if (rvct) |
|
96 { |
|
97 TInt local = ETrue; |
|
98 while (GetNextLine(line)) |
|
99 { |
|
100 linenum++; |
|
101 if (line.Length() == 0) continue; |
|
102 _LIT8(KRVCTOffsetLine, " Image$$ER_RO$$Base "); |
|
103 if (!foundOffset) |
|
104 { |
|
105 if (HasPrefix(line, KRVCTOffsetLine)) |
|
106 { |
|
107 TLex8 lex(line.Mid(KRVCTOffsetLine().Length())); |
|
108 iTextOffset = HexLexL(lex); |
|
109 foundOffset = ETrue; |
|
110 |
|
111 // No go through any symbols we found before this, and correct their offsets |
|
112 for (TInt i = 0; i < iSymbols.Count(); i++) |
|
113 { |
|
114 iSymbols[i].iAddress -= iTextOffset; |
|
115 } |
|
116 continue; |
|
117 } |
|
118 } |
|
119 |
|
120 _LIT8(KGlobalSection, " Global Symbols"); |
|
121 if (HasPrefix(line, KGlobalSection)) local = EFalse; // We've reached the global section, don't have to ignore so much stuff |
|
122 |
|
123 SSymbol symbol; |
|
124 |
|
125 // This is rather awkward, because there's no proper delimiting between symbol name and the next stuff |
|
126 _LIT8(KSpaces, " "); |
|
127 if (line.Length() < 55) continue; |
|
128 TInt foundSpaces = line.Mid(55).Find(KSpaces); |
|
129 if (foundSpaces == KErrNotFound) continue; |
|
130 TInt spp = 55 + foundSpaces - 10; |
|
131 symbol.iName = line.Left(spp).AllocLC(); |
|
132 symbol.iName->Des().Trim(); |
|
133 |
|
134 TLex8 lex(line); |
|
135 lex.Inc(spp); |
|
136 symbol.iAddress = HexLexL(lex) - iTextOffset; |
|
137 lex.SkipSpace(); |
|
138 if (local) |
|
139 { |
|
140 // In local symbols section we have to worry about non-code stuff |
|
141 _LIT8(KArm, "ARM Code "); |
|
142 _LIT8(KThumb, "Thumb Code"); |
|
143 TPtrC8 type = lex.Remainder().Left(KThumb().Length()); |
|
144 if (type != KArm && type != KThumb) |
|
145 { |
|
146 CleanupStack::PopAndDestroy(symbol.iName); |
|
147 continue; |
|
148 } |
|
149 } |
|
150 |
|
151 lex.Inc(10); // Far enough to get over "ARM Code" or "Thumb Code" |
|
152 lex.SkipSpace(); |
|
153 User::LeaveIfError(lex.Val(symbol.iLength)); |
|
154 if (symbol.iLength == 0) |
|
155 { |
|
156 CleanupStack::PopAndDestroy(symbol.iName); |
|
157 continue; // todo thunks lie about their size... |
|
158 } |
|
159 |
|
160 User::LeaveIfError(iSymbols.Append(symbol)); |
|
161 CleanupStack::Pop(symbol.iName); |
|
162 } |
|
163 } |
|
164 else |
|
165 { |
|
166 while (GetNextLine(line)) |
|
167 { |
|
168 linenum++; |
|
169 _LIT8(KGccTextOffsetLine, "Address of section .text set to "); |
|
170 if (HasPrefix(line, KGccTextOffsetLine)) |
|
171 { |
|
172 // GCCE style |
|
173 TLex8 lex(line.Mid(KGccTextOffsetLine().Length())); |
|
174 iTextOffset = HexLexL(lex); |
|
175 continue; |
|
176 } |
|
177 |
|
178 _LIT8(KFin, ".fini"); |
|
179 if (line == KFin) break; |
|
180 if (line.Length() < 16) continue; |
|
181 TLex8 lex(line); |
|
182 lex.Inc(16); |
|
183 SSymbol symbol; |
|
184 symbol.iLength = 4; // unless otherwise updated by the next symbol addr |
|
185 TInt err = HexLex(lex, symbol.iAddress); |
|
186 if (err) continue; |
|
187 symbol.iAddress -= iTextOffset; |
|
188 lex.SkipSpace(); |
|
189 if (lex.Offset() < 42) continue; // Code symbols have space up to column 42 |
|
190 symbol.iName = lex.Remainder().AllocLC(); |
|
191 |
|
192 User::LeaveIfError(iSymbols.Append(symbol)); |
|
193 CleanupStack::Pop(symbol.iName); |
|
194 } |
|
195 // GCCE doesn't even sort the symbols in its map file. Unbelievable! Or possibly even inconceivable! |
|
196 iSymbols.SortUnsigned(); |
|
197 for (TInt i = 1; i < iSymbols.Count(); i++) |
|
198 { |
|
199 SSymbol& prevSymbol = iSymbols[i - 1]; |
|
200 prevSymbol.iLength = iSymbols[i].iAddress - prevSymbol.iAddress; |
|
201 } |
|
202 } |
|
203 iFile.Close(); |
|
204 iReadBuf.Close(); |
|
205 } |
|
206 |
|
207 TBool CMapFile::GetNextLine(TPtrC8& aPtr) |
|
208 { |
|
209 _LIT8(KNewline, "\r\n"); |
|
210 iReadBuf.Delete(0, aPtr.Length()); |
|
211 if (HasPrefix(iReadBuf, KNewline)) iReadBuf.Delete(0, KNewline().Length()); |
|
212 |
|
213 TInt newline = iReadBuf.Find(KNewline); |
|
214 if (newline != KErrNotFound) |
|
215 { |
|
216 aPtr.Set(iReadBuf.Left(newline)); |
|
217 return ETrue; |
|
218 } |
|
219 // Otherwise need to try reading some more from file |
|
220 TPtr8 restOfDesc((TUint8*)iReadBuf.Ptr() + iReadBuf.Size(), 0, iReadBuf.MaxSize() - iReadBuf.Size()); |
|
221 TInt err = iFile.Read(restOfDesc); |
|
222 if (err) restOfDesc.Zero(); |
|
223 iReadBuf.SetLength(iReadBuf.Length() + restOfDesc.Length()); |
|
224 |
|
225 // Now re-try looking for newline |
|
226 newline = iReadBuf.Find(KNewline); |
|
227 if (newline != KErrNotFound) |
|
228 { |
|
229 aPtr.Set(iReadBuf.Left(newline + KNewline().Length())); |
|
230 return ETrue; |
|
231 } |
|
232 |
|
233 // No more newlines, just return whatever's left in the buffer |
|
234 aPtr.Set(iReadBuf); |
|
235 return aPtr.Length() != 0; // And return whether it's worth having |
|
236 } |
|
237 |
|
238 EXPORT_C void CMapFile::Lookup(TUint32 aOffsetInCodeSeg, TDes& aResult) |
|
239 { |
|
240 //TUint32 offset = aOffsetInCodeSeg & 0xFFFFFFFE; // Mask bottom bit as it just indicates thumb mode |
|
241 CMapFileImpl* impl = static_cast<CMapFileImpl*>(this); // We know we're actually a CMapFileImpl |
|
242 impl->DoLookup(aOffsetInCodeSeg, aResult); |
|
243 } |
|
244 |
|
245 void CMapFileImpl::DoLookup(TUint32 aOffsetInCodeSeg, TDes& aResult) |
|
246 { |
|
247 TInt pos = 0; |
|
248 SSymbol dummy; dummy.iAddress = aOffsetInCodeSeg; |
|
249 TBool found = iSymbols.FindInUnsignedKeyOrder(dummy, pos) == KErrNone; |
|
250 if (!found && pos != 0) pos--; |
|
251 |
|
252 aResult.Zero(); |
|
253 const SSymbol& symbol = iSymbols[pos]; |
|
254 if (aOffsetInCodeSeg >= symbol.iAddress && aOffsetInCodeSeg < symbol.iAddress + symbol.iLength) |
|
255 { |
|
256 aResult.Copy(*symbol.iName); |
|
257 aResult.AppendFormat(_L(" + 0x%x"), aOffsetInCodeSeg - symbol.iAddress); |
|
258 } |
|
259 } |
|
260 |
|
261 EXPORT_C void CMapFile::GetFileNameL(TDes& aFileName) const |
|
262 { |
|
263 aFileName.Copy(*iFileName); |
|
264 } |
|
265 |
|
266 RNode* CMapFile::CreateCompletionTreeL() |
|
267 { |
|
268 CMapFileImpl* impl = static_cast<CMapFileImpl*>(this); // We know we're actually a CMapFileImpl |
|
269 return impl->DoCreateCompletionTreeL(); |
|
270 } |
|
271 |
|
272 RNode* CMapFileImpl::DoCreateCompletionTreeL() |
|
273 { |
|
274 RNode* result = RNode::NewL(); |
|
275 CleanupDeletePushL(result); |
|
276 |
|
277 RLtkBuf tempBuf; |
|
278 tempBuf.CreateLC(256); |
|
279 for (TInt i = 0; i < iSymbols.Count(); i++) |
|
280 { |
|
281 tempBuf.Zero(); |
|
282 tempBuf.AppendL(*iSymbols[i].iName); |
|
283 tempBuf.ReserveExtraL(1); |
|
284 result->InsertStringL(tempBuf.PtrZ(), iSymbols[i].iAddress); |
|
285 } |
|
286 CleanupStack::PopAndDestroy(&tempBuf); |
|
287 CleanupStack::Pop(result); |
|
288 return result; |
|
289 } |