os/kernelhwsrv/kerneltest/e32utils/crashread/crashread.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2003-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 the License "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 <e32std_private.h>
    18 #include <f32file.h>
    19 #include <d32locd.h>
    20 #include <e32cons.h>
    21 #include "crashflash.h"
    22 #include <partitions.h>
    23 #include <ftlcontrolio.h>
    24 
    25 #ifdef _DEBUG
    26 #define TRACE(a) RDebug::Print(a); PrintLine(a)
    27 #define TRACE1(a,b) RDebug::Print(a,b); PrintLine(a,b)
    28 #define TRACE2(a,b,c) RDebug::Print(a,b,c); PrintLine(a,b,c)
    29 #define TRACE5(a,b,c,d,e,f) RDebug::Print(a,b,c,d,e,f); PrintLine(a,b,c,d,e,f)
    30 #else
    31 #define TRACE(a) 
    32 #define TRACE1(a,b) 
    33 #define TRACE2(a,b,c) 
    34 #define TRACE5(a,b,c,d,e,f)
    35 #endif
    36 
    37 #ifndef _CRASHLOG_COMPR
    38 _LIT(KCrashLogFileName, "?:\\crashlog.txt");
    39 #else
    40 _LIT(KCrashLogCompFileName, "?:\\crashlog.gz");
    41 _LIT(KCrashLogCompTruncatedFileName, "?:\\crashlog_truncated.gz");
    42 #endif //_CRASHLOG_COMPR
    43 
    44 _LIT8(KCrashLogSignatureStomp, "\x00\x00\x00\x00");
    45 
    46 CConsoleBase* console = 0;
    47 
    48 RLocalDrive gLd;
    49 TLocalDriveCapsV4 gCaps;
    50 TPckg<TLocalDriveCapsV4> gCapsBuf(gCaps);
    51 
    52 #ifdef _DEBUG
    53 LOCAL_C void CheckConsoleCreated()
    54 	{
    55 	if(!console)
    56 		{
    57 		TRAPD(r, console = Console::NewL(_L("crashread"), 
    58 			TSize(KConsFullScreen,KConsFullScreen)));
    59 		__ASSERT_ALWAYS(r == KErrNone, User::Panic(_L("Could not create console"), 1));
    60 		}
    61 	}
    62 
    63 LOCAL_C void PrintLine(TRefByValue<const TDesC> aFmt,...)
    64 	{
    65     // Print to a console screen.
    66     VA_LIST list;
    67     VA_START(list, aFmt);
    68     TBuf<0x100> aBuf;
    69     aBuf.AppendFormatList(aFmt, list);
    70     CheckConsoleCreated();
    71     console->Write(aBuf);
    72 	console->Write(_L("\n\r"));
    73 	}
    74 #endif
    75 
    76 /** Read the signature from the flash and verify it is correct.
    77 	@return ETrue when signature found, EFalse otherwise
    78 */
    79 LOCAL_C TBool SignatureExistsL()
    80 	{
    81 	TBuf8<KCrashLogSignatureBytes> buf(0);
    82 	User::LeaveIfError(gLd.Read(KCrashLogSizeFieldBytes,KCrashLogSignatureBytes,buf));
    83 
    84 	if(buf.Compare(KCrashLogSignature) == 0)
    85 		{
    86 		return ETrue;
    87 		}
    88 
    89 	return EFalse;
    90 	}
    91 
    92 LOCAL_C TInt LogSizeL()
    93 	{
    94 	TBuf8<KCrashLogSizeFieldBytes> buf(0);
    95 	User::LeaveIfError(gLd.Read(0,KCrashLogSizeFieldBytes,buf));
    96 	TInt size = *((TUint*)(buf.Ptr()));
    97 	size -= (KCrashLogHeaderSize);
    98 	return size;
    99 	}
   100 
   101 #ifdef _CRASHLOG_COMPR	
   102 /** Read the log flags from the flash.  Flags located after the log size and uncompressed size
   103 	@return The log flags byte
   104 */
   105 LOCAL_C TUint32 LogFlagsL()
   106 	{
   107 	TBuf8<KCrashLogFlagsFieldBytes> buf(0);
   108 	User::LeaveIfError(gLd.Read(KCrashLogSizeFieldBytes+KCrashLogUncompSizeFieldBytes+KCrashLogSignatureBytes,
   109 						KCrashLogFlagsFieldBytes,buf));
   110 	return *((TUint32*)buf.Ptr());
   111 	}
   112 #endif //_CRASHLOG_COMPR
   113 	
   114 LOCAL_C TInt InvalidateSignature()
   115 	{
   116 	//On Nand we erase the block.
   117 	if(gCaps.iType == EMediaNANDFlash)
   118 		{
   119 		return gLd.Format(0,gCaps.iNumBytesMain * gCaps.iNumPagesPerBlock);
   120 		}
   121 	//On Nor we just stomp on the first 4 bytes of the signature
   122 	return gLd.Write(KCrashLogSizeFieldBytes,KCrashLogSignatureStomp);
   123 	}
   124 
   125 /**
   126 @return KErrNone if no read errors, otherwise the last read error. 
   127 @leave if other errors occur.	
   128 @param aFileName Where the log wll be copied to
   129 @param aStartPosition Where to begin reads within the flash section.
   130 @param aLogSize The total amount to read.
   131 */
   132 TInt CopyToFileL(const TDesC& aFileName, const TInt aStartPosition, const TInt aLogSize)
   133 	{
   134 	// Connect to f32 and write out the file
   135 	RFs fs;
   136 	RFile file;
   137 	User::LeaveIfError(fs.Connect());
   138 	CleanupClosePushL(fs);
   139 	User::LeaveIfError(file.Replace(fs, aFileName, EFileWrite));
   140 	CleanupClosePushL(file);
   141 
   142 	//create buffer
   143 	const TInt KBufferSize=32*1024;
   144 	HBufC8* buf = HBufC8::NewLC(KBufferSize);
   145 	TPtr8 ptr = buf->Des();
   146 
   147 	TInt readError = KErrNone;
   148 	for(TInt offset=0; offset<aLogSize; offset+=KBufferSize)
   149 		{
   150 		//don't read beyond end on final iteration.
   151 		const TInt readLength = Min(KBufferSize, aLogSize-offset);
   152 
   153 		ptr.SetLength(0);
   154 		TInt r = gLd.Read(aStartPosition+offset,readLength,ptr);
   155 
   156 		// in case of error store it, but attempt to continue.
   157 		if (r!=KErrNone)
   158 			{
   159 			readError=r;
   160 			}
   161 
   162 		User::LeaveIfError(file.Write(offset, ptr));
   163 		}
   164 
   165 	User::LeaveIfError(file.Flush());
   166 	CleanupStack::PopAndDestroy(buf);
   167 	CleanupStack::PopAndDestroy(&file);
   168 	CleanupStack::PopAndDestroy(&fs);
   169 	return readError;
   170 	}
   171 
   172 
   173 LOCAL_C TInt MainL()
   174 	{
   175 	// check if command line argument is 'reset'
   176 	RBuf cl;
   177 	cl.CreateL(User::CommandLineLength());
   178 	cl.CleanupClosePushL();
   179 	User::CommandLine(cl);
   180 	TBool reset = (cl==_L("reset"));
   181 	CleanupStack::PopAndDestroy();
   182 	
   183 	TBool changed;
   184 	TInt r = 0;
   185 	TInt i=0;
   186 	// 1) Find a crash log partition.
   187 	for(; i<KMaxLocalDrives; i++)
   188 		{
   189 		r = gLd.Connect(i,changed);
   190 		if(r == KErrNone)
   191 			{
   192 			r = gLd.Caps(gCapsBuf);
   193 			if(r != KErrNone)
   194 				{
   195 				//TRACE1(_L("Could not retrieve gCaps for drive: %d.  Skipping to next..."),i);
   196 				continue;
   197 				}
   198 			if(gCaps.iPartitionType == (TUint16)KPartitionTypeSymbianCrashLog)
   199 				{
   200 				TRACE1(_L("Found Symbian crash log partition on drive: %d"),i);
   201 				CleanupClosePushL(gLd);
   202 				// 1) See if there is an existing crash log
   203 				TBool exists = SignatureExistsL();
   204 				if(!exists)
   205 					{
   206 					TRACE(_L("Did not find an existing crash log signature on this crash log partition..."));
   207 					//There may be a second crash log partition. (nor or nand
   208 					//depending on ordering in variantmediadef.h).  So we continue searching
   209 					CleanupStack::PopAndDestroy(&gLd);
   210 					continue; 
   211 					}
   212 				TRACE1(_L("Found a crash log signature on drive: %d."),i);
   213 				//We've found a crash log partition with a signature on it.
   214 				break;
   215 				}
   216 			else
   217 				{
   218 				//TRACE2(_L("Partition type on drive: %d is %d"),i,gCaps.iPartitionType);
   219 				}
   220 			}
   221 		}
   222 	if(i == KMaxLocalDrives)
   223 		{
   224 		TRACE(_L("No crash log partition found with valid crash log signature found.  Exiting..."));
   225 		User::Leave(KErrNotFound);
   226 		}
   227 
   228 	// If we're doing a reset, don't try to read the crash log, just skip to stomping the signature
   229 	if(!reset)
   230 		{
   231 		TUint8 systemDriveChar = (TUint8) RFs::GetSystemDriveChar();
   232 #ifndef _CRASHLOG_COMPR
   233 		// Determine size of crash log and copy to file.
   234 		TInt logSize = LogSizeL();
   235 		TRACE1(_L("Reading crash log of %d bytes..."), logSize);
   236 		TBuf<sizeof(KCrashLogFileName)> crashLogFileName(KCrashLogFileName);
   237 		crashLogFileName[0] = systemDriveChar;
   238 		r = CopyToFileL(crashLogFileName, KCrashLogSizeFieldBytes+KCrashLogSignatureBytes, logSize);
   239 
   240 		if (r==KErrNone)
   241 			{
   242 			TRACE1(_L("Crash log successfully written to: %S."), &crashLogFileName);
   243 			}
   244 		else
   245 			{
   246 			TRACE1(_L("Crash log written to %S but errors were encountered when reading, it may be incomplete or corrupt."), &crashLogFileName);
   247 			}
   248 
   249 #else
   250 		// 2) 	Read crash log header to get the compressed and uncompressed size of the log
   251 		//		also need to read the flags to determine if the log had to be truncated and
   252 		//		if the expected log format is found
   253 		const TUint32 logFlags = LogFlagsL();
   254 		
   255 		// Extract byte offset from the end of the header to the start of the log data
   256 		const TInt logOff = logFlags>>KCrashLogFlagOffShift;
   257 		
   258 		// Work out if the log had to be truncated
   259 		const TInt truncated = logFlags&KCrashLogFlagTruncated;			
   260 		
   261 		// Check the crashlog type flag is that expected - here we can only cope with GZIP compatible logs
   262 		if ((logFlags & (0xffffffff>>(32-KCrashLogFlagTypeBits))) != KCrashLogFlagGzip)
   263 			{// wrong log type so can't extract it
   264 			TRACE(_L("Crash Log data is stored in an incompatible data format so can't be read"));
   265 			}
   266 		else
   267 			{
   268 			// 2) Read the log data
   269 			const TInt logSize = LogSizeL()-logOff; // don't include any offset bytes	
   270 			TRACE1(_L("Reading compressed crash log of %d bytes..."), logSize);
   271 
   272 			
   273 			TRACE1(_L("Writing compressed crash log to file..."), logSize);
   274 			RBuf crashLogCompFileName;
   275 			if (!truncated)
   276 				{
   277 				crashLogCompFileName.CreateL(KCrashLogCompFileName);
   278 				}
   279 			else
   280 				{
   281 				crashLogCompFileName.CreateL(KCrashLogCompTruncatedFileName);
   282 				}
   283 			crashLogCompFileName.CleanupClosePushL();
   284 
   285 			crashLogCompFileName[0] = systemDriveChar;
   286 			r = CopyToFileL(crashLogCompFileName, KCrashLogHeaderSize+logOff, logSize);
   287 				
   288 			if (r==KErrNone)
   289 				{
   290 				if (!truncated)
   291 					{
   292 					TRACE1(_L("Crash log successfully written to: %S."), &crashLogCompFileName);
   293 					}
   294 				else
   295 					{
   296 					TRACE(_L("Crash log was truncated, some log data has been lost"));
   297 					TRACE1(_L("Crash log successfully written to: %S."), &crashLogCompFileName);
   298 					}						
   299 				}
   300 			else
   301 				{
   302 				if(!truncated)
   303 					{
   304 					TRACE1(_L("Crash log written to %S but errors were encountered when reading, it may be incomplete or corrupt."), &crashLogCompFileName);
   305 					}
   306 				else
   307 					{
   308 					TRACE1(_L("Crash log written to %S but errors were encountered when reading, it may be incomplete or corrupt."), &crashLogCompFileName);
   309 					}
   310 				}
   311 			CleanupStack::PopAndDestroy(&crashLogCompFileName);
   312 			}
   313 #endif //_CRASHLOG_COMPR			
   314 		}
   315 
   316 	// 5) Stomp on the signature to mark it eligible to be overwritten
   317 	TRACE(_L("Overwriting existing signature to indicate crash log has been read..."));
   318 	User::LeaveIfError(InvalidateSignature());
   319 
   320 	CleanupStack::PopAndDestroy(&gLd);
   321 
   322 	if (r==KErrNone)
   323 		{
   324 		TRACE(_L("Crash reader finished successfully."));
   325 		}
   326 	else
   327 		{
   328 		TRACE(_L("Crash reader finished but with errors."));
   329 		}
   330 	return KErrNone;
   331 	}
   332 
   333 GLDEF_C TInt E32Main()
   334 	{
   335 	__UHEAP_MARK;
   336 	CTrapCleanup* cleanup=CTrapCleanup::New();
   337 	TRAPD(ret, MainL());
   338 	if(console)
   339 		{
   340 		console->Getch();
   341 		delete console;
   342 		}
   343 	if (ret){} // stops compile warning
   344 	delete cleanup;
   345 	__UHEAP_MARKEND;
   346 	return KErrNone;
   347 	}