--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dbgsrv/coredumpserver/plugins/formatters/dexc/src/dexcformatter.cpp Tue Mar 02 10:33:16 2010 +0530
@@ -0,0 +1,736 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "dexcformatter.h"
+//
+// there is a line limit but what if file name is longer?
+//
+
+/**
+1st stage construction
+@return pointer to the newly created object, caller takes ownership of the object.
+*/
+CDexcFormatter* CDexcFormatter::NewL()
+{
+ LOG_MSG("->CDexcFormatter::NewL()\n");
+ CDexcFormatter* self = CDexcFormatter::NewLC();
+ CleanupStack::Pop(self);
+ return self;
+}
+
+/**
+1st stage construction
+@return pointer to the newly created object, caller takes ownership of the object.
+*/
+CDexcFormatter* CDexcFormatter::NewLC()
+{
+ LOG_MSG("->CDexcFormatter::NewLC()\n");
+ CDexcFormatter* self = new(ELeave) CDexcFormatter();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+}
+
+/**
+2nd stage construction
+Reserves config parameter list, creates config parameter objects and sets them to default values.
+*/
+void CDexcFormatter::ConstructL()
+{
+ LOG_MSG("->CDexcFormatter::ConstructL()\n");
+ TInt err;
+ COptionConfig * config;
+
+ iConfigList.ReserveL( (TInt)EDexcParamsLast );
+
+ _LIT( KTrueFalseOpt, "True,False" );
+ _LIT( KTrueOpt, "True" );
+ _LIT( KFalseOpt, "False" );
+
+ _LIT( KDumpStackPrompt, "Dump stack memory?" );
+ config = COptionConfig::NewL( (TInt)EDumpStack,
+ KDEXCFormatterUid,
+ COptionConfig::EFormatterPlugin,
+ COptionConfig::ETBool,
+ KDumpStackPrompt,
+ 1,
+ KTrueFalseOpt,
+ 1,
+ KTrueOpt );
+
+ err = iConfigList.Append( config );
+
+ if(err != KErrNone)
+ {
+ delete config;
+ LOG_MSG("CDexcFormatter::ConstructL - unable to append dump stack config option!\n" );
+ User::Leave(err);
+ }
+ iDumpStack = ETrue;
+
+ _LIT( KDumpAsciiPrompt, "Stack contents in ASCII?" );
+ config = COptionConfig::NewL( (TInt)EAsciiStack,
+ KDEXCFormatterUid,
+ COptionConfig::EFormatterPlugin,
+ COptionConfig::ETBool,
+ KDumpAsciiPrompt,
+ 1,
+ KTrueFalseOpt,
+ 0,
+ KFalseOpt );
+
+ err = iConfigList.Append( config );
+ if(err != KErrNone)
+ {
+ delete config;
+ LOG_MSG("CDexcFormatter::ConstructL - unable to append dump ascii config option!\n" );
+ User::Leave(err);
+ }
+ iAsciiStack = EFalse;
+}
+
+/**
+dtor frees config parameter list
+*/
+CDexcFormatter::~CDexcFormatter()
+{
+ LOG_MSG("->~CDexcFormatter()\n");
+ iConfigList.ResetAndDestroy();
+}
+
+/**
+ Sets pointer to the writer plugin.
+ Configures formatter's dump data save plugin.
+
+@param aDataSave pointer to writer plugin object.
+@leave KErrNoMemory if aDataSave is NULL
+*/
+void CDexcFormatter::ConfigureDataSaveL(CCrashDataSave* aDataSave)
+{
+ LOG_MSG2("->ConfigureDataSaveL(%d)\n", aDataSave);
+ User::LeaveIfNull(aDataSave);
+ iDataSave = aDataSave;
+}
+
+/**
+ Sets pointer to the crash data server.
+ Configures formatter's crash data source plugin.
+
+@param aDataSource pointer to core dump server object.
+@leave KErrNoMemory if aDataSource is NULL
+*/
+void CDexcFormatter::ConfigureDataSourceL(CCrashDataSource* aDataSource)
+{
+ LOG_MSG2("->ConfigureDataSourceL(%d)\n", aDataSource);
+ User::LeaveIfNull(aDataSource);
+ iDataSource = aDataSource;
+}
+
+/**
+ Returns a short formatter description.
+@param aPluginDescription Descriptor capable of storing a short plugin description.
+*/
+void CDexcFormatter::GetDescription(TDes& aPluginDescription)
+{
+ LOG_MSG("->CDexcFormatter::GetDescription()\n");
+ aPluginDescription.Copy(KPluginDescription());
+}
+
+
+/**
+Called by CDS to ask for the configuration parameters that the writer needs (see Plugin Configuration)
+@return actual number of implemented config parameters
+*/
+TInt CDexcFormatter::GetNumberConfigParametersL( )
+{
+ TInt count = iConfigList.Count();
+ LOG_MSG2("->CDexcFormatter::GetNumberConfigParametersL() : returns:%d\n", count );
+ return count;
+}
+
+
+/**
+Called by CDS to ask for configuration parameter prompt (see Plugin Configuration)
+
+@param aIndex indicates which parameter to return
+@return pointer to COptionConfig object representing the requested config parameter. Caller doesn't take ownership of the object!
+@leave KErrBadHandle if index is out of bounds
+@see COptionConfig
+*/
+COptionConfig * CDexcFormatter::GetConfigParameterL( const TInt aIndex )
+{
+ // return the config identified by aIndex
+ if( ( aIndex < 0 ) || ( aIndex >= iConfigList.Count() ) )
+ {
+ User::Leave( KErrBadHandle );
+ }
+
+ return iConfigList[aIndex];
+}
+
+/**
+Change a configuration parameter.
+@param aIndex Index of parameter to change
+@param aValue Unused
+@param aDescValue Path and filename to use
+@leave KErrBadHandle if index is out of bounds or one of the other system wide error codes
+*/
+void CDexcFormatter::SetConfigParameterL( const TInt aIndex, const TInt32 & aValue, const TDesC & aDescValue )
+{
+ if( ( aIndex < 0 ) || ( aIndex >= iConfigList.Count() ) )
+ {
+ User::Leave( KErrBadHandle );
+ }
+
+ COptionConfig & config = *(iConfigList[aIndex]);
+
+ if( ( aIndex != (TInt)EDumpStack ) && ( aIndex != (TInt)EAsciiStack ) )
+ {
+ LOG_MSG( " Leaving : aIndex != EDumpStack && aIndex != EAsciiStack" );
+ User::Leave( KErrArgument );
+ }
+
+ TBool setTo = ETrue;
+
+ if( aDescValue.Length() )
+ {
+ if( 0 == aDescValue.CompareF(_L("True") ) )
+ {
+ setTo = ETrue;
+ //LOG_MSG( " 0 == aDescValue.CompareF(_L(True" );
+ }
+ else if( 0 == aDescValue.CompareF(_L("False") ) )
+ {
+ //LOG_MSG( " 0 == aDescValue.CompareF(_L(False" );
+ setTo = EFalse;
+ }
+ else
+ {
+ LOG_MSG( " ERROR !* : CDexcFormatter::SetConfigParameterL : Invalid string for boolean" );
+ User::Leave( KErrArgument );
+ }
+ }
+ else
+ {
+ if( 1 == aValue )
+ {
+ //LOG_MSG( " 1 == aValue" );
+ setTo = ETrue;
+ }
+ else if ( 0 == aValue )
+ {
+ //LOG_MSG( " 0 == aValue " );
+ setTo = EFalse;
+ }
+ else
+ {
+ LOG_MSG( " Value of %d not valid. Must be 0 or 1\n" );
+ User::Leave( KErrArgument );
+ }
+ }
+
+
+ if( setTo )
+ {
+ config.Value( 1 );
+ config.ValueL( _L("True") );
+ }
+ else
+ {
+ config.Value( 0 );
+ config.ValueL( _L("False") );
+ }
+
+ if( aIndex == (TInt)EDumpStack )
+ {
+ iDumpStack = config.ValueAsBool();
+ }
+ else if( aIndex == (TInt)EAsciiStack )
+ {
+ iAsciiStack = config.ValueAsBool();
+ }
+}
+
+/**
+ Dumps basic information about the thread that crashed.
+@param aThread TThreadInfo data structure holding information about the crashed thread.
+@leave err one of the system wide error codes
+*/
+void CDexcFormatter::DumpLogL(const CThreadInfo& aThread)
+{
+ LOG_MSG("->DumpLogL()\n");
+ iLine.Fill('-', 76);
+ iDataSave->WriteL(iLine);
+
+ _LIT8(KHdr, "\r\nEKA2 USER CRASH LOG\r\n");
+ iLine = KHdr;
+ iDataSave->WriteL(iLine);
+
+ RBuf8 filename;
+ filename.CreateL(KMaxFileName);
+ filename.Copy(aThread.Name());
+ _LIT8(KName, "Thread Name: %S\r\n");
+ iLine.Format(KName, &filename);
+ filename.Close();
+ iDataSave->WriteL(iLine);
+
+ _LIT8(KFmtTid, "Thread ID: %u\r\n");
+ iLine.Format(KFmtTid, aThread.Id());
+ iDataSave->WriteL(iLine);
+
+ _LIT8(KFmtStack, "User Stack %08X-%08X\r\n");
+ iLine.Format(KFmtStack, aThread.UsrStackAddr(), aThread.UsrStackAddr() + aThread.UsrStackSize());
+ iDataSave->WriteL(iLine);
+}
+/**
+ Dumps panic details.
+@param aCrash TCrashInfo data structure holding information about the crash.
+@leave err one of the system wide error codes
+*/
+void CDexcFormatter::DumpPanicInfoL(const TCrashInfo& aCrash)
+{
+ LOG_MSG("->DumpPanicInfoL()\n");
+ //_LIT8(KFmtPanic, "\r\nPanic: %S-%d\r\n");
+ _LIT8(KFmtPanic, "Panic: %S-%d\r\n");
+ RBuf8 buf;
+ buf.CreateL(aCrash.iCategory.Length());
+ buf.Copy(aCrash.iCategory);
+ iLine.Format(KFmtPanic, &buf, aCrash.iReason);
+ buf.Close();
+ iDataSave->WriteL(iLine);
+}
+
+/**
+ Picks registers from available register list and puts them in the required register list.
+ Order of the output list is determined by the order of aReqIds.
+
+@param aAllRegs input RRegisterList of all available registers.
+@param aReqRegs output RRegisterList for the required registers.
+@param aReqIds EDF_Register_Last terminated array of IDs of required registers.
+@return KErrNone if successful, otherwise one of the other system-wide error codes.
+*/
+TInt CDexcFormatter::PickRegisters(const RRegisterList& aAllRegs, RRegisterList& aReqRegs,
+ const TFunctionalityRegister* const aReqIds) const
+{
+ LOG_MSG("->CDexcFormatter::PickRegistersL()\n");
+ if(aReqIds == NULL)
+ {
+ return KErrArgument;
+ }
+
+ TInt regsCount = aAllRegs.Count();
+ const TFunctionalityRegister* reg;
+ for(reg = aReqIds; *reg != ERegisterLast; ++reg)
+ {
+ for(TInt i = 0; i < regsCount; ++i)
+ {
+ if(aAllRegs[i].GetId() == *reg)
+ {
+ aReqRegs.Append(aAllRegs[i]);
+ break;
+ }
+ }
+ }
+
+ if(aReqRegs.Count() != (reg - aReqIds))
+ {
+ LOG_MSG3("CDExcFormatter::PickRegisters - found only %d out of %d registers!\n", aReqRegs.Count(), (reg - aReqIds));
+ return KErrNotFound;
+ }
+ return KErrNone;
+}
+
+/**
+ Dumps exception details. Valid on ARM platform only!
+
+@param aCrash TCrashInfo data structure holding information about the crash event.
+@leave err one of the system wide error codes
+*/
+void CDexcFormatter::DumpExcInfoL(const TCrashInfo& aCrash)
+{
+ LOG_MSG("-> CDexcFormatter::DumpExcInfoL()\n");
+
+ _LIT8(KHdr, "\r\nUNHANDLED EXCEPTION:\r\n");
+ iLine = KHdr;
+ iDataSave->WriteL(iLine);
+
+ _LIT8(KFmt1, "code=%d PC=%08x FAR=%08x FSR=%08x\r\n");
+ iLine.Format(KFmt1, aCrash.iContext.iExcCode,
+ aCrash.iContext.iR15,
+ aCrash.iContext.iFaultAddress,
+ aCrash.iContext.iFaultStatus);
+ iDataSave->WriteL(iLine);
+
+ _LIT8(KFmt2, "R13svc=%08x R14svc=%08x SPSRsvc=%08x\r\n");
+ iLine.Format(KFmt2, aCrash.iContext.iR13Svc,
+ aCrash.iContext.iR14Svc,
+ aCrash.iContext.iSpsrSvc);
+ iDataSave->WriteL(iLine);
+
+ LOG_MSG("<- CDexcFormatter::DumpExcInfoL()\n");
+}
+
+/**
+ Dumps register values of the crashed thread. Valid on ARM platform only!
+@param aTid ID of the crashed thread
+@leave err one of the system wide error codes
+*/
+void CDexcFormatter::DumpRegistersL(const TUint64 aTid)
+{
+ LOG_MSG2("-> CDexcFormatter::DumpRegistersL(%Lu)\n", aTid);
+
+ TFunctionalityRegister ids[] = {ERegisterR0,
+ ERegisterR1,
+ ERegisterR2,
+ ERegisterR3,
+ ERegisterR4,
+ ERegisterR5,
+ ERegisterR6,
+ ERegisterR7,
+ ERegisterR8,
+ ERegisterR9,
+ ERegisterR10,
+ ERegisterR11,
+ ERegisterR12,
+ ERegisterR13,
+ ERegisterR14,
+ ERegisterR15,
+ ERegisterCpsr,
+ ERegisterLast};
+
+ RRegisterList allRegs;
+ CleanupClosePushL(allRegs);
+ RRegisterList reqRegs;
+ CleanupClosePushL(reqRegs);
+
+ _LIT8(KHdr, "\r\nUSER REGISTERS:\r\n");
+ iLine = KHdr;
+ iDataSave->WriteL(iLine);
+
+ LOG_MSG("CDexcFormatter::DumpRegistersL - getting list of avaliable registers\n");
+ iDataSource->GetRegisterListL(allRegs);
+
+ LOG_MSG("CDexcFormatter::DumpRegistersL - picking required registers\n");
+ User::LeaveIfError(PickRegisters(allRegs, reqRegs, ids));
+
+ LOG_MSG("CDexcFormatter::DumpRegistersL - reading data of required registers\n");
+ iDataSource->ReadRegistersL(aTid, reqRegs);
+
+ //display zeros when register is not available
+ //use AppendFormat to get rid of this macro
+#define REG_VAL(i) reqRegs[i].iAvailable ? reqRegs[i].GetContent32() : 0
+ _LIT8(KFmtCpsr, "CPSR=%08x\r\n");
+ TInt regsCount = reqRegs.Count();
+ iLine.Format(KFmtCpsr, REG_VAL(regsCount - 1));
+ iDataSave->WriteL(iLine);
+
+ regsCount -= 4;
+ for(TInt i = 0; i < regsCount; i+=4)
+ {
+ _LIT8(KFmtReg, "r%02d=%08x %08x %08x %08x\r\n");
+ iLine.Format(KFmtReg, i, REG_VAL(i), REG_VAL(i+1), REG_VAL(i+2), REG_VAL(i+3));
+ iDataSave->WriteL(iLine);
+ }
+#undef REG_VAL
+ CleanupStack::PopAndDestroy(2, &allRegs);
+}
+
+/**
+Cleanup item implementation for code segment list in DumpCodeSegsL() method.
+@param aArray pointer to the list that is supposed to be freed
+*/
+void CDexcFormatter::CleanupCodeSegList(TAny *aArray)
+{
+ LOG_MSG("->CDexcFormatter::CleanupCodeSegList()\n");
+ RCodeSegPointerList *codeSegList = static_cast<RCodeSegPointerList*> (aArray);
+ codeSegList->ResetAndDestroy();
+ codeSegList->Close();
+}
+
+/**
+ Dumps code segments of the process that owned the crashed thread.
+@param aTid ID of the crashed thread
+@leave err one of the system wide error codes
+*/
+void CDexcFormatter::DumpCodeSegsL(const TUint64 aTid)
+{
+ LOG_MSG2("-> CDexcFormatter::DumpCodeSegsL(%Lu)\n", aTid);
+ _LIT8(KHdr, "\r\nCODE SEGMENTS:\r\n");
+ _LIT8(KFmtSegs, "%08X-%08X %S\r\n");
+
+ iLine = KHdr;
+ iDataSave->WriteL(iLine);
+
+ RCodeSegPointerList segs;
+ TCleanupItem cleanup(CDexcFormatter::CleanupCodeSegList, (TAny*)&segs);
+ CleanupStack::PushL(cleanup);
+
+ //User::LeaveIfError(iDataSource->GetCodeSegments(aPid, segs));
+ LOG_MSG("CDexcFormatter::DumpCodeSegsL() - getting code segments data\n");
+ iDataSource->GetCodeSegmentsL(aTid, segs);
+
+ RBuf8 filename;
+ CleanupClosePushL(filename);
+ filename.CreateL(KMaxFileName);
+ for (TInt i=0; i < segs.Count(); i++)
+ {
+ filename.Copy(segs[i]->iName); //conversion
+ iLine.Format(KFmtSegs, segs[i]->iCodeRunAddr, segs[i]->iCodeRunAddr + segs[i]->iCodeSize, &filename);
+ iDataSave->WriteL(iLine);
+ }
+ LOG_MSG2("CDexcFormatter::DumpCodeSegsL - code segments count:%d\n", segs.Count());
+ CleanupStack::PopAndDestroy(2);
+
+ //compatibility with legacy D_EXC implementation
+ iLine.Zero();
+ iLine.Append(_L8("\r\n"));
+ iDataSave->WriteL(iLine);
+}
+
+/**
+ Dumps thread stack information and content.
+@param aTid ID of the crashed thread
+@param aInfo CThreadInfo data structure holding information about the crashed thread
+@leave err one of the system wide error codes
+*/
+void CDexcFormatter::DumpStackL(const TUint64 aTid, const CThreadInfo& aInfo)
+{
+ LOG_MSG2("-> CDexcFormatter::DumpStackL(%Lu)\n", aTid);
+
+ TInt length = KBufSize < aInfo.UsrStackSize() ? KBufSize : aInfo.UsrStackSize();
+
+ RBuf8 buf;
+ buf.CreateL(length);
+ CleanupClosePushL(buf);
+
+ TUint top = aInfo.UsrStackAddr() + aInfo.UsrStackSize();
+ for(TUint base = aInfo.UsrStackAddr(); base < top; base += KBufSize)
+ {
+ LOG_MSG3("CDexcFormatter::DumpStackL - reading %d bytes of memory from:0x%X\n", length, base);
+ iDataSource->ReadMemoryL(aTid, base, length, buf);
+
+ //6571de54: 07 00 00 10 14 04 17 f8 00 00 00 00 d4 4e 40 00 .............N@.
+ //<-addr-------------------------memory----------------------representation>
+ if(iAsciiStack)
+ {
+ TBuf8<80> out; //74 used
+ TBuf8<20> ascii; //16 usd
+ TInt len = buf.Length();
+ for(TUint offset = 0; offset < len; offset += 16)
+ {
+ out.Zero();
+ ascii.Zero();
+ out.AppendNumFixedWidth(base + offset, EHex, 8); //addr
+ out.Append(_L(": "));
+
+ for(TUint byte = 0; byte < 16; ++byte)
+ {
+ TUint8 c = *(buf.Ptr() + offset + byte);
+ out.AppendNumFixedWidth(c, EHex, 2); //each memory byte
+ out.Append(' ');
+
+ if(c < 0x20 || c >= 0x7f) //something writable
+ c = 0x2e; //.
+ ascii.Append(TChar(c)); //byte representation
+ }
+ out.Append(ascii);
+ out.Append(_L("\r\n"));
+ iDataSave->WriteL(out);
+ }
+ }
+ else //binary dump
+ iDataSave->WriteL(buf);
+ }
+ CleanupStack::PopAndDestroy(&buf);
+}
+
+/**
+ Retrives the 'cancel crash' property value and checks if required to abort the crash dump. Updates 'crash progress' property.
+
+@param aProgress descriptor with the crash progress value.
+@leave KErrAbort if crash cancel property has been set
+ */
+void CDexcFormatter::UpdateCrashProgressL(const TDesC &aProgress) const
+ {
+ LOG_MSG("->CDexcFormatter::UpdateCrashProgress()\n");
+ TInt cancelCrash = EFalse;
+ TInt err = RProperty::Get(KCoreDumpServUid, ECancelCrash, cancelCrash);
+ if(err != KErrNone)
+ {
+ LOG_MSG2("CDexcFormatter::UpdateCrashProgress - unable to retrive 'cancel crash' value! err:%d\n", err);
+ }
+
+ if(cancelCrash)
+ {
+ LOG_MSG("CDexcFormatter::UpdateCrashProgress - aborting dump in progress\n");
+ User::Leave(KErrAbort);
+ }
+
+ err = RProperty::Set(KCoreDumpServUid, ECrashProgress, aProgress);
+ if(err != KErrNone)
+ {
+ LOG_MSG2("CDexcFormatter::UpdateCrashProgress - unable to retrive 'crash progress' value! err:%d\n", err);
+ }
+#ifdef DEBUG
+ User::After(1000000);
+#endif
+ }
+
+/**
+ Gets information about the threads of the crashed process and finds the one that caused the crash.
+@return reference to the CThreadInfo data structure holding information about the crashed thread
+@leave err one of the system wide error codes
+*/
+const CThreadInfo& CDexcFormatter::GetCrashedThreadInfoLC(const TCrashInfo &aCrashInfo) const
+ {
+ LOG_MSG("->CDexcFormatter::GetCrashedThreadInfoLC()\n");
+
+ RThreadPointerList *threadList = new(ELeave)RThreadPointerList;
+ TCleanupItem cleanup(CDexcFormatter::CleanupThreadList, (TAny*)threadList);
+ CleanupStack::PushL(cleanup);
+
+ CThreadInfo *threadInfo = NULL;
+ TUint totalThreadListDescSize;
+ iDataSource->GetThreadListL((TUint64)aCrashInfo.iPid, *threadList, totalThreadListDescSize); //for crashed process
+
+ for(TInt i = 0; i < threadList->Count(); i++)
+ {
+ if(aCrashInfo.iTid == (*threadList)[i]->Id())
+ {
+ threadInfo = (*threadList)[i]; //crashed thread
+ break;
+ }
+ }
+
+ if(NULL == threadInfo)
+ {
+ LOG_MSG("CDexcFormatter::CrashEventL - crashed thread not found!\n");
+ User::Leave( KErrNotFound );
+ }
+
+ return *threadInfo;
+ }
+
+/**
+ Prepares the name of the dump file. Checks DataSave filename option, if it is provided by the user
+ it appends crashed thread ID and extension, if not it uses default name appended with thread ID and extension.
+@param aTid ID of the crashed thread
+@param aExtension descriptor holding the file extension
+@return descriptor holding the final dump file name, caller is responsible to pop it from the cleanup stack
+@leave err one of the system wide error codes
+ */
+const TDesC& CDexcFormatter::DumpFileNameLC(TUint64 aTid, const TDesC &aExtension)
+{
+ COptionConfig *option = iDataSave->GetConfigParameterL(CCrashDataSave::ECoreFilePath);
+ const TDesC &userFileName = option->ValueAsDesc();
+ HBufC *filename = HBufC::NewLC(userFileName.Length() + KDexcFileNameLength);
+ if(userFileName.Length() > 0)
+ {
+ *filename = userFileName;
+ _LIT(KTidFormat, "%Lu");
+ filename->Des().AppendFormat(KTidFormat, aTid);
+ }
+ else
+ {
+ _LIT(KTxtFileFormat, "c:\\d_exc_%Lu");
+ filename->Des().Format(KTxtFileFormat, aTid);
+ }
+ filename->Des().Append(aExtension);
+ return *filename;
+}
+
+
+/**
+ Main formatter method. Handles crash event notification and drives dump process.
+
+@param aCrashInfo pointer to the TCrashInfo data structure holding information about the crash.
+@leave err one of the system wide error codes
+*/
+void CDexcFormatter::CrashEventL(TCrashInfo *aCrashInfo)
+{
+ LOG_MSG("-> CrashEventL()\n");
+
+ User::LeaveIfNull(aCrashInfo);
+ LOG_MSG("CDexcFormatter::CrashEvenL - crash info is sane\n");
+ User::LeaveIfNull(iDataSource);
+ LOG_MSG("CDexcFormatter::CrashEvenL - data source is sane\n");
+ User::LeaveIfNull(iDataSave);
+ LOG_MSG("CDexcFormatter::CrashEvenL - data save is sane\n");
+
+ _LIT(KProgressStart, "crash dump started");
+ UpdateCrashProgressL(KProgressStart);
+
+ const CThreadInfo &threadInfo = GetCrashedThreadInfoLC(*aCrashInfo);
+ _LIT(KProgressText, "dumping text file");
+ UpdateCrashProgressL(KProgressText);
+
+ LOG_MSG("CDexcFormatter::CrashEventL - opening text file\n");
+ _LIT(KTxtFileExt, ".txt");
+ iDataSave->OpenL(DumpFileNameLC(aCrashInfo->iTid, KTxtFileExt));
+ CleanupStack::PopAndDestroy(); //filename
+ DumpLogL(threadInfo);
+
+ if(aCrashInfo->iType == TCrashInfo::ECrashKill)
+ {
+ LOG_MSG("CDexcFormatter::CrashEventL - dumping panic info\n");
+ DumpPanicInfoL(*aCrashInfo);
+ }
+#ifdef __MARM__
+ else //ECrashException
+ {
+ LOG_MSG("CDexcFormatter::CrashEventL - dumping exeception info\n");
+ DumpExcInfoL(*aCrashInfo);
+ }
+ LOG_MSG("CDexcFormatter::CrashEventL - dumping registers info\n");
+ DumpRegistersL(aCrashInfo->iTid);
+#endif
+ LOG_MSG("CDexcFormatter::CrashEventL - dumping code segments info\n");
+ DumpCodeSegsL(aCrashInfo->iTid);
+
+ LOG_MSG("CDexcFormatter::CrashEventL - closing text file\n");
+ iDataSave->CloseL();
+
+ if(iDumpStack)
+ {
+ _LIT(KProgressStack, "dumping stack file");
+ UpdateCrashProgressL(KProgressStack);
+ LOG_MSG("CDexcFormatter::CrashEventL - opening stack file\n");
+ _LIT(KStkFileExt, ".stk");
+ iDataSave->OpenL(DumpFileNameLC(aCrashInfo->iTid, KStkFileExt));
+ CleanupStack::PopAndDestroy();//filename
+ LOG_MSG("CDexcFormatter::CrashEventL - dumping stack\n");
+ DumpStackL(aCrashInfo->iTid, threadInfo);
+ LOG_MSG("CDexcFormatter::CrashEventL - closing stack file\n");
+ iDataSave->CloseL();
+ }
+ _LIT(KProgressCompleted, "crash dump completed");
+ UpdateCrashProgressL(KProgressCompleted);
+ CleanupStack::PopAndDestroy(); //GetCrashedThreadInfoLC()::threadList , results in a call to CleanupThreadList
+ LOG_MSG("CDexcFormatter::CrashEventL - crash finished\n");
+}
+
+/**
+Cleanup item implementation for thread list in CrashEventL() method.
+@param aArray pointer to the list that is supposed to be freed
+*/
+void CDexcFormatter::CleanupThreadList(TAny *aArray)
+{
+ LOG_MSG("->CDexcFormatter::CleanupThreadList()\n");
+ RThreadPointerList *threadList = static_cast<RThreadPointerList*> (aArray);
+ threadList->ResetAndDestroy();
+ threadList->Close();
+ delete threadList;
+}
+