|
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 } |