sl@0: // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: _LIT(KBlankLine, "\r"); sl@0: sl@0: class TDll sl@0: { sl@0: public: sl@0: TDll(const TDesC& aName, TUint8* aBase, TInt aSize) sl@0: : iName(aName), iBase((TUint)aBase), iSize((TUint)aSize) sl@0: {} sl@0: sl@0: TFullName iName; sl@0: TUint iBase; sl@0: TUint iSize; sl@0: }; sl@0: sl@0: class TDllList sl@0: { sl@0: public: sl@0: static void FindDlls(); sl@0: static void ResetAndDestroy(); sl@0: static void ListDlls(TFileText& aTextFile); sl@0: static TInt Match(TUint anAddr, const TDll*& aDll); sl@0: sl@0: private: sl@0: static RPointerArray iList; sl@0: }; sl@0: sl@0: RPointerArray TDllList::iList(10); sl@0: sl@0: void TDllList::ResetAndDestroy() sl@0: { sl@0: iList.ResetAndDestroy(); sl@0: } sl@0: sl@0: void TDllList::ListDlls(TFileText& aTextFile) sl@0: { sl@0: TBuf<0x100> line; sl@0: sl@0: _LIT(KDllFormat, "%08x-%08x %S\r"); sl@0: sl@0: aTextFile.Write(KBlankLine); sl@0: for (TInt i=0; iiBase<=anAddr && aDll->iBase+aDll->iSize > anAddr) sl@0: return KErrNone; sl@0: } sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: sl@0: void TDllList::FindDlls() sl@0: // sl@0: // For each library known to the system, look for a chunk of the same name sl@0: // sl@0: { sl@0: TFindLibrary findLib; sl@0: TFullName libName; sl@0: sl@0: while (findLib.Next(libName)==KErrNone) sl@0: { sl@0: TFindChunk findChunk(libName); sl@0: TFullName chunkName; sl@0: if (findChunk.Next(chunkName)!=KErrNone) sl@0: continue; sl@0: RChunk chunk; sl@0: if (chunk.Open(findChunk)!=KErrNone) sl@0: continue; sl@0: TUint8* base=chunk.Base(); sl@0: TInt size=chunk.Size(); sl@0: chunk.Close(); sl@0: TDll* dllptr=new TDll(libName,base,size); sl@0: if (dllptr!=0) sl@0: iList.Append(dllptr); sl@0: } sl@0: } sl@0: sl@0: _LIT(KFormatStackInfo,"Stack %08x-%08x (? %d?), sp=%08x\r"); sl@0: sl@0: HBufC8* GrabStack(const TDesC& /*aLine1*/, TThreadId aId, TUint aSp, TInt& aStackBase, TInt& aStackSize) sl@0: { sl@0: TInt err=KErrNone; sl@0: #if 0 sl@0: // Defect in E32 162 which means that RThread::GetRamSizes will always reset the machine! sl@0: RThread thread; sl@0: if (thread.Open(aId)!=KErrNone) sl@0: return 0; sl@0: sl@0: TInt heapsize=0; sl@0: err=thread.GetRamSizes(heapsize,aStackSize); sl@0: thread.Close(); sl@0: sl@0: if (err!=KErrNone) sl@0: return 0; sl@0: sl@0: // Sanity check sl@0: aStackBase = aSp & ~((1024*1024)-1); sl@0: if (aStackSize<0 || aStackSize>=1024*1024 || aSp>(TUint)(aStackBase+aStackSize)) sl@0: { sl@0: aStackBase=0; // indicates a daft stack pointer sl@0: return 0; sl@0: } sl@0: #else sl@0: // Sanity check & guess at stack size sl@0: aStackBase = aSp & ~((1024*1024)-1); sl@0: aStackSize = (aSp - aStackBase + 4096) & ~4095; // round up to a multiple of the page size sl@0: if (aStackBase+aStackSize-aSp < 200) sl@0: aStackSize += 4096; // seems too small - risk another page! sl@0: if (aStackSize<0 || aStackSize>=1024*1024) sl@0: { sl@0: aStackBase=0; // indicates a daft stack pointer sl@0: return 0; sl@0: } sl@0: aStackSize-=4; // a clue to the wise that this is a guess... sl@0: #endif sl@0: sl@0: // Ask the user if we want to risk grabbing the stack... sl@0: sl@0: TBuf<0x100> line2; sl@0: line2.Format(KFormatStackInfo, aStackBase, aStackBase+aStackSize-1, aStackSize, aSp); sl@0: sl@0: // OK - let stack grabbing commence sl@0: HBufC8* stackbuf = HBufC8::New(aStackSize); sl@0: if (stackbuf==0) sl@0: return 0; sl@0: sl@0: TPtr8 stackdes(stackbuf->Des()); sl@0: err=RDebug::ReadMemory(aId,aStackBase,stackdes,aStackSize); sl@0: if (err!=KErrNone) sl@0: { sl@0: delete stackbuf; sl@0: stackbuf=0; sl@0: } sl@0: return stackbuf; sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: // sl@0: // Reporting more detail of KERN-EXEC 3 errors sl@0: // sl@0: // Warning: This code uses fragile assumptions which may not be true sl@0: // in future releases of EPOC sl@0: // sl@0: // 1) EXEs are located at 0x20000000 sl@0: // 2) the map file for an EXE puts the start of text at 400010 sl@0: // 3) the map file for a DLL puts the start of text at 10000010 sl@0: // 4) the EPOC ROM lives at address 0x50000000 sl@0: // 5) EPOC stacks start at a megabyte boundary sl@0: // sl@0: { sl@0: TBuf<0x100> line1; sl@0: TBuf<0x100> line2; sl@0: SDebugInfo info; sl@0: struct SRegisterInfo reginfo; sl@0: TUint pc = 0; sl@0: TUint regs[16]; sl@0: const TDll* faultDll = NULL; sl@0: sl@0: _LIT(KInfo1, "D_EXC started"); sl@0: User::InfoPrint(KInfo1); sl@0: sl@0: TRequestStatus stat(0); sl@0: // FOREVER sl@0: for (TInt rep=0; rep<2; rep++) // die after two exceptions sl@0: { sl@0: TInt err = KErrNone; sl@0: // wait for any thread to panic... sl@0: sl@0: sl@0: err=RDebug::GetException(info,stat); sl@0: if (err!=KErrNone) sl@0: { sl@0: _LIT(KInfo2, "RDebug failure"); sl@0: User::Panic(KInfo2, err); sl@0: } sl@0: sl@0: User::WaitForRequest(stat); sl@0: sl@0: _LIT(KFormatPanic, "%S panic %S %d\r"); sl@0: _LIT(KFormatException, "%S exception type %d\r"); sl@0: _LIT(KFormatBreakpoint, "%S has breakpoint %d\r"); sl@0: sl@0: sl@0: switch (info.iDebugType) sl@0: { sl@0: case EPanic: sl@0: line1.Format(KFormatPanic,&info.iName,&info.iCategory, info.iPanicType); sl@0: break; sl@0: case EException: sl@0: line1.Format(KFormatException,&info.iName,info.iPanicType); sl@0: break; sl@0: case EBreakPoint: sl@0: line1.Format(KFormatBreakpoint,&info.iName,info.iPanicType); sl@0: break; sl@0: default: sl@0: continue; sl@0: } sl@0: sl@0: // assume that it's KERN-EXEC 3 and try to use the sl@0: // full RDebug support to locate the faulting instruction sl@0: sl@0: HBufC8* stack = NULL; sl@0: TInt stackbase=0; sl@0: TInt stacksize=0; sl@0: sl@0: const TInt KStackPointerReg = 13; sl@0: sl@0: pc = 0x00000001; // illegal value sl@0: sl@0: sl@0: err = RDebug::Open(); sl@0: if (err==KErrNone) sl@0: { sl@0: err = RDebug::RegisterInfo(reginfo); sl@0: if (!err) sl@0: { sl@0: RDebug::GetRegister(info.iId,reginfo.iNumberOfPcRegister, pc); sl@0: for (int i=0; i<16; i++) sl@0: { sl@0: RDebug::GetRegister(info.iId, i, regs[i]); sl@0: } sl@0: } sl@0: sl@0: TDllList::FindDlls(); sl@0: sl@0: stack=GrabStack(line1, info.iId, regs[KStackPointerReg], stackbase, stacksize); sl@0: sl@0: RDebug::Close(); sl@0: } sl@0: sl@0: sl@0: _LIT(KFormatEXE, "pc=%08x, .map equivalent %08x\r"); sl@0: _LIT(KFormatROM, "pc=%08x, in ROM\r"); sl@0: _LIT(KFormatDll, "pc=%08x, in DLL %S, .map equivalent %08x\r"); sl@0: _LIT(KFormatOther, "pc=%08x, iCodeAddr=%08x\r"); sl@0: _LIT(KFormatError, "(Unable to determine pc)\r"); sl@0: sl@0: sl@0: if ((pc&3) == 0) sl@0: { sl@0: if (pc >= 0x20000000 && pc < 0x30000000) sl@0: { sl@0: line2.Format(KFormatEXE, pc, pc-0x20000000+0x400010); sl@0: } sl@0: else if (pc >= 0x50000000 && pc < 0x60000000) sl@0: { sl@0: line2.Format(KFormatROM, pc); sl@0: } sl@0: else if (TDllList::Match(pc, faultDll)==KErrNone) sl@0: { sl@0: line2.Format(KFormatDll, pc, &faultDll->iName, pc-(faultDll->iBase)+0x10000010); sl@0: } sl@0: else sl@0: { sl@0: line2.Format(KFormatOther, pc, info.iCodeAddr); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: line2.Copy(KFormatError); sl@0: } sl@0: sl@0: RFs fs; sl@0: err = fs.Connect(); sl@0: if (err!=KErrNone) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: _LIT(KFormatFilename,"d:\\d_exc_%d.txt"); sl@0: _LIT(KFormatStackname,"d:\\d_exc_%d.stk"); sl@0: sl@0: // Report the basic information about registers, DLLs etc sl@0: sl@0: TFileName name; sl@0: name.Format(KFormatFilename, *(TUint*)&info.iId); sl@0: sl@0: RFile file; sl@0: err=file.Replace(fs, name, EFileWrite+EFileShareAny+EFileStreamText); sl@0: if (err!=KErrNone) sl@0: { sl@0: fs.Close(); sl@0: break; sl@0: } sl@0: sl@0: TFileText textfile; sl@0: textfile.Set(file); sl@0: sl@0: textfile.Write(line1); sl@0: textfile.Write(line2); sl@0: textfile.Write(KBlankLine); sl@0: sl@0: _LIT(KFormatRegisters,"r%02d=%08x %08x %08x %08x\r"); sl@0: sl@0: line2.Format(KFormatRegisters, 0, regs[0], regs[1], regs[2], regs[3]); sl@0: textfile.Write(line2); sl@0: line2.Format(KFormatRegisters, 4, regs[4], regs[5], regs[6], regs[7]); sl@0: textfile.Write(line2); sl@0: line2.Format(KFormatRegisters, 8, regs[8], regs[9], regs[10], regs[11]); sl@0: textfile.Write(line2); sl@0: line2.Format(KFormatRegisters, 12,regs[12], regs[13], regs[14], regs[15]); sl@0: textfile.Write(line2); sl@0: sl@0: if (stackbase!=0) sl@0: { sl@0: line2.Format(KFormatStackInfo, stackbase, stackbase+stacksize-1, stacksize, regs[KStackPointerReg]); sl@0: textfile.Write(line2); sl@0: } sl@0: sl@0: TDllList::ListDlls(textfile); sl@0: TDllList::ResetAndDestroy(); sl@0: sl@0: file.Close(); sl@0: sl@0: // Dump the stack as binary data sl@0: sl@0: if (stack) sl@0: { sl@0: name.Format(KFormatStackname, *(TUint*)&info.iId); sl@0: err=file.Replace(fs, name, EFileWrite+EFileShareAny+EFileStreamText); sl@0: if (err==KErrNone) sl@0: { sl@0: file.Write(*stack); sl@0: file.Close(); sl@0: } sl@0: } sl@0: delete stack; sl@0: sl@0: fs.Close(); sl@0: } sl@0: return stat.Int(); sl@0: } sl@0: sl@0: