|
1 // Copyright (c) 2008-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 // e32\debug\crashMonitor\src\scmdatasave.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #define __INCLUDE_REG_OFFSETS__ // for SP_R13U in nk_plat.h |
|
19 |
|
20 #include <omap_dbg.h> |
|
21 #include "arm_mem.h" |
|
22 #include "nk_plat.h" |
|
23 #include <omap_assp.h> |
|
24 #include <scmonitor.h> |
|
25 #include <scmdatasave.h> |
|
26 |
|
27 /** |
|
28 * @file |
|
29 * @internal technology |
|
30 */ |
|
31 |
|
32 /** |
|
33 * SCMDataSave constructor |
|
34 * @param aMonitor - the monitor which has caught the syetem crash this object is saving data for |
|
35 * @param aFlash - the flash memory data will be written to, note the CrashFlash interface is |
|
36 * rather limited and does not support partial block writes |
|
37 * @param aFlashInfo - data describing the structure of the flash data |
|
38 */ |
|
39 EXPORT_C SCMDataSave::SCMDataSave(Monitor* aMonitor, CrashFlash* aFlash) |
|
40 : iMonitor(aMonitor) |
|
41 ,iFlash(aFlash) |
|
42 ,iByteCount(0) |
|
43 #ifdef SCM_COMM_OUTPUT |
|
44 ,iWriteSelect(EWriteComm) // write data to debug port |
|
45 #else |
|
46 ,iWriteSelect(EWriteFlash) // write data to flash |
|
47 #endif |
|
48 ,iPerformChecksum(ETrue) // checksum data |
|
49 ,iStartingPointForCrash(0) |
|
50 { |
|
51 const TInt KCacheSize = 128; |
|
52 iFlashCache = HBuf8::New(KCacheSize); |
|
53 CLTRACE1("(SCMDataSave) Creating writer with cache size = %d", KCacheSize); |
|
54 iWriter = new TCachedByteStreamWriter(const_cast<TUint8*>(iFlashCache->Ptr()), KCacheSize); |
|
55 iWriter->SetWriterImpl(this); |
|
56 } |
|
57 |
|
58 /** |
|
59 * Destructor |
|
60 */ |
|
61 SCMDataSave::~SCMDataSave() |
|
62 { |
|
63 delete iFlashCache; |
|
64 } |
|
65 |
|
66 /** |
|
67 * Getter for the current byte count. This is the amount of data that has currently |
|
68 * been written to given media for this crash log |
|
69 * @return The number of bytes written already to given media |
|
70 */ |
|
71 TInt SCMDataSave::GetByteCount() |
|
72 { |
|
73 return iByteCount; |
|
74 } |
|
75 |
|
76 /** |
|
77 * Logs the user stack for a given DThread object if it is available |
|
78 * @param aThread - thread whose stack we wish to log |
|
79 * @param aSizeDumped Holds the size of the data dumped |
|
80 * @return one of the OS codes |
|
81 */ |
|
82 TInt SCMDataSave::LogThreadUserStack(DThread* aThread, TBool aFullStack, TUint& aSizeDumped) |
|
83 { |
|
84 LOG_CONTEXT |
|
85 aSizeDumped = 0; |
|
86 TUint memDumped = 0; |
|
87 |
|
88 TUint svSp, usrSp; |
|
89 iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp ); |
|
90 |
|
91 //first we check for a user stack... |
|
92 if (aThread->iUserStackRunAddress && aThread->iUserStackSize) |
|
93 { |
|
94 //Get data together |
|
95 TThreadStack usrStack; |
|
96 usrStack.iStackType = TThreadStack::EUsrStack; |
|
97 usrStack.iThreadId = (TUint64)aThread->iId; |
|
98 |
|
99 //map in the user stack |
|
100 TUint8* usrStart = (TUint8*)iMonitor->MapAndLocateUserStack(aThread); //What about Demand paging?? |
|
101 TUint8* usrEnd = (TUint8*)(usrStart + aThread->iUserStackSize); |
|
102 if(usrStart) |
|
103 { |
|
104 TUint8* stackPointer = (TUint8*)usrSp; |
|
105 |
|
106 //check the stack pointer is in the range of the stack... |
|
107 if (stackPointer < usrStart || stackPointer >= usrEnd) |
|
108 { |
|
109 stackPointer = usrStart; |
|
110 } |
|
111 |
|
112 //log the size of the stack we are dumping |
|
113 usrStack.iStackSize = aFullStack || (stackPointer == usrStart) ? usrEnd - usrStart : usrEnd - stackPointer; |
|
114 TUint8* dumpFrom = aFullStack ? usrStart : stackPointer; |
|
115 |
|
116 //write the stack |
|
117 aSizeDumped+= usrStack.GetSize(); |
|
118 usrStack.Serialize(*iWriter); |
|
119 |
|
120 //now we dump the actual stack |
|
121 //if there is a memErr when we read, there isnt much we can do - possibly a bit in the struct to say available/not available? |
|
122 //-1 because we dont want to write the byte at usrEnd |
|
123 MTRAPD(memErr, LogMemory(dumpFrom, usrStack.iStackSize, aThread, memDumped)); |
|
124 if(KErrNone != memErr) |
|
125 { |
|
126 CLTRACE("Failed to log usr stack"); |
|
127 } |
|
128 |
|
129 aSizeDumped+= memDumped; |
|
130 } |
|
131 else |
|
132 { |
|
133 //write the struct |
|
134 aSizeDumped+=usrStack.GetSize(); |
|
135 usrStack.Serialize(*iWriter); |
|
136 } |
|
137 } |
|
138 return KErrNone; |
|
139 } |
|
140 |
|
141 /** |
|
142 * Logs the supervisor stack for a given DThread object |
|
143 * @param aThread - thread whose stack we wish to log |
|
144 * @param aSizeDumped Holds the size of the data dumped |
|
145 * @return one of the system wide codes |
|
146 */ |
|
147 TInt SCMDataSave::LogThreadSupervisorStack(DThread* aThread, TBool aFullStack, TUint& aSizeDumped) |
|
148 { |
|
149 LOG_CONTEXT |
|
150 aSizeDumped = 0; |
|
151 TUint memDumped; |
|
152 |
|
153 TUint svSp, usrSp; |
|
154 iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp ); |
|
155 |
|
156 //now we dump the supervisor stack |
|
157 TThreadStack svrStack; |
|
158 svrStack.iStackType = TThreadStack::ESvrStack; |
|
159 svrStack.iThreadId = (TUint64)aThread->iId; |
|
160 |
|
161 if (aThread->iSupervisorStack && aThread->iSupervisorStackSize) |
|
162 { |
|
163 TUint8* svrStart = (TUint8*)aThread->iSupervisorStack; |
|
164 TUint8* svrEnd = (TUint8*)(svrStart + aThread->iSupervisorStackSize); |
|
165 TUint8* svrStackPointer = (TUint8*)svSp; |
|
166 |
|
167 //size of stack we are to dump |
|
168 svrStack.iStackSize = aFullStack || (svrStackPointer == svrStart) ? svrEnd - svrStart : svrEnd - svrStackPointer; |
|
169 |
|
170 if(svrStart) |
|
171 { |
|
172 //check the stack pointer is in the range of the stack... |
|
173 if (svrStackPointer < svrStart || svrStackPointer >= svrEnd) |
|
174 { |
|
175 svrStackPointer = svrStart; |
|
176 } |
|
177 |
|
178 //write struct to flash |
|
179 aSizeDumped+=svrStack.GetSize(); |
|
180 svrStack.Serialize(*iWriter); |
|
181 |
|
182 //now we dump the actual stack |
|
183 //if there is a memErr when we read, there isnt much we can do - possibly a bit in the struct to say available/not available? |
|
184 MTRAPD(memErr, LogMemory(svrStart, svrStack.iStackSize, aThread, memDumped)); |
|
185 aSizeDumped+=memDumped; |
|
186 |
|
187 if(KErrNone != memErr) |
|
188 { |
|
189 CLTRACE("Failed to log supervisor stack"); |
|
190 } |
|
191 } |
|
192 else |
|
193 { |
|
194 //write the struct |
|
195 aSizeDumped+=svrStack.GetSize(); |
|
196 svrStack.Serialize(*iWriter); |
|
197 } |
|
198 } |
|
199 |
|
200 return KErrNone; |
|
201 } |
|
202 |
|
203 /** |
|
204 * Takes a DProcess kernel object and logs its corrosponding code segments |
|
205 * @param aProcess |
|
206 * @param aSizeDumped Holds the size of the data dumped |
|
207 * @return one of the OS wide error codes |
|
208 */ |
|
209 TInt SCMDataSave::LogCodeSegments(DProcess* aProc, TUint& aSizeDumped) |
|
210 { |
|
211 LOG_CONTEXT |
|
212 aSizeDumped = 0; |
|
213 |
|
214 //the code segment set for this process |
|
215 TCodeSegmentSet segSet; |
|
216 segSet.iPid = (TUint64)aProc->iId; |
|
217 |
|
218 //make sure list mutex is ok |
|
219 if(Kern::CodeSegLock()->iHoldCount) |
|
220 { |
|
221 return KErrCorrupt; |
|
222 } |
|
223 |
|
224 //get code seg list |
|
225 SDblQue queue; |
|
226 aProc->TraverseCodeSegs(&queue, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd); |
|
227 |
|
228 //iterate through the list |
|
229 TInt codeSegCnt = 0; |
|
230 for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext) |
|
231 { |
|
232 //get the code seg |
|
233 DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink); |
|
234 |
|
235 if(codeSeg) |
|
236 { |
|
237 codeSegCnt++; |
|
238 } |
|
239 } |
|
240 |
|
241 if(codeSegCnt == 0) |
|
242 { |
|
243 return KErrNone; |
|
244 } |
|
245 |
|
246 segSet.iNumSegs = codeSegCnt; |
|
247 segSet.Serialize(*iWriter); |
|
248 aSizeDumped+=segSet.GetSize(); |
|
249 |
|
250 TModuleMemoryInfo memoryInfo; |
|
251 |
|
252 //now we write each code segment |
|
253 for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext) |
|
254 { |
|
255 //get the code seg |
|
256 DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink); |
|
257 |
|
258 if(codeSeg) |
|
259 { |
|
260 TCodeSegment seg; |
|
261 seg.iXip = (codeSeg->iXIP) ? ETrue : EFalse; |
|
262 |
|
263 //Get the code seg type |
|
264 if(codeSeg->IsExe()) |
|
265 { |
|
266 seg.iCodeSegType = EExeCodeSegType; |
|
267 } |
|
268 else if(codeSeg->IsDll()) |
|
269 { |
|
270 seg.iCodeSegType = EDllCodeSegType; |
|
271 } |
|
272 |
|
273 TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); |
|
274 if(KErrNone == err) |
|
275 { |
|
276 seg.iCodeSegMemInfo = memoryInfo; |
|
277 } |
|
278 else |
|
279 { |
|
280 seg.iCodeSegMemInfo.iCodeSize = 0; |
|
281 |
|
282 // Still need to indicate it wasnt available somehow |
|
283 } |
|
284 |
|
285 //Get filename |
|
286 seg.iNameLength = codeSeg->iFileName->Length(); |
|
287 seg.iName = *(codeSeg->iFileName); |
|
288 |
|
289 aSizeDumped+=seg.GetSize(); |
|
290 seg.Serialize(*iWriter); |
|
291 } |
|
292 } |
|
293 |
|
294 //Empty this queue and clear marks |
|
295 DCodeSeg::EmptyQueue(queue, DCodeSeg::EMarkDebug); |
|
296 |
|
297 return KErrNone; |
|
298 } |
|
299 |
|
300 /** |
|
301 * This logs the rom version and header information to the crash media |
|
302 * @param aSizeDumped amount of data occupied |
|
303 * @return one of the OS wide codes |
|
304 */ |
|
305 TInt SCMDataSave::LogRomInfo(TUint& aSizeDumped) |
|
306 { |
|
307 aSizeDumped = 0; |
|
308 |
|
309 TRomHeaderData romData; |
|
310 |
|
311 TRomHeader rHdr = Epoc::RomHeader(); |
|
312 |
|
313 romData.iMajorVersion = rHdr.iVersion.iMajor; |
|
314 romData.iMinorVersion = rHdr.iVersion.iMinor; |
|
315 romData.iBuildNumber = rHdr.iVersion.iBuild; |
|
316 romData.iTime = rHdr.iTime; |
|
317 |
|
318 TInt err = romData.Serialize(*iWriter); |
|
319 if(KErrNone != err) |
|
320 { |
|
321 return err; |
|
322 } |
|
323 |
|
324 aSizeDumped += romData.GetSize(); |
|
325 |
|
326 return KErrNone; |
|
327 } |
|
328 |
|
329 /** |
|
330 * Takes a DProcess kernel object and logs to flash |
|
331 * @param aProc |
|
332 * @param aSizeDumped Holds the size of the data dumped |
|
333 * @return one of the OS wide error codes |
|
334 */ |
|
335 TInt SCMDataSave::LogProcessData(DProcess* aProc, TUint& aSizeDumped) |
|
336 { |
|
337 LOG_CONTEXT |
|
338 aSizeDumped = 0; |
|
339 |
|
340 TProcessData procData; |
|
341 DCodeSeg* codeSeg = aProc->iCodeSeg; |
|
342 |
|
343 procData.iPriority = aProc->iPriority; |
|
344 procData.iPid = (TUint64)aProc->iId; |
|
345 |
|
346 //the code segment is not always available |
|
347 if(codeSeg) |
|
348 { |
|
349 procData.iNamesize = codeSeg->iFileName->Length(); |
|
350 procData.iName = *(codeSeg->iFileName); |
|
351 } |
|
352 |
|
353 aSizeDumped += procData.GetSize(); |
|
354 procData.Serialize(*iWriter); |
|
355 |
|
356 return KErrNone; |
|
357 } |
|
358 |
|
359 /** |
|
360 * Creates meta data about the crash such as time of crash, exit reason etc. to be logged |
|
361 * later on when we have log size. |
|
362 * @param aCategory - crash category |
|
363 * @param aReason - crash reason |
|
364 * @param aSizeDumped Holds the size of the data dumped |
|
365 * @return one of the OS wide codes |
|
366 */ |
|
367 TInt SCMDataSave::LogCrashHeader(const TDesC8& aCategory, TInt aReason, TInt aCrashId, TUint& aSizeDumped) |
|
368 { |
|
369 LOG_CONTEXT |
|
370 aSizeDumped = 0; |
|
371 |
|
372 //the thread that crashed is the context in which we are running |
|
373 DThread* crashedThread = &Kern::CurrentThread(); |
|
374 |
|
375 iCrashInf.iPid = crashedThread->iOwningProcess->iId; |
|
376 iCrashInf.iTid = crashedThread->iId; |
|
377 iCrashInf.iCrashTime = CrashTime(); |
|
378 iCrashInf.iExitType = 0; // Not yet done: Exception or Fault - should be in category |
|
379 iCrashInf.iExitReason = aReason; |
|
380 iCrashInf.iFlashAlign = KFlashAlignment; //record the flash alignment (word aligned for now) |
|
381 iCrashInf.iCachedWriterSize = iWriter->GetCacheSize(); |
|
382 |
|
383 iCrashInf.iCategorySize = aCategory.Length(); |
|
384 iCrashInf.iCategory = aCategory; |
|
385 iCrashInf.iCrashId = aCrashId; |
|
386 |
|
387 iCrashInf.iFlashBlockSize = KCrashLogBlockSize;; |
|
388 iCrashInf.iFlashPartitionSize = KCrashLogSize;; |
|
389 |
|
390 TSuperPage& sp=Kern::SuperPage(); |
|
391 iCrashInf.iExcCode = sp.iKernelExcId; |
|
392 |
|
393 //These will be updated with more info at end of crash |
|
394 aSizeDumped+=iCrashInf.GetSize(); |
|
395 iCrashInf.Serialize(*iWriter); |
|
396 |
|
397 aSizeDumped+=iHdr.GetSize(); |
|
398 iHdr.Serialize(*iWriter); |
|
399 |
|
400 CLTRACE1("(SCMDataSave::LogCrashHeader) finished bytes written= %d", iWriter->GetBytesWritten()); |
|
401 return KErrNone; |
|
402 } |
|
403 |
|
404 /** |
|
405 * Logs meta data about a given DThread object |
|
406 * @param aThread Thread to dump |
|
407 * @param aSizeDumped Holds the size of the data dumped |
|
408 * @return |
|
409 */ |
|
410 TInt SCMDataSave::LogThreadData(DThread* aThread, TUint& aSizeDumped) |
|
411 { |
|
412 LOG_CONTEXT |
|
413 aSizeDumped = 0; |
|
414 |
|
415 //struct to hold data that gets written to flash |
|
416 TThreadData threadData; |
|
417 |
|
418 threadData.iTid = (TUint64)aThread->iId; |
|
419 threadData.iOwnerId = (TUint64)aThread->iOwningProcess->iId; |
|
420 threadData.iPriority = aThread->iThreadPriority; |
|
421 |
|
422 //Get the stack pointers |
|
423 TUint svSp, usrSp; |
|
424 iMonitor->GetStackPointers(&(aThread->iNThread), svSp, usrSp ); |
|
425 threadData.iUsrSP = usrSp; |
|
426 threadData.iSvcSP = svSp; |
|
427 |
|
428 //supervisor and user stack details |
|
429 threadData.iSvcStack = (TInt32)aThread->iSupervisorStack; |
|
430 threadData.iSvcStacksize = aThread->iSupervisorStackSize; |
|
431 threadData.iUsrStack = aThread->iUserStackRunAddress; |
|
432 threadData.iUsrStacksize = aThread->iUserStackSize; |
|
433 |
|
434 //currently we can only get the kernels heap |
|
435 if(aThread == &Kern::CurrentThread()) |
|
436 { |
|
437 TInt32 heapLoc = 0; |
|
438 TInt32 heapSz = 0; |
|
439 TInt err = FindKernelHeap(heapLoc,heapSz); |
|
440 if(KErrNone == err) |
|
441 { |
|
442 threadData.iSvcHeap = heapLoc; |
|
443 threadData.iSvcHeapSize = heapSz; |
|
444 } |
|
445 else |
|
446 { |
|
447 CLTRACE("\tError: Unable to get kernel heap"); |
|
448 } |
|
449 } |
|
450 |
|
451 //get filename |
|
452 TFileName filename; |
|
453 aThread->TraceAppendFullName(filename, EFalse); |
|
454 |
|
455 threadData.iName.Copy(filename); |
|
456 threadData.iNamesize = threadData.iName.Length(); |
|
457 |
|
458 |
|
459 #ifdef __INCLUDE_NTHREADBASE_DEFINES__ |
|
460 threadData.iLastCpu = aThread->iNThread.iLastCpu; |
|
461 #else |
|
462 threadData.iLastCpu = aThread->iNThread.iSpare3; |
|
463 #endif |
|
464 |
|
465 threadData.Serialize(*iWriter); |
|
466 aSizeDumped+=threadData.GetSize(); |
|
467 |
|
468 return KErrNone; |
|
469 } |
|
470 |
|
471 /** |
|
472 * Logs the arm exception stacks |
|
473 * @param aSizeDumped Holds the size of the data dumped |
|
474 * @return one of the OS wide codes |
|
475 */ |
|
476 TInt SCMDataSave::LogExceptionStacks(TUint& aSizeDumped) |
|
477 { |
|
478 LOG_CONTEXT |
|
479 aSizeDumped = 0; |
|
480 TUint memDumped = 0; |
|
481 |
|
482 #if defined(__EPOC32__) && !defined(__CPU_X86) |
|
483 |
|
484 TStackInfo& stackInfo = Kern::SuperPage().iStackInfo; |
|
485 |
|
486 TThreadStack irqStack; |
|
487 irqStack.iStackType = TThreadStack::EIRQStack; |
|
488 irqStack.iStackSize = stackInfo.iIrqStackSize; |
|
489 |
|
490 aSizeDumped+=irqStack.GetSize(); |
|
491 irqStack.Serialize(*iWriter); |
|
492 |
|
493 //now dump the IRQ memory - not much we can do in the event of an error |
|
494 MTRAPD(irqErr, LogMemory((TUint8*)stackInfo.iIrqStackBase, stackInfo.iIrqStackSize, &Kern::CurrentThread(), memDumped)); |
|
495 |
|
496 if(KErrNone != irqErr) |
|
497 { |
|
498 CLTRACE("*****Failed to log IRQ stack"); |
|
499 } |
|
500 aSizeDumped+=memDumped; |
|
501 |
|
502 //Next, we do the FIQ stack |
|
503 TThreadStack fiqStack; |
|
504 fiqStack.iStackType = TThreadStack::EFIQStack; |
|
505 fiqStack.iStackSize = stackInfo.iFiqStackSize; |
|
506 |
|
507 aSizeDumped+=fiqStack.GetSize(); |
|
508 fiqStack.Serialize(*iWriter); |
|
509 |
|
510 //Now dump the stack itself |
|
511 MTRAPD(fiqErr, LogMemory((TUint8*)stackInfo.iFiqStackBase, stackInfo.iFiqStackSize, &Kern::CurrentThread(), memDumped)); |
|
512 |
|
513 if(KErrNone != fiqErr ) |
|
514 { |
|
515 CLTRACE("*****Failed to log FIQ stack"); |
|
516 } |
|
517 aSizeDumped+=memDumped; |
|
518 |
|
519 #endif |
|
520 |
|
521 return KErrNone; |
|
522 } |
|
523 |
|
524 /** |
|
525 * Logs the CPU Registers at the time of crash |
|
526 * @param aSizeDumped Holds the size of the data dumped |
|
527 * @return system wide OS code |
|
528 */ |
|
529 TInt SCMDataSave::LogCPURegisters(TUint& aSizeDumped) |
|
530 { |
|
531 LOG_CONTEXT |
|
532 aSizeDumped = 0; |
|
533 |
|
534 TInt32 fullSet = 37; |
|
535 |
|
536 //meta data about the thread set |
|
537 TRegisterSet threadSet; |
|
538 threadSet.iNumRegisters = fullSet; |
|
539 |
|
540 aSizeDumped+=threadSet.GetSize(); |
|
541 threadSet.Serialize(*iWriter); |
|
542 |
|
543 SFullArmRegSet regSet; |
|
544 ReadCPURegisters(regSet); |
|
545 TArmReg* regs = (TArmReg*)®Set; |
|
546 |
|
547 TInt32 cnt = 0; |
|
548 for(cnt = 0; cnt < fullSet; cnt++) |
|
549 { |
|
550 //this is the struct to store the register value in |
|
551 TRegisterValue regVal; |
|
552 regVal.iType = cnt * 0x100; |
|
553 regVal.iValue32 = regs[cnt]; |
|
554 regVal.iOwnId = Kern::CurrentThread().iId; |
|
555 |
|
556 aSizeDumped+=regVal.GetSize(); |
|
557 regVal.Serialize(*iWriter); |
|
558 } |
|
559 |
|
560 return KErrNone; |
|
561 } |
|
562 |
|
563 /** |
|
564 * This logs the registers for a given thread to the flash memory |
|
565 * @param aThread - thread whose registers we want |
|
566 * @param aRegType - type of register set required such as user, supervisor etc |
|
567 * @param aSizeDumped Holds the size of the data dumped |
|
568 * @return one of the OS return codes |
|
569 */ |
|
570 TInt SCMDataSave::LogRegisters(DThread* aThread, const TRegisterSetType& aRegType, TUint& aSizeDumped) |
|
571 { |
|
572 LOG_CONTEXT |
|
573 aSizeDumped = 0; |
|
574 |
|
575 TArmRegSet regs; |
|
576 TUint32 availableRegs; |
|
577 TInt err; |
|
578 |
|
579 //for the current thread we do things differently |
|
580 if(aThread == &Kern::CurrentThread() && aRegType == EFullCPURegisters) |
|
581 { |
|
582 err = LogCPURegisters(aSizeDumped); |
|
583 return err; |
|
584 } |
|
585 else if(aThread == &Kern::CurrentThread()) |
|
586 { |
|
587 //only do full cpu reg for the current thread |
|
588 return KErrNotSupported; |
|
589 } |
|
590 |
|
591 //Read the appropriate registers |
|
592 switch(aRegType) |
|
593 { |
|
594 case EUserRegisters : |
|
595 { |
|
596 err = ReadUserRegisters(aThread, regs, availableRegs); |
|
597 break; |
|
598 } |
|
599 case ESupervisorRegisters : |
|
600 { |
|
601 err = ReadSystemRegisters(aThread, regs, availableRegs); |
|
602 break; |
|
603 } |
|
604 default : return KErrNotSupported; |
|
605 } |
|
606 |
|
607 if(err != KErrNone) |
|
608 { |
|
609 return err; |
|
610 } |
|
611 |
|
612 //meta data about the thread set |
|
613 TRegisterSet threadSet; |
|
614 |
|
615 //to get the number of registers in advance, we need to count the number of times 1 is set in the bit field of availableRegs |
|
616 TUint numR = 0; |
|
617 for(TInt cnt =0; cnt< 8*sizeof(availableRegs); cnt++) //cycle through 1 bit at a time |
|
618 { |
|
619 if(0x1 & (availableRegs>>cnt)) |
|
620 numR++; |
|
621 } |
|
622 |
|
623 threadSet.iNumRegisters = numR; |
|
624 |
|
625 if(numR == 0) |
|
626 return KErrNone; |
|
627 |
|
628 threadSet.Serialize(*iWriter); |
|
629 aSizeDumped += threadSet.GetSize(); |
|
630 |
|
631 TInt32 currentRegister = 1; |
|
632 TArmReg* reg = (TArmReg*)(®s); |
|
633 |
|
634 for(TInt32 cnt = 0; cnt < KArmRegisterCount; cnt++) |
|
635 { |
|
636 //look at the unavailable bitmask to see current register is available |
|
637 //only write the registers we have values for |
|
638 if(currentRegister & availableRegs) |
|
639 { |
|
640 //this is the struct to store the register value in |
|
641 TRegisterValue regVal; |
|
642 |
|
643 //get register type as per symbian elf docs |
|
644 TUint32 registerType; |
|
645 err = GetRegisterType(aRegType, cnt, registerType); |
|
646 if(err != KErrNone) |
|
647 { |
|
648 continue; |
|
649 } |
|
650 regVal.iType = registerType; |
|
651 regVal.iOwnId = aThread->iId; |
|
652 |
|
653 //set value |
|
654 regVal.iValue32 = reg[cnt]; |
|
655 |
|
656 aSizeDumped+=regVal.GetSize(); |
|
657 regVal.Serialize(*iWriter); |
|
658 } |
|
659 |
|
660 currentRegister<<=1; |
|
661 } |
|
662 |
|
663 return KErrNone; |
|
664 } |
|
665 |
|
666 /** |
|
667 * This logs memory in the specified area |
|
668 * @param aStartAddress - address to start from |
|
669 * @param aEndAddress - address to finish |
|
670 * @param aThread - process whose memory this is in |
|
671 * @param aSizeDumped Holds the size of the data dumped |
|
672 * @return one of the system wide codes |
|
673 */ |
|
674 TInt SCMDataSave::LogMemory(const TUint8* aStartAddress, TInt aLength, const DThread* aThread, TUint& aSizeDumped) |
|
675 { |
|
676 LOG_CONTEXT |
|
677 aSizeDumped = 0; |
|
678 |
|
679 if(aThread->iOwningProcess != &Kern::CurrentProcess()) |
|
680 { |
|
681 TInt err = iMonitor->SwitchAddressSpace(aThread->iOwningProcess, ETrue); |
|
682 if(KErrNone != err) |
|
683 { |
|
684 return err; |
|
685 } |
|
686 } |
|
687 |
|
688 TMemoryDump memDump; |
|
689 memDump.iStartAddress = (TUint32)aStartAddress; |
|
690 memDump.iLength = aLength; |
|
691 memDump.iPid = aThread->iOwningProcess->iId; |
|
692 |
|
693 aSizeDumped+=memDump.GetSize(); |
|
694 memDump.Serialize(*iWriter); |
|
695 |
|
696 if(!aStartAddress) |
|
697 { |
|
698 return KErrArgument; |
|
699 } |
|
700 |
|
701 TRawData theMemory; |
|
702 theMemory.iData.Set(const_cast<TUint8*>(aStartAddress), aLength, aLength); |
|
703 |
|
704 theMemory.Serialize(*iWriter); |
|
705 aSizeDumped+=theMemory.GetSize(); |
|
706 |
|
707 return KErrNone; |
|
708 } |
|
709 |
|
710 /** |
|
711 * This logs the locks held by system at time of crash |
|
712 * @param aSizeDumped Holds the size of the data dumped |
|
713 * @return one of the system wide codes |
|
714 */ |
|
715 TInt SCMDataSave::LogLocks(TUint& aSizeDumped) |
|
716 { |
|
717 LOG_CONTEXT |
|
718 aSizeDumped = 0; |
|
719 |
|
720 // get the mutex logs & waits & log via a TLockData object |
|
721 TSCMLockData lockData; |
|
722 |
|
723 const TInt KMaxLockCheck = 20; // so no possibility of infinite loop |
|
724 |
|
725 TInt lockCount = 0; |
|
726 // check for kernel locks - |
|
727 for(TInt i=0;i<KMaxLockCheck;i++) |
|
728 { |
|
729 TBool locked = NKern::KernelLocked(i); |
|
730 if(!locked) |
|
731 { |
|
732 lockData.SetLockCount(lockCount); |
|
733 break; |
|
734 } |
|
735 // found a valid lock for value i increment the clock counter |
|
736 lockCount++; |
|
737 } |
|
738 |
|
739 // now mutexes |
|
740 DMutex* mutex = Kern::CodeSegLock(); |
|
741 if(mutex) |
|
742 { |
|
743 lockData.SetMutexHoldCount(mutex->iHoldCount); |
|
744 lockData.SetMutexThreadWaitCount(mutex->iWaitCount); |
|
745 } |
|
746 else |
|
747 { |
|
748 // no mutex held set to -1 |
|
749 lockData.SetMutexHoldCount(0); |
|
750 lockData.SetMutexThreadWaitCount(0); |
|
751 } |
|
752 |
|
753 aSizeDumped+=lockData.GetSize(); |
|
754 TInt err = lockData.Serialize(*iWriter); |
|
755 |
|
756 return err; |
|
757 } |
|
758 |
|
759 /** |
|
760 * Writes the SCM Configuration to the start of the media |
|
761 * @param aScmConfig Configuration to write |
|
762 * @return one of the system wide codes |
|
763 */ |
|
764 TInt SCMDataSave::LogConfig(SCMConfiguration& aScmConfig) |
|
765 { |
|
766 iWriter->SetPosition(0); |
|
767 |
|
768 TInt err = aScmConfig.Serialize(*iWriter); |
|
769 |
|
770 if( err != KErrNone) |
|
771 { |
|
772 CLTRACE1("SCMDataSave::LogConfig failed err = %d", err); |
|
773 } |
|
774 |
|
775 return err; |
|
776 } |
|
777 |
|
778 /** |
|
779 * Reads the SCM Configuration from the media |
|
780 * @param aScmConfig |
|
781 * @return one of the system wide codes |
|
782 */ |
|
783 TInt SCMDataSave::ReadConfig(SCMConfiguration& aScmConfig) |
|
784 { |
|
785 const TInt KBufSize = 135; //Not yet done: Put in header, beside config defn |
|
786 |
|
787 if( KBufSize < aScmConfig.GetSize()) |
|
788 { |
|
789 CLTRACE2("(SCMDataSave::ReadConfig) ** ERROR Inadequate buffer actual = %d req = %d" |
|
790 , KBufSize, aScmConfig.GetSize()); |
|
791 } |
|
792 |
|
793 // try and read the configuration |
|
794 TBuf8<KBufSize> buf; |
|
795 buf.SetLength(KBufSize); |
|
796 |
|
797 iFlash->SetReadPos(0); // config always at 0 |
|
798 iFlash->Read(buf); |
|
799 |
|
800 TByteStreamReader reader(const_cast<TUint8*>(buf.Ptr())); |
|
801 TInt err = aScmConfig.Deserialize(reader); |
|
802 if(err == KErrNotReady) |
|
803 { |
|
804 CLTRACE("(SCMDataSave::ReadConfig) no config saved - use default"); |
|
805 } |
|
806 else if(err == KErrNone) |
|
807 { |
|
808 CLTRACE("(SCMDataSave::ReadConfig) Config read ok"); |
|
809 } |
|
810 else |
|
811 { |
|
812 CLTRACE1("(SCMDataSave::ReadConfig) error reading config err = %d", err); |
|
813 } |
|
814 |
|
815 return err; |
|
816 } |
|
817 |
|
818 /** |
|
819 * This is a look up table to map the register type and number to the symbian elf definition |
|
820 * of register type |
|
821 * @param aSetType this is the register set type - user, supervisor etc |
|
822 * @param aRegNumber this is the number of the register as per TArmRegisters in arm_types.h |
|
823 * @param aSizeDumped Holds the size of the data dumped |
|
824 * @return One of the OS wide codes |
|
825 */ |
|
826 TInt SCMDataSave::GetRegisterType(const TRegisterSetType& aSetType, TInt32& aRegNumber, TUint32& aRegisterType) |
|
827 { |
|
828 //validate arguments |
|
829 if(aRegNumber < EArmR0 || aRegNumber > EArmFlags) |
|
830 { |
|
831 return KErrArgument; |
|
832 } |
|
833 |
|
834 //look at what type we are using |
|
835 switch(aSetType) |
|
836 { |
|
837 case EUserRegisters : |
|
838 { |
|
839 aRegisterType = aRegNumber * 0x100; //for R0 to R16 (CPSR) it just increments in 0x100 from 0x0 to 0x1000 |
|
840 break; |
|
841 } |
|
842 case ESupervisorRegisters : |
|
843 { |
|
844 //same as EUserRegisters except R13 and R14 are different |
|
845 if(aRegNumber == EArmSp) |
|
846 { |
|
847 aRegisterType = 0x1100; |
|
848 break; |
|
849 } |
|
850 else if(aRegNumber == EArmLr) |
|
851 { |
|
852 aRegisterType = 0x1200; |
|
853 break; |
|
854 } |
|
855 else |
|
856 { |
|
857 aRegisterType = aRegNumber * 0x100; |
|
858 break; |
|
859 } |
|
860 } |
|
861 default : return KErrNotSupported; |
|
862 } |
|
863 |
|
864 return KErrNone; |
|
865 } |
|
866 |
|
867 /** |
|
868 * Writes the trace buffer to the crash log. |
|
869 * @param aSizeToDump Number of bytes to dump. If this is zero we attempt to write the entire buffer |
|
870 * @param aSizeDumped Holds the size of the data dumped |
|
871 * @return One of the OS wide codes |
|
872 */ |
|
873 TInt SCMDataSave::LogTraceBuffer(TInt aSizeToDump, TUint& aSizeDumped) |
|
874 { |
|
875 LOG_CONTEXT |
|
876 aSizeDumped = 0; |
|
877 TUint memDumped = 0; |
|
878 |
|
879 TBool dumpAll = (aSizeToDump == 0) ? ETrue : EFalse; |
|
880 |
|
881 //Because the btrace buffer is a circular one, we need to save it in two parts |
|
882 //this corrosponds to how we read it |
|
883 TUint8* data; |
|
884 TUint sizeOfPartRead; |
|
885 TInt spaceRemaining = aSizeToDump; |
|
886 |
|
887 //This structure will be filled after the first pass and cached so by the time we ARE writing it will |
|
888 //contain the data we want |
|
889 aSizeDumped+=iTrace.GetSize(); |
|
890 iTrace.Serialize(*iWriter); |
|
891 |
|
892 //read first part |
|
893 TInt err = BTrace::Control(BTrace::ECtrlCrashReadFirst,&data,&sizeOfPartRead); |
|
894 |
|
895 while(KErrNone == err && sizeOfPartRead > 0) |
|
896 { |
|
897 TUint rawSize = 0; //how much of this read data want we to dump |
|
898 |
|
899 if(dumpAll) |
|
900 { |
|
901 rawSize = sizeOfPartRead; |
|
902 } |
|
903 else //Otherwise see what room is left for dumpage |
|
904 { |
|
905 rawSize = ((sizeOfPartRead + iTrace.iSizeOfMemory) > aSizeToDump) ? spaceRemaining : sizeOfPartRead; |
|
906 } |
|
907 |
|
908 //Only relevant if restricting the dump |
|
909 if(spaceRemaining <= 0 && !dumpAll) |
|
910 break; |
|
911 |
|
912 TPtrC8 ptr(data, rawSize); |
|
913 err = LogRawData(ptr, memDumped); |
|
914 if(KErrNone != err) |
|
915 { |
|
916 CLTRACE1("Logging Raw data failed - [%d]", err); |
|
917 err = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&sizeOfPartRead); |
|
918 continue; |
|
919 } |
|
920 |
|
921 aSizeDumped+=memDumped; |
|
922 |
|
923 iTrace.iSizeOfMemory += rawSize; |
|
924 iTrace.iNumberOfParts++; |
|
925 spaceRemaining -= rawSize; |
|
926 |
|
927 err = BTrace::Control(BTrace::ECtrlCrashReadNext,&data,&sizeOfPartRead); |
|
928 } |
|
929 |
|
930 return KErrNone; |
|
931 } |
|
932 |
|
933 /** |
|
934 * Logs the data in a TRawData struct |
|
935 * @param aData |
|
936 * @param aSizeDumped Holds the size of the data dumped |
|
937 * @return One of the OS wide codes |
|
938 */ |
|
939 TInt SCMDataSave::LogRawData(const TDesC8& aData, TUint& aSizeDumped) |
|
940 { |
|
941 TRawData theData; |
|
942 theData.iLength = aData.Length(); |
|
943 theData.iData.Set(const_cast<TUint8*>(aData.Ptr()), aData.Length(), aData.Length()); |
|
944 |
|
945 aSizeDumped+=theData.GetSize(); |
|
946 return theData.Serialize(*iWriter); |
|
947 } |
|
948 |
|
949 |
|
950 /** |
|
951 * Logs the kernels heap and returns the size dumped via aSizeDumped |
|
952 * @param aSizeDumped Holds the size of the data dumped |
|
953 * @return |
|
954 */ |
|
955 TInt SCMDataSave::LogKernelHeap(TUint& aSizeDumped) |
|
956 { |
|
957 LOG_CONTEXT |
|
958 |
|
959 TInt32 heapLoc = 0; |
|
960 TInt32 heapSize = 0; |
|
961 TInt32 err = FindKernelHeap(heapLoc, heapSize); |
|
962 if(KErrNone == err) |
|
963 { |
|
964 return LogMemory((TUint8*)heapLoc, heapSize, &Kern::CurrentThread(), aSizeDumped); |
|
965 } |
|
966 |
|
967 CLTRACE1("\tCouldnt find the kernel heap: [%d]", err); |
|
968 return err; |
|
969 } |
|
970 |
|
971 /** |
|
972 * Iterates the object containers and finds the kernel heap |
|
973 * @param aHeapLocation Contains the memory location of the kernel heap |
|
974 * @param aHeapSize Contains the size of the Heap |
|
975 * @return One of the OS wide codes |
|
976 */ |
|
977 TInt SCMDataSave::FindKernelHeap(TInt32& aHeapLocation, TInt32& aHeapSize) |
|
978 { |
|
979 LOG_CONTEXT |
|
980 |
|
981 //Get Chunk object container |
|
982 DObjectCon* objectContainer = Kern::Containers()[EChunk]; |
|
983 if(objectContainer == NULL) |
|
984 { |
|
985 CLTRACE("\tFailed to get object container for the chunks"); |
|
986 return KErrNotFound; |
|
987 } |
|
988 |
|
989 //Must check the mutex on this is ok otherwise the data will be in an inconsistent state |
|
990 if(objectContainer->Lock()->iHoldCount) |
|
991 { |
|
992 CLTRACE("\tChunk Container is in an inconsistant state"); |
|
993 return KErrCorrupt; |
|
994 } |
|
995 |
|
996 TInt numObjects = objectContainer->Count(); |
|
997 |
|
998 for(TInt cnt = 0; cnt< numObjects; cnt ++) |
|
999 { |
|
1000 DChunk* candidateHeapChunk = (DChunk*)(*objectContainer)[cnt]; |
|
1001 |
|
1002 //Get the objects name |
|
1003 TBuf8<KMaxKernelName> name; |
|
1004 candidateHeapChunk->TraceAppendFullName(name,EFalse); |
|
1005 |
|
1006 if(name == KKernelHeapChunkName) |
|
1007 { |
|
1008 #ifndef __MEMMODEL_FLEXIBLE__ |
|
1009 aHeapLocation = (TInt32)candidateHeapChunk->iBase; |
|
1010 #else |
|
1011 aHeapLocation = (TInt32)candidateHeapChunk->iFixedBase; |
|
1012 #endif |
|
1013 |
|
1014 aHeapSize = candidateHeapChunk->iSize; |
|
1015 |
|
1016 return KErrNone; |
|
1017 } |
|
1018 } |
|
1019 |
|
1020 return KErrNotFound; |
|
1021 } |
|
1022 |
|
1023 /** |
|
1024 * This logs the variant specific descriptor data to the crash log |
|
1025 * @param aSizeDumped records how much was dumped by this function |
|
1026 * @return one of the OS wide codes |
|
1027 */ |
|
1028 TInt SCMDataSave::LogVariantSpecificData(TUint& aSizeDumped) |
|
1029 { |
|
1030 LOG_CONTEXT |
|
1031 |
|
1032 aSizeDumped = 0; |
|
1033 |
|
1034 //Change this descriptor as required for your needs |
|
1035 _LIT(KVariantSpecificData, "This is the variant specific data. Put your own here"); |
|
1036 |
|
1037 TVariantSpecificData varData; |
|
1038 varData.iSize = KVariantSpecificData().Size(); |
|
1039 |
|
1040 TInt err = varData.Serialize(*iWriter); |
|
1041 if(KErrNone != err) |
|
1042 { |
|
1043 CLTRACE1("\tLogging variant specific data failed with code [%d]", err); |
|
1044 return err; |
|
1045 } |
|
1046 aSizeDumped+=varData.GetSize(); |
|
1047 |
|
1048 TUint rawDataSize = 0; |
|
1049 err = LogRawData(KVariantSpecificData(), rawDataSize); |
|
1050 if(KErrNone != err) |
|
1051 { |
|
1052 CLTRACE1("\tLogging variant specific data failed with code [%d]", err); |
|
1053 return err; |
|
1054 } |
|
1055 |
|
1056 aSizeDumped+=rawDataSize; |
|
1057 |
|
1058 return KErrNone; |
|
1059 } |
|
1060 |
|
1061 |
|
1062 /** |
|
1063 * This method is the callback used by MPhysicalWriterImpl interface |
|
1064 * if the TCachedByteStreamWriter is configured to use this interface |
|
1065 * the callback avoids the need for temp buffers & can interface directly with the |
|
1066 * flash writer methods |
|
1067 * @param aData - data to write |
|
1068 * @param aLen - length of data to write |
|
1069 * @param aPos - writers internal position |
|
1070 */ |
|
1071 void SCMDataSave::DoPhysicalWrite(TAny* aData, TInt aPos, TInt aLen) |
|
1072 { |
|
1073 if(iPerformChecksum) |
|
1074 { |
|
1075 iChecksum.ChecksumBlock((TUint8*)aData, aLen); |
|
1076 } |
|
1077 |
|
1078 if( this->iWriteSelect == EWriteComm) |
|
1079 { |
|
1080 WriteUart((TUint8*)aData, aLen); |
|
1081 } |
|
1082 else // EWriteFlash |
|
1083 { |
|
1084 Write(aData, aLen); |
|
1085 } |
|
1086 } |
|
1087 |
|
1088 /** |
|
1089 * Writes data to Flash |
|
1090 * @param aSomething Pointer to the data |
|
1091 * @param aSize Size of the data |
|
1092 */ |
|
1093 void SCMDataSave::Write(const TAny* aSomething, TInt aSize) |
|
1094 { |
|
1095 TPtrC8 data((const TUint8 *)aSomething, aSize); |
|
1096 |
|
1097 TInt written = 0; |
|
1098 |
|
1099 WriteCrashFlash(iByteCount, written, data); |
|
1100 iByteCount+= written; |
|
1101 } |
|
1102 |
|
1103 /** |
|
1104 * Writes a descriptor to the crash flash |
|
1105 * @param aPos Position in flash to write |
|
1106 * @param aSize Holds the size of the data written after the call |
|
1107 * @param aBuffer Descriptor to write |
|
1108 */ |
|
1109 void SCMDataSave::WriteCrashFlash(TInt aPos, TInt& aSize, const TDesC8& aBuffer) |
|
1110 { |
|
1111 //Set write position in the flash |
|
1112 iFlash->SetWritePos(aPos); |
|
1113 iFlash->Write(aBuffer); |
|
1114 |
|
1115 //get bytes written |
|
1116 aSize += iFlash->BytesWritten(); |
|
1117 |
|
1118 if(aSize != aBuffer.Length()) |
|
1119 { |
|
1120 CLTRACE2("(SCMDataSave::WriteCrashFlash) Over the limit aSize = %d aBuffer.Length() = %d", |
|
1121 aSize, aBuffer.Length()); |
|
1122 } |
|
1123 } |
|
1124 |
|
1125 /** |
|
1126 * Writes a descriptor via serial |
|
1127 * @param aDes Descriptor to write |
|
1128 */ |
|
1129 void SCMDataSave::WriteUart(const TDesC8& aDes) |
|
1130 { |
|
1131 WriteUart(aDes.Ptr(), aDes.Length()); |
|
1132 } |
|
1133 |
|
1134 /** |
|
1135 * Writes data via serial |
|
1136 * @param aData Data to write |
|
1137 * @param aSize Size of data to write |
|
1138 */ |
|
1139 void SCMDataSave::WriteUart(const TUint8* aData, TInt aSize) |
|
1140 { |
|
1141 OMAP* assp = ((OMAP*)Arch::TheAsic()); |
|
1142 TOmapDbgPrt* dbg = assp->DebugPort(); |
|
1143 |
|
1144 if (dbg) |
|
1145 { |
|
1146 for(TInt i=0;i<aSize;i++) |
|
1147 { |
|
1148 dbg->DebugOutput(*(aData+i)); |
|
1149 } |
|
1150 } |
|
1151 else |
|
1152 { |
|
1153 CLTRACE("SCMDataSave::WriteUart ERROR - dbg was null"); |
|
1154 } |
|
1155 } |
|
1156 |
|
1157 /** |
|
1158 * Setter for the current number of bytes written for this crash log |
|
1159 * If aByte is not word aligned, it will be rounded up to be so |
|
1160 * @param aByte Current bytes written |
|
1161 */ |
|
1162 void SCMDataSave::SetByteCount(TInt aByte) |
|
1163 { |
|
1164 //ensure aligned |
|
1165 if(aByte % iWriter->GetCacheSize() == 0) |
|
1166 { |
|
1167 iByteCount = aByte; |
|
1168 } |
|
1169 else |
|
1170 { |
|
1171 iByteCount = aByte + (iWriter->GetCacheSize() - (aByte % iWriter->GetCacheSize())); |
|
1172 } |
|
1173 } |
|
1174 |
|
1175 /** |
|
1176 * Gets the output target selection |
|
1177 * @return TScmWriteSelect output target selection |
|
1178 * @param void |
|
1179 */ |
|
1180 SCMDataSave::TWriteSelect SCMDataSave::GetWriteSelect() |
|
1181 { |
|
1182 return iWriteSelect; |
|
1183 } |
|
1184 |
|
1185 /** |
|
1186 * Sets the output target selection |
|
1187 * @return void |
|
1188 * @param TScmWriteSelect aWriteSelect output target selection |
|
1189 */ |
|
1190 void SCMDataSave::SetWriteSelect(SCMDataSave::TWriteSelect aWriteSelect) |
|
1191 { |
|
1192 iWriteSelect = aWriteSelect; |
|
1193 } |
|
1194 |
|
1195 /** |
|
1196 * Gets the amount of space remaining for the media of choice |
|
1197 * @return |
|
1198 */ |
|
1199 TUint SCMDataSave::SpaceRemaining() |
|
1200 { |
|
1201 TInt currentPosition = iWriter->GetBytesWritten() + iStartingPointForCrash; |
|
1202 |
|
1203 return MaxLogSize() - currentPosition; |
|
1204 } |
|
1205 |
|
1206 /** |
|
1207 * To find the max size of a log for a given media |
|
1208 * @return the max size of a log for a given media |
|
1209 */ |
|
1210 TUint SCMDataSave::MaxLogSize() |
|
1211 { |
|
1212 //see what write media is being used |
|
1213 switch(GetWriteSelect()) |
|
1214 { |
|
1215 case EWriteFlash: |
|
1216 { |
|
1217 return KMaxCrashLogSize; |
|
1218 } |
|
1219 case EWriteComm: |
|
1220 { |
|
1221 return 0xFFFFFFFF; |
|
1222 } |
|
1223 default: |
|
1224 { |
|
1225 return 0; |
|
1226 } |
|
1227 } |
|
1228 } |
|
1229 |
|
1230 /** |
|
1231 * Records the offset in the flash partition where this crash begins |
|
1232 * @param aStart Offset in flash |
|
1233 */ |
|
1234 void SCMDataSave::SetCrashStartingPoint(TUint32 aStart) |
|
1235 { |
|
1236 iStartingPointForCrash = aStart; |
|
1237 } |
|
1238 |
|
1239 //eof |
|
1240 |