kerneltest/e32utils/crashread/crashread.cpp
changeset 43 96e5fb8b040d
child 33 0173bcd7697c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32utils/crashread/crashread.cpp	Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,346 @@
+// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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 <e32std.h>
+#include <e32std_private.h>
+#include <f32file.h>
+#include <e32cons.h>
+#include "crashflash.h"
+#include <partitions.h>
+#include <ftlcontrolio.h>
+
+#ifdef _DEBUG
+#define TRACE(a) RDebug::Print(a); PrintLine(a)
+#define TRACE1(a,b) RDebug::Print(a,b); PrintLine(a,b)
+#define TRACE2(a,b,c) RDebug::Print(a,b,c); PrintLine(a,b,c)
+#define TRACE5(a,b,c,d,e,f) RDebug::Print(a,b,c,d,e,f); PrintLine(a,b,c,d,e,f)
+#else
+#define TRACE(a) 
+#define TRACE1(a,b) 
+#define TRACE2(a,b,c) 
+#define TRACE5(a,b,c,d,e,f)
+#endif
+
+#ifndef _CRASHLOG_COMPR
+_LIT(KCrashLogFileName, "?:\\crashlog.txt");
+#else
+_LIT(KCrashLogCompFileName, "?:\\crashlog.gz");
+_LIT(KCrashLogCompTruncatedFileName, "?:\\crashlog_truncated.gz");
+#endif //_CRASHLOG_COMPR
+
+_LIT8(KCrashLogSignatureStomp, "\x00\x00\x00\x00");
+
+CConsoleBase* console = 0;
+
+RLocalDrive gLd;
+TLocalDriveCapsV4 gCaps;
+TPckg<TLocalDriveCapsV4> gCapsBuf(gCaps);
+
+#ifdef _DEBUG
+LOCAL_C void CheckConsoleCreated()
+	{
+	if(!console)
+		{
+		TRAPD(r, console = Console::NewL(_L("crashread"), 
+			TSize(KConsFullScreen,KConsFullScreen)));
+		__ASSERT_ALWAYS(r == KErrNone, User::Panic(_L("Could not create console"), 1));
+		}
+	}
+
+LOCAL_C void PrintLine(TRefByValue<const TDesC> aFmt,...)
+	{
+    // Print to a console screen.
+    VA_LIST list;
+    VA_START(list, aFmt);
+    TBuf<0x100> aBuf;
+    aBuf.AppendFormatList(aFmt, list);
+    CheckConsoleCreated();
+    console->Write(aBuf);
+	console->Write(_L("\n\r"));
+	}
+#endif
+
+/** Read the signature from the flash and verify it is correct.
+	@return ETrue when signature found, EFalse otherwise
+*/
+LOCAL_C TBool SignatureExistsL()
+	{
+	TBuf8<KCrashLogSignatureBytes> buf(0);
+	User::LeaveIfError(gLd.Read(KCrashLogSizeFieldBytes,KCrashLogSignatureBytes,buf));
+
+	if(buf.Compare(KCrashLogSignature) == 0)
+		{
+		return ETrue;
+		}
+
+	return EFalse;
+	}
+
+LOCAL_C TInt LogSizeL()
+	{
+	TBuf8<KCrashLogSizeFieldBytes> buf(0);
+	User::LeaveIfError(gLd.Read(0,KCrashLogSizeFieldBytes,buf));
+	TInt size = *((TUint*)(buf.Ptr()));
+	size -= (KCrashLogHeaderSize);
+	return size;
+	}
+
+#ifdef _CRASHLOG_COMPR	
+/** Read the log flags from the flash.  Flags located after the log size and uncompressed size
+	@return The log flags byte
+*/
+LOCAL_C TUint32 LogFlagsL()
+	{
+	TBuf8<KCrashLogFlagsFieldBytes> buf(0);
+	User::LeaveIfError(gLd.Read(KCrashLogSizeFieldBytes+KCrashLogUncompSizeFieldBytes+KCrashLogSignatureBytes,
+						KCrashLogFlagsFieldBytes,buf));
+	return *((TUint32*)buf.Ptr());
+	}
+#endif //_CRASHLOG_COMPR
+	
+LOCAL_C TInt InvalidateSignature()
+	{
+	//On Nand we erase the block.
+	if(gCaps.iType == EMediaNANDFlash)
+		{
+		return gLd.Format(0,gCaps.iNumBytesMain * gCaps.iNumPagesPerBlock);
+		}
+	//On Nor we just stomp on the first 4 bytes of the signature
+	return gLd.Write(KCrashLogSizeFieldBytes,KCrashLogSignatureStomp);
+	}
+
+/**
+@return KErrNone if no read errors, otherwise the last read error. 
+@leave if other errors occur.	
+@param aFileName Where the log wll be copied to
+@param aStartPosition Where to begin reads within the flash section.
+@param aLogSize The total amount to read.
+*/
+TInt CopyToFileL(const TDesC& aFileName, const TInt aStartPosition, const TInt aLogSize)
+	{
+	// Connect to f32 and write out the file
+	RFs fs;
+	RFile file;
+	User::LeaveIfError(fs.Connect());
+	CleanupClosePushL(fs);
+	User::LeaveIfError(file.Replace(fs, aFileName, EFileWrite));
+	CleanupClosePushL(file);
+
+	//create buffer
+	const TInt KBufferSize=32*1024;
+	HBufC8* buf = HBufC8::NewLC(KBufferSize);
+	TPtr8 ptr = buf->Des();
+
+	TInt readError = KErrNone;
+	for(TInt offset=0; offset<aLogSize; offset+=KBufferSize)
+		{
+		//don't read beyond end on final iteration.
+		const TInt readLength = Min(KBufferSize, aLogSize-offset);
+
+		ptr.SetLength(0);
+		TInt r = gLd.Read(aStartPosition+offset,readLength,ptr);
+
+		// in case of error store it, but attempt to continue.
+		if (r!=KErrNone)
+			{
+			readError=r;
+			}
+
+		User::LeaveIfError(file.Write(offset, ptr));
+		}
+
+	User::LeaveIfError(file.Flush());
+	CleanupStack::PopAndDestroy(buf);
+	CleanupStack::PopAndDestroy(&file);
+	CleanupStack::PopAndDestroy(&fs);
+	return readError;
+	}
+
+
+LOCAL_C TInt MainL()
+	{
+	// check if command line argument is 'reset'
+	RBuf cl;
+	cl.CreateL(User::CommandLineLength());
+	cl.CleanupClosePushL();
+	User::CommandLine(cl);
+	TBool reset = (cl==_L("reset"));
+	CleanupStack::PopAndDestroy();
+	
+	TBool changed;
+	TInt r = 0;
+	TInt i=0;
+	// 1) Find a crash log partition.
+	for(; i<KMaxLocalDrives; i++)
+		{
+		r = gLd.Connect(i,changed);
+		if(r == KErrNone)
+			{
+			r = gLd.Caps(gCapsBuf);
+			if(r != KErrNone)
+				{
+				//TRACE1(_L("Could not retrieve gCaps for drive: %d.  Skipping to next..."),i);
+				continue;
+				}
+			if(gCaps.iPartitionType == (TUint16)KPartitionTypeSymbianCrashLog)
+				{
+				TRACE1(_L("Found Symbian crash log partition on drive: %d"),i);
+				CleanupClosePushL(gLd);
+				// 1) See if there is an existing crash log
+				TBool exists = SignatureExistsL();
+				if(!exists)
+					{
+					TRACE(_L("Did not find an existing crash log signature on this crash log partition..."));
+					//There may be a second crash log partition. (nor or nand
+					//depending on ordering in variantmediadef.h).  So we continue searching
+					CleanupStack::PopAndDestroy(&gLd);
+					continue; 
+					}
+				TRACE1(_L("Found a crash log signature on drive: %d."),i);
+				//We've found a crash log partition with a signature on it.
+				break;
+				}
+			else
+				{
+				//TRACE2(_L("Partition type on drive: %d is %d"),i,gCaps.iPartitionType);
+				}
+			}
+		}
+	if(i == KMaxLocalDrives)
+		{
+		TRACE(_L("No crash log partition found with valid crash log signature found.  Exiting..."));
+		User::Leave(KErrNotFound);
+		}
+
+	// If we're doing a reset, don't try to read the crash log, just skip to stomping the signature
+	if(!reset)
+		{
+		TUint8 systemDriveChar = (TUint8) RFs::GetSystemDriveChar();
+#ifndef _CRASHLOG_COMPR
+		// Determine size of crash log and copy to file.
+		TInt logSize = LogSizeL();
+		TRACE1(_L("Reading crash log of %d bytes..."), logSize);
+		TBuf<sizeof(KCrashLogFileName)> crashLogFileName(KCrashLogFileName);
+		crashLogFileName[0] = systemDriveChar;
+		r = CopyToFileL(crashLogFileName, KCrashLogSizeFieldBytes+KCrashLogSignatureBytes, logSize);
+
+		if (r==KErrNone)
+			{
+			TRACE1(_L("Crash log successfully written to: %S."), &crashLogFileName);
+			}
+		else
+			{
+			TRACE1(_L("Crash log written to %S but errors were encountered when reading, it may be incomplete or corrupt."), &crashLogFileName);
+			}
+
+#else
+		// 2) 	Read crash log header to get the compressed and uncompressed size of the log
+		//		also need to read the flags to determine if the log had to be truncated and
+		//		if the expected log format is found
+		const TUint32 logFlags = LogFlagsL();
+		
+		// Extract byte offset from the end of the header to the start of the log data
+		const TInt logOff = logFlags>>KCrashLogFlagOffShift;
+		
+		// Work out if the log had to be truncated
+		const TInt truncated = logFlags&KCrashLogFlagTruncated;			
+		
+		// Check the crashlog type flag is that expected - here we can only cope with GZIP compatible logs
+		if ((logFlags & (0xffffffff>>(32-KCrashLogFlagTypeBits))) != KCrashLogFlagGzip)
+			{// wrong log type so can't extract it
+			TRACE(_L("Crash Log data is stored in an incompatible data format so can't be read"));
+			}
+		else
+			{
+			// 2) Read the log data
+			const TInt logSize = LogSizeL()-logOff; // don't include any offset bytes	
+			TRACE1(_L("Reading compressed crash log of %d bytes..."), logSize);
+
+			
+			TRACE1(_L("Writing compressed crash log to file..."), logSize);
+			RBuf crashLogCompFileName;
+			if (!truncated)
+				{
+				crashLogCompFileName.CreateL(KCrashLogCompFileName);
+				}
+			else
+				{
+				crashLogCompFileName.CreateL(KCrashLogCompTruncatedFileName);
+				}
+			crashLogCompFileName.CleanupClosePushL();
+
+			crashLogCompFileName[0] = systemDriveChar;
+			r = CopyToFileL(crashLogCompFileName, KCrashLogHeaderSize+logOff, logSize);
+				
+			if (r==KErrNone)
+				{
+				if (!truncated)
+					{
+					TRACE1(_L("Crash log successfully written to: %S."), &crashLogCompFileName);
+					}
+				else
+					{
+					TRACE(_L("Crash log was truncated, some log data has been lost"));
+					TRACE1(_L("Crash log successfully written to: %S."), &crashLogCompFileName);
+					}						
+				}
+			else
+				{
+				if(!truncated)
+					{
+					TRACE1(_L("Crash log written to %S but errors were encountered when reading, it may be incomplete or corrupt."), &crashLogCompFileName);
+					}
+				else
+					{
+					TRACE1(_L("Crash log written to %S but errors were encountered when reading, it may be incomplete or corrupt."), &crashLogCompFileName);
+					}
+				}
+			CleanupStack::PopAndDestroy(&crashLogCompFileName);
+			}
+#endif //_CRASHLOG_COMPR			
+		}
+
+	// 5) Stomp on the signature to mark it eligible to be overwritten
+	TRACE(_L("Overwriting existing signature to indicate crash log has been read..."));
+	User::LeaveIfError(InvalidateSignature());
+
+	CleanupStack::PopAndDestroy(&gLd);
+
+	if (r==KErrNone)
+		{
+		TRACE(_L("Crash reader finished successfully."));
+		}
+	else
+		{
+		TRACE(_L("Crash reader finished but with errors."));
+		}
+	return KErrNone;
+	}
+
+GLDEF_C TInt E32Main()
+	{
+	__UHEAP_MARK;
+	CTrapCleanup* cleanup=CTrapCleanup::New();
+	TRAPD(ret, MainL());
+	if(console)
+		{
+		console->Getch();
+		delete console;
+		}
+	if (ret){} // stops compile warning
+	delete cleanup;
+	__UHEAP_MARKEND;
+	return KErrNone;
+	}