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