|
1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #include <e32std.h> |
|
17 #include <e32svr.h> |
|
18 #include <f32file.h> |
|
19 |
|
20 _LIT(KBlankLine, "\r"); |
|
21 |
|
22 class TDll |
|
23 { |
|
24 public: |
|
25 TDll(const TDesC& aName, TUint8* aBase, TInt aSize) |
|
26 : iName(aName), iBase((TUint)aBase), iSize((TUint)aSize) |
|
27 {} |
|
28 |
|
29 TFullName iName; |
|
30 TUint iBase; |
|
31 TUint iSize; |
|
32 }; |
|
33 |
|
34 class TDllList |
|
35 { |
|
36 public: |
|
37 static void FindDlls(); |
|
38 static void ResetAndDestroy(); |
|
39 static void ListDlls(TFileText& aTextFile); |
|
40 static TInt Match(TUint anAddr, const TDll*& aDll); |
|
41 |
|
42 private: |
|
43 static RPointerArray<TDll> iList; |
|
44 }; |
|
45 |
|
46 RPointerArray<TDll> TDllList::iList(10); |
|
47 |
|
48 void TDllList::ResetAndDestroy() |
|
49 { |
|
50 iList.ResetAndDestroy(); |
|
51 } |
|
52 |
|
53 void TDllList::ListDlls(TFileText& aTextFile) |
|
54 { |
|
55 TBuf<0x100> line; |
|
56 |
|
57 _LIT(KDllFormat, "%08x-%08x %S\r"); |
|
58 |
|
59 aTextFile.Write(KBlankLine); |
|
60 for (TInt i=0; i<iList.Count(); i++) |
|
61 { |
|
62 const TDll& dll=*(iList[i]); |
|
63 line.Format(KDllFormat, dll.iBase, dll.iBase+dll.iSize-1, &dll.iName); |
|
64 aTextFile.Write(line); |
|
65 } |
|
66 } |
|
67 |
|
68 TInt TDllList::Match(TUint anAddr, const TDll*& aDll) |
|
69 { |
|
70 for (TInt i=0; i<iList.Count(); i++) |
|
71 { |
|
72 aDll=iList[i]; |
|
73 if (aDll->iBase<=anAddr && aDll->iBase+aDll->iSize > anAddr) |
|
74 return KErrNone; |
|
75 } |
|
76 return KErrNotFound; |
|
77 } |
|
78 |
|
79 |
|
80 void TDllList::FindDlls() |
|
81 // |
|
82 // For each library known to the system, look for a chunk of the same name |
|
83 // |
|
84 { |
|
85 TFindLibrary findLib; |
|
86 TFullName libName; |
|
87 |
|
88 while (findLib.Next(libName)==KErrNone) |
|
89 { |
|
90 TFindChunk findChunk(libName); |
|
91 TFullName chunkName; |
|
92 if (findChunk.Next(chunkName)!=KErrNone) |
|
93 continue; |
|
94 RChunk chunk; |
|
95 if (chunk.Open(findChunk)!=KErrNone) |
|
96 continue; |
|
97 TUint8* base=chunk.Base(); |
|
98 TInt size=chunk.Size(); |
|
99 chunk.Close(); |
|
100 TDll* dllptr=new TDll(libName,base,size); |
|
101 if (dllptr!=0) |
|
102 iList.Append(dllptr); |
|
103 } |
|
104 } |
|
105 |
|
106 _LIT(KFormatStackInfo,"Stack %08x-%08x (? %d?), sp=%08x\r"); |
|
107 //_LIT(KGrabStack,"Capture stack data"); |
|
108 //_LIT(KNoStack,"Don't risk it"); |
|
109 |
|
110 HBufC8* GrabStack(const TDesC& /*aLine1*/, TThreadId aId, TUint aSp, TInt& aStackBase, TInt& aStackSize) |
|
111 { |
|
112 TInt err=KErrNone; |
|
113 #if 0 |
|
114 // Defect in E32 162 which means that RThread::GetRamSizes will always reset the machine! |
|
115 RThread thread; |
|
116 if (thread.Open(aId)!=KErrNone) |
|
117 return 0; |
|
118 |
|
119 TInt heapsize=0; |
|
120 err=thread.GetRamSizes(heapsize,aStackSize); |
|
121 thread.Close(); |
|
122 |
|
123 if (err!=KErrNone) |
|
124 return 0; |
|
125 |
|
126 // Sanity check |
|
127 aStackBase = aSp & ~((1024*1024)-1); |
|
128 if (aStackSize<0 || aStackSize>=1024*1024 || aSp>(TUint)(aStackBase+aStackSize)) |
|
129 { |
|
130 aStackBase=0; // indicates a daft stack pointer |
|
131 return 0; |
|
132 } |
|
133 #else |
|
134 // Sanity check & guess at stack size |
|
135 aStackBase = aSp & ~((1024*1024)-1); |
|
136 aStackSize = (aSp - aStackBase + 4096) & ~4095; // round up to a multiple of the page size |
|
137 if (aStackBase+aStackSize-aSp < 200) |
|
138 aStackSize += 4096; // seems too small - risk another page! |
|
139 if (aStackSize<0 || aStackSize>=1024*1024) |
|
140 { |
|
141 aStackBase=0; // indicates a daft stack pointer |
|
142 return 0; |
|
143 } |
|
144 aStackSize-=4; // a clue to the wise that this is a guess... |
|
145 #endif |
|
146 |
|
147 // Ask the user if we want to risk grabbing the stack... |
|
148 |
|
149 TBuf<0x100> line2; |
|
150 line2.Format(KFormatStackInfo, aStackBase, aStackBase+aStackSize-1, aStackSize, aSp); |
|
151 //Don't ask the user just do it for WSERV |
|
152 /*RNotifier ask; |
|
153 if (ask.Connect() != KErrNone) |
|
154 return 0; |
|
155 TRequestStatus status; |
|
156 TInt buttonval=1; |
|
157 ask.Notify(aLine1,line2,KGrabStack,KNoStack,buttonval,status); |
|
158 User::WaitForRequest(status); |
|
159 ask.Close(); |
|
160 if (status.Int()!=KErrNone || buttonval != 0) |
|
161 return 0;*/ |
|
162 |
|
163 // OK - let stack grabbing commence |
|
164 HBufC8* stackbuf = HBufC8::New(aStackSize); |
|
165 if (stackbuf==0) |
|
166 return 0; |
|
167 |
|
168 TPtr8 stackdes(stackbuf->Des()); |
|
169 err=RDebug::ReadMemory(aId,aStackBase,stackdes,aStackSize); |
|
170 if (err!=KErrNone) |
|
171 { |
|
172 delete stackbuf; |
|
173 stackbuf=0; |
|
174 } |
|
175 return stackbuf; |
|
176 } |
|
177 |
|
178 GLDEF_C TInt E32Main() |
|
179 // |
|
180 // Reporting more detail of KERN-EXEC 3 errors |
|
181 // |
|
182 // Warning: This code uses fragile assumptions which may not be true |
|
183 // in future releases of EPOC |
|
184 // |
|
185 // 1) EXEs are located at 0x20000000 |
|
186 // 2) the map file for an EXE puts the start of text at 400010 |
|
187 // 3) the map file for a DLL puts the start of text at 10000010 |
|
188 // 4) the EPOC ROM lives at address 0x50000000 |
|
189 // 5) EPOC stacks start at a megabyte boundary |
|
190 // |
|
191 { |
|
192 TBuf<0x100> line1; |
|
193 TBuf<0x100> line2; |
|
194 SDebugInfo info; |
|
195 struct SRegisterInfo reginfo; |
|
196 TUint pc; |
|
197 TUint regs[16]; |
|
198 const TDll* faultDll; |
|
199 |
|
200 _LIT(KInfo1, "D_EXC started"); |
|
201 User::InfoPrint(KInfo1); |
|
202 |
|
203 TRequestStatus stat(0); |
|
204 // FOREVER |
|
205 for (TInt rep=0; rep<2; rep++) // die after two exceptions |
|
206 { |
|
207 TInt err; |
|
208 // wait for any thread to panic... |
|
209 |
|
210 |
|
211 err=RDebug::GetException(info,stat); |
|
212 if (err!=KErrNone) |
|
213 { |
|
214 _LIT(KInfo2, "RDebug failure"); |
|
215 User::Panic(KInfo2, err); |
|
216 } |
|
217 |
|
218 User::WaitForRequest(stat); |
|
219 |
|
220 _LIT(KFormatPanic, "%S panic %S %d\r"); |
|
221 _LIT(KFormatException, "%S exception type %d\r"); |
|
222 _LIT(KFormatBreakpoint, "%S has breakpoint %d\r"); |
|
223 |
|
224 |
|
225 switch (info.iDebugType) |
|
226 { |
|
227 case EPanic: |
|
228 line1.Format(KFormatPanic,&info.iName,&info.iCategory, info.iPanicType); |
|
229 break; |
|
230 case EException: |
|
231 line1.Format(KFormatException,&info.iName,info.iPanicType); |
|
232 break; |
|
233 case EBreakPoint: |
|
234 line1.Format(KFormatBreakpoint,&info.iName,info.iPanicType); |
|
235 break; |
|
236 default: |
|
237 continue; |
|
238 } |
|
239 |
|
240 // assume that it's KERN-EXEC 3 and try to use the |
|
241 // full RDebug support to locate the faulting instruction |
|
242 |
|
243 HBufC8* stack=0; |
|
244 TInt stackbase=0; |
|
245 TInt stacksize=0; |
|
246 |
|
247 const TInt KStackPointerReg = 13; |
|
248 |
|
249 pc = 0x00000001; // illegal value |
|
250 |
|
251 |
|
252 err = RDebug::Open(); |
|
253 if (err==KErrNone) |
|
254 { |
|
255 err = RDebug::RegisterInfo(reginfo); |
|
256 if (!err) |
|
257 { |
|
258 RDebug::GetRegister(info.iId,reginfo.iNumberOfPcRegister, pc); |
|
259 for (int i=0; i<16; i++) |
|
260 RDebug::GetRegister(info.iId, i, regs[i]); |
|
261 } |
|
262 |
|
263 TDllList::FindDlls(); |
|
264 |
|
265 stack=GrabStack(line1, info.iId, regs[KStackPointerReg], stackbase, stacksize); |
|
266 |
|
267 //RDebug::KillThread(info.iId); |
|
268 RDebug::Close(); |
|
269 } |
|
270 |
|
271 |
|
272 _LIT(KFormatEXE, "pc=%08x, .map equivalent %08x\r"); |
|
273 _LIT(KFormatROM, "pc=%08x, in ROM\r"); |
|
274 _LIT(KFormatDll, "pc=%08x, in DLL %S, .map equivalent %08x\r"); |
|
275 _LIT(KFormatOther, "pc=%08x, iCodeAddr=%08x\r"); |
|
276 _LIT(KFormatError, "(Unable to determine pc)\r"); |
|
277 |
|
278 if ((pc&3) == 0) |
|
279 { |
|
280 if (pc >= 0x20000000 && pc < 0x30000000) |
|
281 line2.Format(KFormatEXE, pc, pc-0x20000000+0x400010); |
|
282 else |
|
283 if (pc >= 0x50000000 && pc < 0x60000000) |
|
284 line2.Format(KFormatROM, pc); |
|
285 else |
|
286 if (TDllList::Match(pc, faultDll)==KErrNone) |
|
287 line2.Format(KFormatDll, pc, &faultDll->iName, pc-(faultDll->iBase)+0x10000010); |
|
288 |
|
289 else |
|
290 line2.Format(KFormatOther, pc, info.iCodeAddr); |
|
291 |
|
292 } |
|
293 else |
|
294 line2.Copy(KFormatError); |
|
295 |
|
296 RFs fs; |
|
297 err = fs.Connect(); |
|
298 if (err!=KErrNone) |
|
299 break; |
|
300 |
|
301 _LIT(KFormatFilename,"d:\\d_exc_%d.txt"); |
|
302 _LIT(KFormatStackname,"d:\\d_exc_%d.stk"); |
|
303 |
|
304 // Report the basic information about registers, DLLs etc |
|
305 |
|
306 TFileName name; |
|
307 name.Format(KFormatFilename, *(TUint*)&info.iId); |
|
308 |
|
309 RFile file; |
|
310 err=file.Replace(fs, name, EFileWrite+EFileShareAny+EFileStreamText); |
|
311 if (err!=KErrNone) |
|
312 break; |
|
313 |
|
314 TFileText textfile; |
|
315 textfile.Set(file); |
|
316 |
|
317 textfile.Write(line1); |
|
318 textfile.Write(line2); |
|
319 textfile.Write(KBlankLine); |
|
320 |
|
321 _LIT(KFormatRegisters,"r%02d=%08x %08x %08x %08x\r"); |
|
322 |
|
323 line2.Format(KFormatRegisters, 0, regs[0], regs[1], regs[2], regs[3]); |
|
324 textfile.Write(line2); |
|
325 line2.Format(KFormatRegisters, 4, regs[4], regs[5], regs[6], regs[7]); |
|
326 textfile.Write(line2); |
|
327 line2.Format(KFormatRegisters, 8, regs[8], regs[9], regs[10], regs[11]); |
|
328 textfile.Write(line2); |
|
329 line2.Format(KFormatRegisters, 12,regs[12], regs[13], regs[14], regs[15]); |
|
330 textfile.Write(line2); |
|
331 |
|
332 if (stackbase!=0) |
|
333 { |
|
334 line2.Format(KFormatStackInfo, stackbase, stackbase+stacksize-1, stacksize, regs[KStackPointerReg]); |
|
335 textfile.Write(line2); |
|
336 } |
|
337 |
|
338 TDllList::ListDlls(textfile); |
|
339 TDllList::ResetAndDestroy(); |
|
340 |
|
341 file.Close(); |
|
342 |
|
343 // Dump the stack as binary data |
|
344 |
|
345 if (stack) |
|
346 { |
|
347 name.Format(KFormatStackname, *(TUint*)&info.iId); |
|
348 err=file.Replace(fs, name, EFileWrite+EFileShareAny+EFileStreamText); |
|
349 if (err==KErrNone) |
|
350 { |
|
351 file.Write(*stack); |
|
352 file.Close(); |
|
353 } |
|
354 } |
|
355 delete stack; |
|
356 |
|
357 fs.Close(); |
|
358 } |
|
359 return stat.Int(); |
|
360 } |
|
361 |
|
362 |