|
1 // Copyright (c) 2005-2010 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 "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 // Trace Data parser |
|
15 // |
|
16 |
|
17 #include <e32svr.h> |
|
18 #include <e32def.h> |
|
19 #include <e32def_private.h> |
|
20 #include <e32btrace.h> |
|
21 |
|
22 #include "tracedataparser.h" |
|
23 #include "testdatawriternotifier.h" |
|
24 #include "tracecoreconstants.h" |
|
25 #include "d32tracebuffer.h" |
|
26 |
|
27 |
|
28 EXPORT_C TUint32 TTraceDataParser::Swap(TUint32 x) |
|
29 { |
|
30 return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24); |
|
31 } |
|
32 |
|
33 EXPORT_C TUint32 TTraceDataParser::ReadUint32FromBuf(TUint8*& aBuf, TBool aFromTestWriter) |
|
34 { |
|
35 #ifdef __WINS__ |
|
36 aFromTestWriter = EFalse; |
|
37 #endif |
|
38 // reads a 4 byte integer of expected endianess |
|
39 TUint32 n; |
|
40 if (!aFromTestWriter) |
|
41 { |
|
42 n = *(aBuf+3) + (*(aBuf+2) << 8) + (*(aBuf+1) << 16) + (*aBuf << 24); |
|
43 } |
|
44 else |
|
45 { |
|
46 // endianess order is reversed for TestWriter on hw |
|
47 n = (*aBuf) + (*(aBuf+1) << 8) + (*(aBuf+2) << 16) + (*(aBuf+3) << 24); |
|
48 } |
|
49 aBuf += sizeof(TUint32); |
|
50 return n; |
|
51 } |
|
52 |
|
53 EXPORT_C TUint16 TTraceDataParser::ReadUint16FromBuf(TUint8*& aBuf) |
|
54 { |
|
55 // reads a 2 byte integer of expected endianess |
|
56 TUint16 n = (*aBuf << 8)+ (*(aBuf+1)); |
|
57 aBuf += sizeof(TUint16); |
|
58 return n; |
|
59 } |
|
60 |
|
61 TPtr8 TTraceDataParser::ReadTracePrintf(TUint8* aData, TInt aSize) |
|
62 { |
|
63 TPtr8 printfString(aData, aSize, aSize); |
|
64 TInt endPosition = printfString.Locate(TChar(0)); |
|
65 if (endPosition >= 0) |
|
66 { |
|
67 printfString = printfString.Left(endPosition); |
|
68 } |
|
69 else |
|
70 { |
|
71 printfString.Trim(); |
|
72 } |
|
73 return printfString; |
|
74 } |
|
75 |
|
76 TBool TTraceDataParser::StringsMatch(const TDesC8& aString1, const TDesC8& aString2) |
|
77 { |
|
78 TInt compareLength = (aString1.Length() > aString2.Length()) ? aString2.Length() : aString1.Length(); |
|
79 if ( (aString2.Left(compareLength).Compare(aString1) == 0) || |
|
80 (aString1.Left(compareLength).Compare(aString2) == 0) ) |
|
81 { |
|
82 return ETrue; |
|
83 } |
|
84 return EFalse; |
|
85 } |
|
86 |
|
87 /** |
|
88 * Function to string for a number |
|
89 * @param aBuffer Trace data descriptor |
|
90 * @param aFindStringPattern Pattern that indicates where in the string the number will be, using an asterisk |
|
91 * @param aNumberFound If found, the number in the string |
|
92 * @return Symbian error code |
|
93 */ |
|
94 TInt TTraceDataParser::ParseStringForNumber(const TDesC8& aBuffer, const TDesC8& aFindStringPattern, TInt& aNumberFound) |
|
95 { |
|
96 TInt err = KErrNotFound; |
|
97 TInt posOfNum = aFindStringPattern.Locate('*'); |
|
98 TInt lengthOfNum = 1 + aBuffer.Length() - aFindStringPattern.Length(); |
|
99 if (posOfNum >= 0 && lengthOfNum >= 1) |
|
100 { |
|
101 TBuf<KMaxNumberBufferLength> numberBuffer; |
|
102 numberBuffer.Copy(aBuffer.Mid(posOfNum, lengthOfNum)); |
|
103 TLex lex(numberBuffer); |
|
104 err = lex.Val(aNumberFound); |
|
105 } |
|
106 return err; |
|
107 } |
|
108 |
|
109 /* |
|
110 * Validate the trace data in buffer |
|
111 * |
|
112 * @param aBuffer the buffer containing the trace data |
|
113 * @param aExpectedNum expected number of traces |
|
114 * @param aComponentID component ID of traces |
|
115 * @param aGroupID group ID of traces |
|
116 * @param aData first expected trace data |
|
117 * @param aTraceWord trace word of traces |
|
118 * @param aIdentical indicates that the payload of each trace packet should be identical |
|
119 * @param aBufferMode The mode of the trace buffer.. 0=straight, 1=circular. |
|
120 * @param aOrdinalData indicates whether the payload data reflects its position in the stream of trace packets |
|
121 * @param aNumTraces number of traces written to circular buffer |
|
122 * @param aMaxTraces maximum number of traces circular buffer can hold |
|
123 * @return Standard Symbian error code |
|
124 */ |
|
125 EXPORT_C TInt TTraceDataParser::ValidatePayload(TDesC8& aBuffer, |
|
126 TInt aExpectedNum, |
|
127 TComponentId aComponentID, |
|
128 TGroupId aGroupID, |
|
129 TUint32 aData, |
|
130 TUint32 aTraceWord, |
|
131 TBool aIdentical, |
|
132 TInt aBufferMode, |
|
133 TBool aOrdinalData, |
|
134 TInt aNumTraces, |
|
135 TInt aMaxTraces) |
|
136 { |
|
137 if ((aBuffer.Length() == 0) && (aExpectedNum <= 0)) // size is zero and there should be no traces |
|
138 { |
|
139 return KErrNone; |
|
140 } |
|
141 if ((aBuffer.Length() == 0) && (aExpectedNum > 0)) // size is zero and there should be traces |
|
142 { |
|
143 return KErrCorrupt; |
|
144 } |
|
145 if (aBuffer.Length() != 0 && (aExpectedNum <= 0)) // size is non-zero and there should be no traces |
|
146 { |
|
147 return KErrCorrupt; |
|
148 } |
|
149 |
|
150 TUint32 lastData = aData; |
|
151 TBool firstInStream = ETrue; |
|
152 |
|
153 // get the current position on the stream of traces so we can determine what the payload value should be. |
|
154 TInt overwrites = 0; |
|
155 if (aBufferMode == RTraceBuffer::EFreeRunning) |
|
156 { |
|
157 TInt overwrittenTraces = aNumTraces; // initialise to number of traces we wrote to the buffer for circular test |
|
158 while (overwrittenTraces > aMaxTraces) |
|
159 { |
|
160 overwrittenTraces = overwrittenTraces - aMaxTraces; // aMaxTraces is the max the buffer can hold |
|
161 overwrites++; |
|
162 } |
|
163 lastData = (aMaxTraces * (overwrites - 1)) + overwrittenTraces + 1; // get where we are in the buffer |
|
164 } |
|
165 |
|
166 TInt numberOSTtraces = 0; |
|
167 TUint8* data = (TUint8*) aBuffer.Ptr(); |
|
168 TUint8* endOfData = data + aBuffer.Size(); |
|
169 TUint8 testGID = aGroupID; |
|
170 TUint32 testCID = aComponentID; |
|
171 TUint32 testTraceWord = 0; |
|
172 |
|
173 TTraceHeaderSettings traceHeaderSettings; |
|
174 |
|
175 // Loop through all traces |
|
176 while (data < endOfData) |
|
177 { |
|
178 // Get trace info from header |
|
179 TInt err = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
180 |
|
181 if (err != KErrNone) |
|
182 { |
|
183 return err; |
|
184 } |
|
185 |
|
186 //check the missing flag if we expect it |
|
187 if ((firstInStream&&(overwrites>0))) |
|
188 { |
|
189 if(!(traceHeaderSettings.iHeaderFlags & BTrace::EMissingRecord)) |
|
190 { |
|
191 return KErrCorrupt; |
|
192 } |
|
193 } |
|
194 |
|
195 if (!traceHeaderSettings.iPrintfTrace) |
|
196 { |
|
197 testTraceWord = ((TUint32) (testGID << GROUPIDSHIFT)) + 1; |
|
198 |
|
199 // check group ID |
|
200 if (traceHeaderSettings.iCategory != testGID) |
|
201 { |
|
202 return KErrCorrupt; |
|
203 } |
|
204 // check component ID |
|
205 if (traceHeaderSettings.iComponentID != testCID) |
|
206 { |
|
207 return KErrCorrupt; |
|
208 } |
|
209 // check trace word |
|
210 if (traceHeaderSettings.iTraceWord != testTraceWord) |
|
211 { |
|
212 return KErrCorrupt; |
|
213 } |
|
214 |
|
215 TBool lastTrace = EFalse; |
|
216 if ( (traceHeaderSettings.iMultiPartType == BTrace::EMultipartLast) || (!traceHeaderSettings.iMultiPartType) ) |
|
217 { |
|
218 lastTrace = ETrue; |
|
219 } |
|
220 |
|
221 // check trace payload |
|
222 for (TInt i=0; traceHeaderSettings.iLengthOfPayload>0; i++) |
|
223 { |
|
224 TUint32 param = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter)); |
|
225 // For circular case, we try to estimate to within +/- 2 where we are in payload |
|
226 // for straight case we should get it exactly correct. |
|
227 if ( ((param != lastData) && (aBufferMode == 0)) || |
|
228 ( ((param > lastData + 2) || (param < lastData - 2)) && (aBufferMode == RTraceBuffer::EFreeRunning) ) ) |
|
229 { |
|
230 return KErrCorrupt; |
|
231 } |
|
232 lastData = param; // in case we weren't accurate in circular case. |
|
233 traceHeaderSettings.iLengthOfPayload -= 4; |
|
234 lastData++; |
|
235 } |
|
236 lastData = (!aOrdinalData)? aData : lastData; |
|
237 if (!aOrdinalData) |
|
238 { |
|
239 lastData = (lastTrace || aIdentical) ? aData : lastData; |
|
240 } |
|
241 |
|
242 if (traceHeaderSettings.iMultiPartType || aIdentical || aOrdinalData) |
|
243 { |
|
244 testGID = aGroupID; |
|
245 testCID = aComponentID; |
|
246 testTraceWord = aTraceWord; |
|
247 } |
|
248 else |
|
249 { |
|
250 testGID++; |
|
251 testCID++; |
|
252 testTraceWord += (1 << GROUPIDSHIFT); |
|
253 } |
|
254 numberOSTtraces++; |
|
255 } |
|
256 else |
|
257 { |
|
258 // Go to the next trace |
|
259 data += traceHeaderSettings.iLengthOfPayload; |
|
260 } |
|
261 firstInStream = EFalse; //after this, it's defnitely not the first trace in the stream. |
|
262 } |
|
263 |
|
264 // Check that we're getting the correct number of traces |
|
265 //or approximate ammount (+/-1) for circular buffer because |
|
266 //the arithmetic to overwrite traces sometimes also skips one |
|
267 //extra trace |
|
268 |
|
269 if (numberOSTtraces != aExpectedNum) |
|
270 { |
|
271 if ((aBufferMode==RTraceBuffer::EFreeRunning) |
|
272 &&((numberOSTtraces>=aExpectedNum-1)||(numberOSTtraces<=aExpectedNum+1))) |
|
273 { |
|
274 return KErrNone; |
|
275 } |
|
276 return KErrCorrupt; |
|
277 } |
|
278 |
|
279 return KErrNone; |
|
280 } |
|
281 |
|
282 /* |
|
283 * Validate the single trace data in buffer |
|
284 * |
|
285 * @param aBuffer the buffer containing the trace data |
|
286 * @param aTracePresent determines if trace data should be present or not |
|
287 * @param aGroupID expected GID |
|
288 * @param aComponentID expected CID |
|
289 * @param aData expected trace data |
|
290 * @param aPrintfTrace determines if trace data should be printf data or not |
|
291 * @param aMissingTrace determines if trace data should indicate missing data or not |
|
292 * @param aExpectedPrintfTrace expected printf trace data |
|
293 * @return Standard Symbian error code |
|
294 */ |
|
295 EXPORT_C TInt TTraceDataParser::ValidatePayload(TDesC8& aBuffer, |
|
296 TBool aTracePresent, |
|
297 TGroupId aGroupID, |
|
298 TComponentId aComponentID, |
|
299 TUint32 aData, |
|
300 TBool aPrintfTrace, |
|
301 TBool aMissingTrace, |
|
302 TDesC8* aExpectedPrintfTrace) |
|
303 { |
|
304 if ((aBuffer.Length() == 0) && (!aTracePresent)) // size is zero and there should be no traces |
|
305 { |
|
306 return KErrNone; |
|
307 } |
|
308 if ((aBuffer.Length() == 0) && (aTracePresent)) // size is zero and there should be traces |
|
309 { |
|
310 return KErrCorrupt; |
|
311 } |
|
312 if (aBuffer.Length() != 0 && (!aTracePresent)) // size is non-zero and there should be no traces |
|
313 { |
|
314 return KErrCorrupt; |
|
315 } |
|
316 |
|
317 TUint8* data = (TUint8*) aBuffer.Ptr(); |
|
318 TUint8* endOfData = data + aBuffer.Size(); |
|
319 |
|
320 TTraceHeaderSettings traceHeaderSettings; |
|
321 |
|
322 // Get trace info from header |
|
323 TInt err = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
324 |
|
325 if (err != KErrNone) |
|
326 { |
|
327 return err; |
|
328 } |
|
329 |
|
330 // check trace type |
|
331 if (traceHeaderSettings.iPrintfTrace != aPrintfTrace) |
|
332 { |
|
333 return KErrCorrupt; |
|
334 } |
|
335 |
|
336 if (!traceHeaderSettings.iPrintfTrace) |
|
337 { |
|
338 TUint32 testTraceWord = ((TUint32) (aGroupID << GROUPIDSHIFT)) + 1; |
|
339 |
|
340 // check group ID |
|
341 if (traceHeaderSettings.iCategory != aGroupID) |
|
342 { |
|
343 return KErrCorrupt; |
|
344 } |
|
345 // check component ID |
|
346 if (traceHeaderSettings.iComponentID != aComponentID) |
|
347 { |
|
348 return KErrCorrupt; |
|
349 } |
|
350 // check trace word |
|
351 if (traceHeaderSettings.iTraceWord != testTraceWord) |
|
352 { |
|
353 return KErrCorrupt; |
|
354 } |
|
355 |
|
356 if (aMissingTrace) |
|
357 { |
|
358 // check missing flag |
|
359 if (!(traceHeaderSettings.iHeaderFlags & BTrace::EMissingRecord)) |
|
360 { |
|
361 return KErrCorrupt; |
|
362 } |
|
363 } |
|
364 |
|
365 TInt i = 0; |
|
366 while (data < endOfData) |
|
367 { |
|
368 TUint32 param = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter)); |
|
369 if (param != aData + i) |
|
370 { |
|
371 return KErrCorrupt; |
|
372 } |
|
373 i++; |
|
374 } |
|
375 } |
|
376 else if (!aExpectedPrintfTrace) |
|
377 { |
|
378 return KErrArgument; |
|
379 } |
|
380 else |
|
381 { |
|
382 TBuf8<KExpectedPrintfMaxLength> expectedPrintf; |
|
383 |
|
384 // In the case of an expected dropped trace, we only check for "* Dropped Trace" because |
|
385 // the test writer has completed the request for data when it writes that bit first (right |
|
386 // before the next trace), and when it goes to write the actual trace, it doesn't. |
|
387 // If we change this, the "* Dropped Trace" will be overwritten by the actual trace before |
|
388 // the test can check it, since the test writer doesn't buffer trace data. |
|
389 if (aMissingTrace) |
|
390 { |
|
391 // check that "* Dropped Trace" is in the buffer |
|
392 expectedPrintf = KDroppedTrace; |
|
393 } |
|
394 else |
|
395 { |
|
396 // check that "Test Printf Trace" is in the buffer" |
|
397 expectedPrintf = *aExpectedPrintfTrace; |
|
398 } |
|
399 |
|
400 expectedPrintf.Append(TChar(0)); // printf handler appends null at the end. |
|
401 |
|
402 TPtrC8 actualprintf(data, traceHeaderSettings.iLengthOfPayload); |
|
403 |
|
404 // Need to fix endianess for hw |
|
405 #ifndef __WINS__ |
|
406 TInt bufpos = 0; |
|
407 while (bufpos < (actualprintf.Length()-4)) |
|
408 { |
|
409 // reads a 4 byte integer of expected endianess |
|
410 TUint32 n = actualprintf[bufpos] + (actualprintf[bufpos+1] << 8) + (actualprintf[bufpos+2] << 16) + (actualprintf[bufpos+3] << 24); |
|
411 bufpos += sizeof(TUint32); |
|
412 TUint32 tempData = Swap(n); |
|
413 memcpy((TAny*)(actualprintf.Ptr()+bufpos-4),(TAny*)&tempData, sizeof(TUint32)); |
|
414 } |
|
415 #endif //__WINS__ |
|
416 |
|
417 if (expectedPrintf.Compare(actualprintf) != 0) |
|
418 { |
|
419 return KErrCorrupt; |
|
420 } |
|
421 |
|
422 // Check if there is another trace to follow |
|
423 data += traceHeaderSettings.iLengthOfPayload; |
|
424 if (data != endOfData) |
|
425 { |
|
426 TPtrC8 buffer(data, endOfData - data); |
|
427 |
|
428 return ValidatePayload(buffer, |
|
429 aTracePresent, |
|
430 aGroupID, |
|
431 aComponentID, |
|
432 aData, |
|
433 aPrintfTrace, |
|
434 EFalse, |
|
435 aExpectedPrintfTrace); |
|
436 } |
|
437 } |
|
438 return KErrNone; |
|
439 } |
|
440 |
|
441 /* |
|
442 * Verify the priming data contains all the expected values |
|
443 * |
|
444 * @param aBuffer Buffer containing the trace data |
|
445 * @param aSize Size of the trace buffer |
|
446 * @param aCategory BTrace category of the trace data |
|
447 * @param aSubCategory BTrace subcategory of the trace data |
|
448 * @param aElementsFound Parameter to hold current state of expected data found so far |
|
449 * @param aVerificationData1 Optional input value - used differently for different categories |
|
450 * @param aVerificationData2 Optional input value - used differently for different categories |
|
451 * @return Standard Symbian error code |
|
452 */ |
|
453 TInt TTraceDataParser::VerifyPrimingData(TUint8* aBuffer, |
|
454 TInt aSize, |
|
455 TUint8 aCategory, |
|
456 TUint8 aSubCategory, |
|
457 TInt& aElementsFound, |
|
458 TBool aFromTestWriter, |
|
459 TUint32 aVerificationData1, |
|
460 TUint32 aVerificationData2) |
|
461 { |
|
462 TInt err = KErrNotSupported; |
|
463 switch(aCategory) |
|
464 { |
|
465 case BTrace::EThreadIdentification: |
|
466 err = VerifyThreadPrimingData(aBuffer, aSize, aSubCategory, aElementsFound, aFromTestWriter, aVerificationData1, aVerificationData2); |
|
467 break; |
|
468 case BTrace::EFastMutex: |
|
469 err = VerifyFastMutexPrimingData(aBuffer, aSize, aSubCategory, aElementsFound, aFromTestWriter); |
|
470 break; |
|
471 case BTrace::ECodeSegs: |
|
472 err = VerifyCodeSegsPrimingData(aBuffer, aSize, aSubCategory, aElementsFound, aFromTestWriter, aVerificationData1, aVerificationData2); |
|
473 break; |
|
474 default: |
|
475 break; |
|
476 } |
|
477 return err; |
|
478 } |
|
479 |
|
480 /* |
|
481 * Verify the EThreadIdentification priming data contains all the expected values |
|
482 * |
|
483 * @param aBuffer Buffer containing the trace data |
|
484 * @param aSize Size of the trace buffer |
|
485 * @param aSubCategory BTrace subcategory of the trace data |
|
486 * @param aElementsFound Parameter to hold current state of expected data found so far |
|
487 * @param aThreadAddr The address of the thread to search for |
|
488 * @param aProcessAddr The address of the process to search for |
|
489 * @return Standard Symbian error code |
|
490 */ |
|
491 TInt TTraceDataParser::VerifyThreadPrimingData(TUint8* aBuffer, |
|
492 TInt aSize, |
|
493 TUint8 aSubCategory, |
|
494 TInt& aElementsFound, |
|
495 TBool aFromTestWriter, |
|
496 TUint32 aThreadAddr, |
|
497 TUint32 aProcessAddr) |
|
498 { |
|
499 RThread currentThread; |
|
500 RProcess currentProcess; |
|
501 |
|
502 TUint32 tempThreadAddr; |
|
503 TUint32 tempProcessAddr; |
|
504 |
|
505 switch(aSubCategory) |
|
506 { |
|
507 case BTrace::EProcessCreate: |
|
508 { |
|
509 tempProcessAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
510 if (tempProcessAddr == aProcessAddr) |
|
511 { |
|
512 aElementsFound |= 0x000000ff; |
|
513 } |
|
514 } |
|
515 break; |
|
516 |
|
517 case BTrace::EProcessName: |
|
518 { |
|
519 tempThreadAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
520 tempProcessAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
521 if ( (tempThreadAddr == aThreadAddr) && (tempProcessAddr == aProcessAddr) ) |
|
522 { |
|
523 TBuf8<KMaxName> currentProcessName; |
|
524 currentProcessName.Copy(currentProcess.Name()); |
|
525 TPtr8 processName(aBuffer,(aSize-8),(aSize-8)); //should be name of the process |
|
526 processName.Trim(); |
|
527 if (StringsMatch(currentProcessName, processName)) |
|
528 { |
|
529 aElementsFound |= 0x0000ff00; |
|
530 } |
|
531 } |
|
532 } |
|
533 break; |
|
534 |
|
535 case BTrace::EThreadName: |
|
536 { |
|
537 tempThreadAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
538 tempProcessAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
539 if ( (tempThreadAddr == aThreadAddr) && (tempProcessAddr == aProcessAddr) ) |
|
540 { |
|
541 TBuf8<KMaxName> currentThreadName; |
|
542 currentThreadName.Copy(currentThread.Name()); |
|
543 TPtr8 threadName(aBuffer,(aSize-8),(aSize-8)); //should be name of the thread |
|
544 threadName.Trim(); |
|
545 if (StringsMatch(currentThreadName, threadName)) |
|
546 { |
|
547 aElementsFound |= 0x00ff0000; |
|
548 } |
|
549 } |
|
550 } |
|
551 break; |
|
552 |
|
553 case BTrace::EThreadId: |
|
554 { |
|
555 tempThreadAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
556 tempProcessAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
557 if ( (tempThreadAddr == aThreadAddr) && (tempProcessAddr == aProcessAddr) ) |
|
558 { |
|
559 TThreadId threadId = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
560 if (currentThread.Id() == threadId) |
|
561 { |
|
562 aElementsFound |= 0xff000000; |
|
563 } |
|
564 } |
|
565 } |
|
566 break; |
|
567 |
|
568 default: |
|
569 break; |
|
570 } |
|
571 |
|
572 TInt err = KErrNotFound; |
|
573 if (aElementsFound == 0xffffffff) |
|
574 { |
|
575 err = KErrNone; |
|
576 } |
|
577 return err; |
|
578 } |
|
579 |
|
580 /* |
|
581 * Verify the EFastMutex priming data contains all the expected values |
|
582 * |
|
583 * @param aBuffer Buffer containing the trace data |
|
584 * @param aSize Size of the trace buffer |
|
585 * @param aSubCategory BTrace subcategory of the trace data |
|
586 * @param aElementsFound Parameter to hold current state of expected data found so far |
|
587 * @return Standard Symbian error code |
|
588 */ |
|
589 TInt TTraceDataParser::VerifyFastMutexPrimingData(TUint8* aBuffer, |
|
590 TInt aSize, |
|
591 TUint8 aSubCategory, |
|
592 TInt& aElementsFound, |
|
593 TBool aFromTestWriter) |
|
594 { |
|
595 if (aSubCategory == BTrace::EFastMutexName) |
|
596 { |
|
597 TUint32 fastMutexId = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
598 TUint32 unspecified = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
599 if (fastMutexId && !unspecified) |
|
600 { |
|
601 TPtr8 fastMutexName(aBuffer,(aSize-8),(aSize-8)); //should be name of the fast mutex |
|
602 fastMutexName.Trim(); |
|
603 if (StringsMatch(KFastMutexNameSystemLock(), fastMutexName)) |
|
604 { |
|
605 aElementsFound |= 0x000000ff; |
|
606 } |
|
607 else if (StringsMatch(KFastMutexNameMsgLock(), fastMutexName)) |
|
608 { |
|
609 aElementsFound |= 0x0000ff00; |
|
610 } |
|
611 else if (StringsMatch(KFastMutexNameObjLock(), fastMutexName)) |
|
612 { |
|
613 aElementsFound |= 0x00ff0000; |
|
614 } |
|
615 else if (StringsMatch(KFastMutexNameLogonLock(), fastMutexName)) |
|
616 { |
|
617 aElementsFound |= 0xff000000; |
|
618 } |
|
619 } |
|
620 } |
|
621 |
|
622 TInt err = KErrNotFound; |
|
623 if (aElementsFound == 0xffffffff) |
|
624 { |
|
625 err = KErrNone; |
|
626 } |
|
627 return err; |
|
628 } |
|
629 |
|
630 /* |
|
631 * Verify the ECodeSegs priming data contains all the expected values |
|
632 * |
|
633 * @param aBuffer Buffer containing the trace data |
|
634 * @param aSize Size of the trace buffer |
|
635 * @param aSubCategory BTrace subcategory of the trace data |
|
636 * @param aElementsFound Parameter to hold current state of expected data found so far |
|
637 * @param aSegAddr1 The address of the first code seg to search for |
|
638 * @param aSegAddr2 The address of the second code seg to search for |
|
639 * @return Standard Symbian error code |
|
640 */ |
|
641 TInt TTraceDataParser::VerifyCodeSegsPrimingData(TUint8* aBuffer, |
|
642 TInt aSize, |
|
643 TUint8 aSubCategory, |
|
644 TInt& aElementsFound, |
|
645 TBool aFromTestWriter, |
|
646 TUint32 aSegAddr1, |
|
647 TUint32 aSegAddr2) |
|
648 { |
|
649 TUint32 codeSegAddr; |
|
650 if (aSubCategory == BTrace::ECodeSegCreated) |
|
651 { |
|
652 codeSegAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
653 if (codeSegAddr == aSegAddr1 || codeSegAddr == aSegAddr2) |
|
654 { |
|
655 TPtr8 codeSegName(aBuffer,(aSize-4),(aSize-4)); //should be name of the code seg |
|
656 codeSegName.Trim(); |
|
657 if (codeSegAddr == aSegAddr1 && StringsMatch(KCodeSegsName1(), codeSegName)) |
|
658 { |
|
659 aElementsFound |= 0x000000ff; |
|
660 } |
|
661 else if (codeSegAddr == aSegAddr2 && StringsMatch(KCodeSegsName2(), codeSegName)) |
|
662 { |
|
663 aElementsFound |= 0x0000ff00; |
|
664 } |
|
665 } |
|
666 } |
|
667 else if (aSubCategory == BTrace::ECodeSegInfo) |
|
668 { |
|
669 codeSegAddr = Swap(ReadUint32FromBuf(aBuffer, aFromTestWriter)); |
|
670 if (codeSegAddr == aSegAddr1) |
|
671 { |
|
672 aElementsFound |= 0x00ff0000; |
|
673 } |
|
674 else if (codeSegAddr == aSegAddr2) |
|
675 { |
|
676 aElementsFound |= 0xff000000; |
|
677 } |
|
678 } |
|
679 |
|
680 TInt err = KErrNotFound; |
|
681 if (aElementsFound == 0xffffffff) |
|
682 { |
|
683 err = KErrNone; |
|
684 } |
|
685 return err; |
|
686 } |
|
687 |
|
688 /* |
|
689 * Work out if a trace point is potentially kernel priming data based on category and subcategory |
|
690 * |
|
691 * @param aCategory BTrace category of the trace data |
|
692 * @param aSubCategory BTrace subcategory of the trace data |
|
693 * @param aIsPotentialPrimingTrace Output value set if there is no error |
|
694 * @return Standard Symbian error code |
|
695 */ |
|
696 TBool TTraceDataParser::IsPotentialPrimingTrace(TUint8 aCategory, TUint8 aSubCategory, TBool& aIsPotentialPrimingTrace) |
|
697 { |
|
698 TInt err = KErrNone; |
|
699 |
|
700 switch(aCategory) |
|
701 { |
|
702 case BTrace::EThreadIdentification: |
|
703 { |
|
704 switch(aSubCategory) |
|
705 { |
|
706 case BTrace::EProcessCreate: |
|
707 case BTrace::EProcessName: |
|
708 case BTrace::EThreadName: |
|
709 case BTrace::EThreadId: |
|
710 aIsPotentialPrimingTrace = ETrue; |
|
711 break; |
|
712 default: |
|
713 aIsPotentialPrimingTrace = EFalse; |
|
714 break; |
|
715 } |
|
716 } |
|
717 break; |
|
718 case BTrace::ECpuUsage: |
|
719 { |
|
720 switch(aSubCategory) |
|
721 { |
|
722 case BTrace::ENewThreadContext: |
|
723 aIsPotentialPrimingTrace = ETrue; |
|
724 break; |
|
725 default: |
|
726 aIsPotentialPrimingTrace = EFalse; |
|
727 break; |
|
728 } |
|
729 } |
|
730 break; |
|
731 case BTrace::EChunks: |
|
732 { |
|
733 switch(aSubCategory) |
|
734 { |
|
735 case BTrace::EChunkCreated: |
|
736 case BTrace::EChunkOwner: |
|
737 case BTrace::EChunkInfo: |
|
738 aIsPotentialPrimingTrace = ETrue; |
|
739 break; |
|
740 default: |
|
741 aIsPotentialPrimingTrace = EFalse; |
|
742 break; |
|
743 } |
|
744 } |
|
745 break; |
|
746 case BTrace::ECodeSegs: |
|
747 { |
|
748 switch(aSubCategory) |
|
749 { |
|
750 case BTrace::ECodeSegCreated: |
|
751 case BTrace::ECodeSegInfo: |
|
752 aIsPotentialPrimingTrace = ETrue; |
|
753 break; |
|
754 default: |
|
755 aIsPotentialPrimingTrace = EFalse; |
|
756 break; |
|
757 } |
|
758 } |
|
759 break; |
|
760 case BTrace::EPaging: |
|
761 { |
|
762 switch(aSubCategory) |
|
763 { |
|
764 case BTrace::EPagingMemoryModel: |
|
765 aIsPotentialPrimingTrace = ETrue; |
|
766 break; |
|
767 default: |
|
768 aIsPotentialPrimingTrace = EFalse; |
|
769 break; |
|
770 } |
|
771 } |
|
772 break; |
|
773 case BTrace::EThreadPriority: |
|
774 { |
|
775 switch(aSubCategory) |
|
776 { |
|
777 case BTrace::EProcessPriority: |
|
778 case BTrace::EDThreadPriority: |
|
779 case BTrace::ENThreadPriority: |
|
780 aIsPotentialPrimingTrace = ETrue; |
|
781 break; |
|
782 default: |
|
783 aIsPotentialPrimingTrace = EFalse; |
|
784 break; |
|
785 } |
|
786 } |
|
787 break; |
|
788 case BTrace::EFastMutex: |
|
789 { |
|
790 switch(aSubCategory) |
|
791 { |
|
792 case BTrace::EFastMutexName: |
|
793 aIsPotentialPrimingTrace = ETrue; |
|
794 break; |
|
795 default: |
|
796 aIsPotentialPrimingTrace = EFalse; |
|
797 break; |
|
798 } |
|
799 } |
|
800 break; |
|
801 case BTrace::ESymbianKernelSync: |
|
802 { |
|
803 switch(aSubCategory) |
|
804 { |
|
805 case BTrace::EMutexCreate: |
|
806 case BTrace::ESemaphoreCreate: |
|
807 case BTrace::ECondVarCreate: |
|
808 aIsPotentialPrimingTrace = ETrue; |
|
809 break; |
|
810 default: |
|
811 aIsPotentialPrimingTrace = EFalse; |
|
812 break; |
|
813 } |
|
814 } |
|
815 break; |
|
816 case BTrace::EClientServer: |
|
817 { |
|
818 switch(aSubCategory) |
|
819 { |
|
820 case BTrace::EServerCreate: |
|
821 case BTrace::ESessionAttach: |
|
822 aIsPotentialPrimingTrace = ETrue; |
|
823 break; |
|
824 default: |
|
825 aIsPotentialPrimingTrace = EFalse; |
|
826 break; |
|
827 } |
|
828 } |
|
829 break; |
|
830 default: |
|
831 err = KErrNotSupported; |
|
832 break; |
|
833 } |
|
834 |
|
835 return err; |
|
836 } |
|
837 |
|
838 /* |
|
839 * If the next trace is a meta trace true is returned if it is the start of priming data for a given group ID |
|
840 * |
|
841 * @param aBuffer Buffer containing the trace data |
|
842 * @param aGroupId Group ID of kernel priming data |
|
843 * @param aCategory BTrace category of the current trace |
|
844 * @param aSubCategory BTrace subcategory of the current trace |
|
845 * @return True if start of priming data for given group ID, false otherwise |
|
846 */ |
|
847 TBool TTraceDataParser::IsStartOfKernelPrimingBatch(TUint8* aBuffer, TGroupId aGroupId, TUint8 aCategory, TUint8 aSubCategory) |
|
848 { |
|
849 TBool startOfBatch = EFalse; |
|
850 if (aCategory == BTrace::EMetaTrace) |
|
851 { |
|
852 if (aSubCategory == BTrace::EMetaTraceFilterChange) |
|
853 { |
|
854 TUint8 metaCategory = aBuffer[0]; |
|
855 TUint8 isActive = aBuffer[1]; |
|
856 if (metaCategory == aGroupId && isActive) |
|
857 { |
|
858 startOfBatch = ETrue; |
|
859 } |
|
860 } |
|
861 } |
|
862 return startOfBatch; |
|
863 } |
|
864 |
|
865 /* |
|
866 * Use heuristics to work out if current trace is part of kernel priming data |
|
867 * |
|
868 * @param aCategory BTrace category of the trace data |
|
869 * @param aSubCategory BTrace subcategory of the trace data |
|
870 * @param aTimeDifference Time difference (in microseconds) since last trace for given category |
|
871 * @param aIsInPrimingBatch Output parameter set to true if in priming data |
|
872 * @param aFirstTrace Boolean used to indicate if this is first trace (so there is no valid time difference) |
|
873 * @param aStartOfBatch Output parameter set to true if start of batch of kernel priming data |
|
874 * @return Standard Symbian error code |
|
875 */ |
|
876 TInt TTraceDataParser::IsInPrimingBatch(TUint8 aCategory, |
|
877 TUint8 aSubCategory, |
|
878 TUint32 aTimeDifference, |
|
879 TBool& aIsInPrimingBatch, |
|
880 TBool& aFirstTrace, |
|
881 TBool& aStartOfBatch) |
|
882 { |
|
883 TBool isPotentialPrimingTrace = EFalse; |
|
884 TInt err = IsPotentialPrimingTrace(aCategory, aSubCategory, isPotentialPrimingTrace); |
|
885 |
|
886 // Look at timestamp to see if this is a new batch of traces |
|
887 if (aFirstTrace) |
|
888 { |
|
889 aFirstTrace = EFalse; |
|
890 } |
|
891 else if (aTimeDifference > KMinMilliSecondsBatchGap * 1000) |
|
892 { |
|
893 aStartOfBatch = ETrue; |
|
894 aIsInPrimingBatch = EFalse; |
|
895 } |
|
896 else |
|
897 { |
|
898 aStartOfBatch = EFalse; |
|
899 } |
|
900 |
|
901 if (isPotentialPrimingTrace && aStartOfBatch) |
|
902 { |
|
903 aIsInPrimingBatch = ETrue; |
|
904 aStartOfBatch = EFalse; |
|
905 } |
|
906 else if (!isPotentialPrimingTrace) |
|
907 { |
|
908 aIsInPrimingBatch = EFalse; |
|
909 } |
|
910 |
|
911 return err; |
|
912 } |
|
913 |
|
914 /* |
|
915 * Parse the trace data header |
|
916 * |
|
917 * The following trace types are supported: |
|
918 * OST traces (ascii and binary) |
|
919 * XTIv3 traces (ascii and binary) |
|
920 * Traces from the Test Writer (ascii and binary) |
|
921 * |
|
922 * @param aData Buffer containing the trace data |
|
923 * @param aSize Size of trace data buffer |
|
924 * @param aTraceHeaderSettings Output parameters set to header settings of the trace data |
|
925 * @return Standard Symbian error code |
|
926 */ |
|
927 TInt TTraceDataParser::ParseHeader(TUint8*& aData, |
|
928 TInt aSize, |
|
929 TTraceHeaderSettings& aTraceHeaderSettings) |
|
930 { |
|
931 // Check buffer is large enough to contain header |
|
932 aSize--; |
|
933 if (aSize < 0) |
|
934 { |
|
935 return KErrOverflow; |
|
936 } |
|
937 |
|
938 TInt err = KErrNone; |
|
939 TUint8* startOfData = aData; |
|
940 aTraceHeaderSettings.iMultiPartType = 0; |
|
941 aTraceHeaderSettings.iMultiPartTraceID = 0; |
|
942 aTraceHeaderSettings.iPrintfTrace = EFalse; |
|
943 aTraceHeaderSettings.iHeaderFlags = EFalse; |
|
944 aTraceHeaderSettings.iFromTestWriter = EFalse; |
|
945 TBool xtiTrace = EFalse; |
|
946 TUint8 version = aData[0]; // Version (1 byte) |
|
947 aData++; |
|
948 |
|
949 if (version == KXtiHeaderVersion) |
|
950 { |
|
951 // Check buffer is large enough to contain header |
|
952 aSize -= KMinSizeXtiHeader; |
|
953 if (aSize < 0) |
|
954 { |
|
955 aData = startOfData; |
|
956 return KErrOverflow; |
|
957 } |
|
958 xtiTrace = ETrue; |
|
959 TUint8 xtiTraceType = aData[KXtiTraceTypeIndex-1]; |
|
960 if (xtiTraceType != KXtiProtocolIdSimpleTrace) |
|
961 { |
|
962 aTraceHeaderSettings.iPrintfTrace = ETrue; |
|
963 aTraceHeaderSettings.iLengthOfPayload = aData[KXtiLengthIndex-1] - 15; |
|
964 aData += KMinSizeXtiHeader; |
|
965 } |
|
966 else |
|
967 { |
|
968 // Check buffer is large enough to contain header |
|
969 aSize -= 1; |
|
970 if (aSize < 0) |
|
971 { |
|
972 aData = startOfData; |
|
973 return KErrOverflow; |
|
974 } |
|
975 // Jump to start of OST buffer |
|
976 aData += KMinSizeXtiHeader + 1; |
|
977 version = aData[0]; |
|
978 aData++; |
|
979 } |
|
980 } |
|
981 |
|
982 if (version == KHeaderVersion) // Ost header version byte is correct |
|
983 { |
|
984 // Check buffer is large enough to contain header |
|
985 aSize -= KMinSizeOstHeader; |
|
986 if (aSize < 0) |
|
987 { |
|
988 aData = startOfData; |
|
989 return KErrOverflow; |
|
990 } |
|
991 const TUint8 protocolId = aData[0]; // Protocol ID (1 byte) |
|
992 aData++; |
|
993 if (xtiTrace) |
|
994 { |
|
995 aTraceHeaderSettings.iLengthOfPayload = aData[0]; |
|
996 aData++; |
|
997 aSize++; |
|
998 } |
|
999 else |
|
1000 { |
|
1001 aTraceHeaderSettings.iLengthOfPayload = ReadUint16FromBuf(aData); // Size (2 bytes) |
|
1002 } |
|
1003 |
|
1004 if (protocolId == KProtocolIdSimpleTrace) // Normal binary data |
|
1005 { |
|
1006 // Check buffer is large enough to contain header |
|
1007 aSize -= KMinSizeOstBinaryHeader; |
|
1008 if (aSize < 0) |
|
1009 { |
|
1010 aData = startOfData; |
|
1011 return KErrOverflow; |
|
1012 } |
|
1013 ReadUint32FromBuf(aData); // Timestamp 1 (4 bytes) |
|
1014 aTraceHeaderSettings.iTimestamp = ReadUint32FromBuf(aData); // Timestamp 2 (4 bytes) |
|
1015 } |
|
1016 else if (protocolId == KProtocolIdAscii) // Ascii Printf data |
|
1017 { |
|
1018 aTraceHeaderSettings.iPrintfTrace = ETrue; |
|
1019 // Check buffer is large enough to contain header |
|
1020 aSize -= KMinSizeOstAsciiHeader; |
|
1021 if (aSize < 0) |
|
1022 { |
|
1023 aData = startOfData; |
|
1024 return KErrOverflow; |
|
1025 } |
|
1026 aData += 8; |
|
1027 aTraceHeaderSettings.iLengthOfPayload -= 8; |
|
1028 } |
|
1029 else // Protocol ID is incorrect |
|
1030 { |
|
1031 err = KErrCorrupt; |
|
1032 } |
|
1033 } |
|
1034 else if (version == SYMBIAN_TRACE) // Trace data is binary data from Test Writer |
|
1035 { |
|
1036 aTraceHeaderSettings.iFromTestWriter = ETrue; |
|
1037 } |
|
1038 else if (version == PRINTF_TRACE) // Trace data is ascii data from Test Writer |
|
1039 { |
|
1040 aTraceHeaderSettings.iFromTestWriter = ETrue; |
|
1041 aTraceHeaderSettings.iPrintfTrace = ETrue; |
|
1042 // The end of the printf trace data will have null char, so use that to find end of payload |
|
1043 TPtr8 printfString(aData, aSize, aSize); |
|
1044 aTraceHeaderSettings.iLengthOfPayload = printfString.Locate(TChar(0)); |
|
1045 if (aTraceHeaderSettings.iLengthOfPayload >= 0) |
|
1046 { |
|
1047 aTraceHeaderSettings.iLengthOfPayload++; |
|
1048 } |
|
1049 else |
|
1050 { |
|
1051 err = KErrCorrupt; |
|
1052 } |
|
1053 } |
|
1054 else if (version != KXtiHeaderVersion) |
|
1055 { |
|
1056 err = KErrCorrupt; |
|
1057 |
|
1058 if(aTraceHeaderSettings.iLengthOfPayload < 0 ) |
|
1059 { |
|
1060 err = KErrOverflow; |
|
1061 } |
|
1062 } |
|
1063 |
|
1064 if (aTraceHeaderSettings.iPrintfTrace) |
|
1065 { |
|
1066 aTraceHeaderSettings.iTimestamp = 0; |
|
1067 aTraceHeaderSettings.iComponentID = 0; |
|
1068 aTraceHeaderSettings.iCategory = 0; |
|
1069 aTraceHeaderSettings.iSubCategory = 0; |
|
1070 aTraceHeaderSettings.iTraceWord = 0; |
|
1071 } |
|
1072 else if (err == KErrNone) |
|
1073 { |
|
1074 // Check buffer is large enough to contain header |
|
1075 aSize -= KMinSizeBinaryHeader; |
|
1076 if (aSize < 0) |
|
1077 { |
|
1078 aData = startOfData; |
|
1079 return KErrOverflow; |
|
1080 } |
|
1081 aTraceHeaderSettings.iComponentID = ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter); // ComponentId (4 bytes) |
|
1082 aTraceHeaderSettings.iTraceWord = ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter); // GroupId (2 bytes). TraceId (2 bytes) |
|
1083 |
|
1084 TUint8* startOfPayload = aData; |
|
1085 TUint8 size; |
|
1086 |
|
1087 TBool testWriterHwData = EFalse; |
|
1088 #ifndef __WINS__ |
|
1089 testWriterHwData = aTraceHeaderSettings.iFromTestWriter; |
|
1090 #endif |
|
1091 |
|
1092 // now look at BTrace header and payload. |
|
1093 if (!testWriterHwData) |
|
1094 { |
|
1095 size = aData[BTrace::ESizeIndex]; |
|
1096 aTraceHeaderSettings.iHeaderFlags = aData[BTrace::EFlagsIndex]; |
|
1097 aTraceHeaderSettings.iCategory = aData[BTrace::ECategoryIndex]; |
|
1098 aTraceHeaderSettings.iSubCategory = aData[BTrace::ESubCategoryIndex]; |
|
1099 } |
|
1100 else |
|
1101 { |
|
1102 // endianess order is reversed for TestWriter on hw |
|
1103 aTraceHeaderSettings.iSubCategory = aData[BTrace::ESizeIndex]; |
|
1104 aTraceHeaderSettings.iCategory = aData[BTrace::EFlagsIndex]; |
|
1105 aTraceHeaderSettings.iHeaderFlags = aData[BTrace::ECategoryIndex]; |
|
1106 size = aData[BTrace::ESubCategoryIndex]; |
|
1107 } |
|
1108 |
|
1109 aData+=4; |
|
1110 |
|
1111 //read header extensions |
|
1112 if(aTraceHeaderSettings.iHeaderFlags & BTrace::EHeader2Present) |
|
1113 { |
|
1114 // Check buffer is large enough to contain header |
|
1115 aSize -= 4; |
|
1116 if (aSize < 0) |
|
1117 { |
|
1118 aData = startOfData; |
|
1119 return KErrOverflow; |
|
1120 } |
|
1121 TUint32 header2 = Swap(ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter)); |
|
1122 aTraceHeaderSettings.iMultiPartType = header2 & BTrace::EMultipartFlagMask; |
|
1123 } |
|
1124 if(aTraceHeaderSettings.iHeaderFlags & BTrace::ETimestampPresent) |
|
1125 { |
|
1126 // Check buffer is large enough to contain header |
|
1127 aSize -= 4; |
|
1128 if (aSize < 0) |
|
1129 { |
|
1130 aData = startOfData; |
|
1131 return KErrOverflow; |
|
1132 } |
|
1133 ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter); |
|
1134 } |
|
1135 if(aTraceHeaderSettings.iHeaderFlags & BTrace::ETimestamp2Present) |
|
1136 { |
|
1137 // Check buffer is large enough to contain header |
|
1138 aSize -= 4; |
|
1139 if (aSize < 0) |
|
1140 { |
|
1141 aData = startOfData; |
|
1142 return KErrOverflow; |
|
1143 } |
|
1144 ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter); |
|
1145 } |
|
1146 if(aTraceHeaderSettings.iHeaderFlags & BTrace::EContextIdPresent) |
|
1147 { |
|
1148 // Check buffer is large enough to contain header |
|
1149 aSize -= 4; |
|
1150 if (aSize < 0) |
|
1151 { |
|
1152 aData = startOfData; |
|
1153 return KErrOverflow; |
|
1154 } |
|
1155 ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter); |
|
1156 } |
|
1157 if(aTraceHeaderSettings.iHeaderFlags & BTrace::EPcPresent) |
|
1158 { |
|
1159 // Check buffer is large enough to contain header |
|
1160 aSize -= 4; |
|
1161 if (aSize < 0) |
|
1162 { |
|
1163 aData = startOfData; |
|
1164 return KErrOverflow; |
|
1165 } |
|
1166 ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter); |
|
1167 } |
|
1168 if(aTraceHeaderSettings.iHeaderFlags & BTrace::EExtraPresent) |
|
1169 { |
|
1170 // Check buffer is large enough to contain header |
|
1171 aSize -=4 ; |
|
1172 if (aSize < 0) |
|
1173 { |
|
1174 aData = startOfData; |
|
1175 return KErrOverflow; |
|
1176 } |
|
1177 aTraceHeaderSettings.iMultiPartTraceID = Swap(ReadUint32FromBuf(aData, aTraceHeaderSettings.iFromTestWriter)); |
|
1178 } |
|
1179 |
|
1180 if (!xtiTrace) |
|
1181 { |
|
1182 size = (size+3)&~3; // make it 4 byte aligned |
|
1183 } |
|
1184 if (size == 0) |
|
1185 { |
|
1186 // This happens when the trace is larger than maximum size, and we can't use the BTrace size field |
|
1187 // Instead calculate payload length based on size in OST header |
|
1188 aTraceHeaderSettings.iLengthOfPayload -= (aData-startOfPayload)+16; // size of rest of payload |
|
1189 } |
|
1190 else |
|
1191 { |
|
1192 aTraceHeaderSettings.iLengthOfPayload = size-(aData-startOfPayload); // size of rest of payload |
|
1193 } |
|
1194 } |
|
1195 |
|
1196 |
|
1197 // Check buffer is large enough to contain payload |
|
1198 aSize -= aTraceHeaderSettings.iLengthOfPayload; |
|
1199 if (aSize < 0) |
|
1200 { |
|
1201 aData = startOfData; |
|
1202 err = KErrOverflow; |
|
1203 } |
|
1204 |
|
1205 return err; |
|
1206 } |
|
1207 |
|
1208 /* |
|
1209 * Get the data required to verify kernel priming traces for EThreadIdentification |
|
1210 * |
|
1211 * @param aBuffer Buffer containing the trace data |
|
1212 * @param aSize Size of the trace buffer |
|
1213 * @param aThreadAddr Output parameter set to address of current thread |
|
1214 * @param aProcessAddr Output parameter set to address of current process |
|
1215 * @return Standard Symbian error code |
|
1216 */ |
|
1217 TInt TTraceDataParser::GetThreadPrimingVerificationDataL(TUint8* aBuffer, |
|
1218 TInt aSize, |
|
1219 TUint32& aThreadAddr, |
|
1220 TUint32& aProcessAddr, |
|
1221 RFile* aFile) |
|
1222 { |
|
1223 TInt err = KErrNone; |
|
1224 TInt filePos = 0; |
|
1225 TUint8* data = NULL; |
|
1226 TUint8* startOfData = NULL; |
|
1227 TUint8* endOfData = NULL; |
|
1228 RBuf8 fileBuffer; |
|
1229 |
|
1230 if (aFile) |
|
1231 { |
|
1232 // Create file buffer and read first chunk from file |
|
1233 err = CreateFileBuffer(fileBuffer, *aFile); |
|
1234 if (err != KErrNone) |
|
1235 { |
|
1236 return err; |
|
1237 } |
|
1238 fileBuffer.CleanupClosePushL(); |
|
1239 err = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData); |
|
1240 if (err != KErrNone) |
|
1241 { |
|
1242 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
1243 return err; |
|
1244 } |
|
1245 } |
|
1246 else |
|
1247 { |
|
1248 data = aBuffer; |
|
1249 startOfData = data; |
|
1250 endOfData = data + aSize; |
|
1251 } |
|
1252 |
|
1253 TInt headerErr = KErrNone; |
|
1254 RThread currentThread; |
|
1255 TUint32 tempThreadAddr; |
|
1256 TUint32 tempProcessAddr; |
|
1257 TThreadId threadid = 0; |
|
1258 |
|
1259 TTraceHeaderSettings traceHeaderSettings; |
|
1260 |
|
1261 err = KErrGeneral; |
|
1262 |
|
1263 while(data < endOfData) |
|
1264 { |
|
1265 headerErr = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
1266 |
|
1267 if (aFile && headerErr == KErrOverflow) |
|
1268 { |
|
1269 // We don't have all the trace data, so read next chunk from file |
|
1270 headerErr = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData); |
|
1271 if (headerErr == KErrNone) |
|
1272 { |
|
1273 continue; |
|
1274 } |
|
1275 } |
|
1276 if (headerErr != KErrNone) |
|
1277 { |
|
1278 err = headerErr; |
|
1279 break; |
|
1280 } |
|
1281 if ( (traceHeaderSettings.iCategory == BTrace::EThreadIdentification) && (traceHeaderSettings.iSubCategory == BTrace::EThreadId) ) |
|
1282 { |
|
1283 tempThreadAddr = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter)); |
|
1284 tempProcessAddr = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter)); |
|
1285 threadid = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter)); |
|
1286 if (currentThread.Id() == threadid) |
|
1287 { |
|
1288 aThreadAddr = tempThreadAddr; |
|
1289 aProcessAddr = tempProcessAddr; |
|
1290 err = KErrNone; |
|
1291 break; |
|
1292 } |
|
1293 } |
|
1294 else |
|
1295 { |
|
1296 data += traceHeaderSettings.iLengthOfPayload; //go to next trace |
|
1297 } |
|
1298 |
|
1299 if (aFile && data == endOfData) |
|
1300 { |
|
1301 // We might not have all the trace data, so read next chunk from file |
|
1302 headerErr = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData); |
|
1303 if (headerErr != KErrNone) |
|
1304 { |
|
1305 err = headerErr; |
|
1306 break; |
|
1307 } |
|
1308 } |
|
1309 } |
|
1310 |
|
1311 if (aFile) |
|
1312 { |
|
1313 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
1314 } |
|
1315 |
|
1316 return err; |
|
1317 } |
|
1318 |
|
1319 |
|
1320 /* |
|
1321 * Get the data required to verify kernel priming traces for ECodeSegs |
|
1322 * |
|
1323 * @param aBuffer Buffer containing the trace data |
|
1324 * @param aSize Size of the trace buffer |
|
1325 * @param aSegAddr1 Output parameter set to address of first code seg |
|
1326 * @param aSegAddr2 Output parameter set to address of second code seg |
|
1327 * @return Standard Symbian error code |
|
1328 */ |
|
1329 TInt TTraceDataParser::GetCodeSegsVerificationDataL(TUint8* aBuffer, |
|
1330 TInt aSize, |
|
1331 TUint32& aSegAddr1, |
|
1332 TUint32& aSegAddr2, |
|
1333 RFile* aFile) |
|
1334 { |
|
1335 TInt err = KErrNone; |
|
1336 TInt filePos = 0; |
|
1337 TUint8* data = NULL; |
|
1338 TUint8* startOfData = NULL; |
|
1339 TUint8* endOfData = NULL; |
|
1340 RBuf8 fileBuffer; |
|
1341 |
|
1342 if (aFile) |
|
1343 { |
|
1344 // Create file buffer and read first chunk from file |
|
1345 err = CreateFileBuffer(fileBuffer, *aFile); |
|
1346 if (err != KErrNone) |
|
1347 { |
|
1348 return err; |
|
1349 } |
|
1350 fileBuffer.CleanupClosePushL(); |
|
1351 err = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData); |
|
1352 if (err != KErrNone) |
|
1353 { |
|
1354 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
1355 return err; |
|
1356 } |
|
1357 } |
|
1358 else |
|
1359 { |
|
1360 data = aBuffer; |
|
1361 startOfData = data; |
|
1362 endOfData = data + aSize; |
|
1363 } |
|
1364 |
|
1365 TInt headerErr = KErrNone; |
|
1366 TUint32 tempSegAddr; |
|
1367 |
|
1368 TTraceHeaderSettings traceHeaderSettings; |
|
1369 |
|
1370 err = KErrGeneral; |
|
1371 |
|
1372 while(data < endOfData) |
|
1373 { |
|
1374 headerErr = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
1375 |
|
1376 if (aFile && headerErr == KErrOverflow) |
|
1377 { |
|
1378 // We don't have all the trace data, so read next chunk from file |
|
1379 headerErr = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData); |
|
1380 if (headerErr == KErrNone) |
|
1381 { |
|
1382 continue; |
|
1383 } |
|
1384 } |
|
1385 if (headerErr != KErrNone) |
|
1386 { |
|
1387 err = headerErr; |
|
1388 break; |
|
1389 } |
|
1390 if ( (traceHeaderSettings.iCategory == BTrace::ECodeSegs) && (traceHeaderSettings.iSubCategory == BTrace::ECodeSegCreated) ) |
|
1391 { |
|
1392 tempSegAddr = Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter)); |
|
1393 traceHeaderSettings.iLengthOfPayload -= 4; |
|
1394 TPtr8 codeSegName(data,traceHeaderSettings.iLengthOfPayload,traceHeaderSettings.iLengthOfPayload); //should be name of the code seg |
|
1395 codeSegName.Trim(); |
|
1396 if (StringsMatch(KCodeSegsName1(), codeSegName)) |
|
1397 { |
|
1398 aSegAddr1 = tempSegAddr; |
|
1399 } |
|
1400 if (StringsMatch(KCodeSegsName2(), codeSegName)) |
|
1401 { |
|
1402 aSegAddr2 = tempSegAddr; |
|
1403 } |
|
1404 if (aSegAddr1 != 0 && aSegAddr2 != 0) |
|
1405 { |
|
1406 err = KErrNone; |
|
1407 break; |
|
1408 } |
|
1409 } |
|
1410 |
|
1411 data += traceHeaderSettings.iLengthOfPayload; //go to next trace |
|
1412 |
|
1413 if (aFile && data == endOfData) |
|
1414 { |
|
1415 // We might not have all the trace data, so read next chunk from file |
|
1416 headerErr = ReadNextChunkFromFile(fileBuffer, *aFile, filePos, data, startOfData, endOfData); |
|
1417 if (headerErr != KErrNone) |
|
1418 { |
|
1419 err = headerErr; |
|
1420 break; |
|
1421 } |
|
1422 } |
|
1423 } |
|
1424 |
|
1425 if (aFile) |
|
1426 { |
|
1427 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
1428 } |
|
1429 |
|
1430 return err; |
|
1431 } |
|
1432 |
|
1433 /* |
|
1434 * Get the data required to verify kernel priming traces |
|
1435 * |
|
1436 * @param aBuffer Buffer containing the trace data |
|
1437 * @param aSize Size of the trace buffer |
|
1438 * @param aGroupId Group ID of traces |
|
1439 * @param aVerificationData1 Output parameter set to first data required |
|
1440 * @param aVerificationData2 Output parameter set to second data required |
|
1441 * @return Standard Symbian error code |
|
1442 */ |
|
1443 TInt TTraceDataParser::GetPrimingVerificationDataL(TUint8* aBuffer, |
|
1444 TInt aSize, |
|
1445 TGroupId aGroupId, |
|
1446 TUint32& aVerificationData1, |
|
1447 TUint32& aVerificationData2, |
|
1448 RFile* aFile) |
|
1449 { |
|
1450 TInt err = KErrNone; |
|
1451 switch(aGroupId) |
|
1452 { |
|
1453 case BTrace::EThreadIdentification: |
|
1454 err = GetThreadPrimingVerificationDataL(aBuffer, aSize, aVerificationData1, aVerificationData2, aFile); |
|
1455 break; |
|
1456 case BTrace::ECodeSegs: |
|
1457 err = GetCodeSegsVerificationDataL(aBuffer, aSize, aVerificationData1, aVerificationData2, aFile); |
|
1458 break; |
|
1459 default: |
|
1460 break; |
|
1461 } |
|
1462 return err; |
|
1463 } |
|
1464 |
|
1465 /* |
|
1466 * Parse trace data for kernel priming data |
|
1467 * |
|
1468 * Note that this function can only verify priming data if the group ID is EThreadIdentification or EFastMutex, |
|
1469 * otherwise KErrNotSupported is returned if aVerifyData is ETrue |
|
1470 * |
|
1471 * @param aBuffer Buffer containing the trace data |
|
1472 * @param aGroupId Group ID of traces to parse |
|
1473 * @param aNumPrimingTraces Output parameter set to number of priming traces found for given group ID |
|
1474 * @param aNumTraces Output parameter set to total number of traces found for given group ID |
|
1475 * @param aVerifyData Flag indicating if priming data should be verified |
|
1476 * @param aVerificationData1 Optional first data required for verifying priming data |
|
1477 * @param aVerificationData1 Optional second data required for verifying priming data |
|
1478 * @return Standard Symbian error code |
|
1479 */ |
|
1480 EXPORT_C TInt TTraceDataParser::ParsePrimingDataL(TDesC8& aBuffer, |
|
1481 TGroupId aGroupId, |
|
1482 TInt& aNumPrimingTraces, |
|
1483 TInt& aNumTraces, |
|
1484 TBool aVerifyData, |
|
1485 TUint32 aVerificationData1, |
|
1486 TUint32 aVerificationData2) |
|
1487 { |
|
1488 aNumPrimingTraces = 0; |
|
1489 aNumTraces = 0; |
|
1490 |
|
1491 TUint8* data = (TUint8*) aBuffer.Ptr(); |
|
1492 TUint8* endOfData = data + aBuffer.Size(); |
|
1493 |
|
1494 // If the output data is to be verified but no verification data provided, try getting it automatically |
|
1495 if (aVerifyData && aVerificationData1 == 0 && aVerificationData2 == 0) |
|
1496 { |
|
1497 TInt err = GetPrimingVerificationDataL(data, endOfData-data, aGroupId, aVerificationData1, aVerificationData2); |
|
1498 if (err != KErrNone) |
|
1499 { |
|
1500 return err; |
|
1501 } |
|
1502 } |
|
1503 |
|
1504 TInt returnErr = KErrNone; |
|
1505 TInt dataVerificationErr = KErrNone; |
|
1506 TInt generalErr = KErrNone; |
|
1507 TBool firstTrace = ETrue; |
|
1508 TBool startOfBatch = ETrue; |
|
1509 TBool inPrimingData = EFalse; |
|
1510 TBool useMetaTraces = EFalse; |
|
1511 TInt numPotentialPrimingTraces = 0; |
|
1512 TUint32 lastTimestamp = 0; |
|
1513 TInt elementsFound = 0; |
|
1514 |
|
1515 TTraceHeaderSettings traceHeaderSettings; |
|
1516 |
|
1517 // Loop through all traces |
|
1518 while (data < endOfData) |
|
1519 { |
|
1520 // Get trace info from header |
|
1521 generalErr = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
1522 |
|
1523 if (generalErr != KErrNone) |
|
1524 { |
|
1525 if (returnErr == KErrNone) |
|
1526 { |
|
1527 // Set error to return, if this is first error so far |
|
1528 returnErr = generalErr; |
|
1529 } |
|
1530 break; |
|
1531 } |
|
1532 |
|
1533 // If this is a meta trace, work out if it signifies start of kernel priming data for GID of interest |
|
1534 if (traceHeaderSettings.iCategory == BTrace::EMetaTrace) |
|
1535 { |
|
1536 useMetaTraces = ETrue; |
|
1537 startOfBatch = IsStartOfKernelPrimingBatch(data, aGroupId, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory); |
|
1538 } |
|
1539 |
|
1540 // This is a trace of the correct GID/CID |
|
1541 if ( (traceHeaderSettings.iComponentID == KKernelHooksOSTComponentUID) && (traceHeaderSettings.iCategory == aGroupId) ) |
|
1542 { |
|
1543 // Increase the number of traces for this GID |
|
1544 aNumTraces++; |
|
1545 |
|
1546 if (useMetaTraces) |
|
1547 { |
|
1548 // If data contains meta traces, work out if this is a priming trace |
|
1549 if (startOfBatch) |
|
1550 { |
|
1551 // This is the start of a batch of priming traces |
|
1552 inPrimingData = ETrue; |
|
1553 startOfBatch = EFalse; |
|
1554 } |
|
1555 if (inPrimingData) |
|
1556 { |
|
1557 // This is a priming trace, so increase number found for this GID |
|
1558 aNumPrimingTraces++; |
|
1559 // If data is to be verified, attempt the verification |
|
1560 if (aVerifyData) |
|
1561 { |
|
1562 dataVerificationErr = VerifyPrimingData(data, traceHeaderSettings.iLengthOfPayload, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, elementsFound, traceHeaderSettings.iFromTestWriter, aVerificationData1, aVerificationData2); |
|
1563 } |
|
1564 } |
|
1565 } |
|
1566 else |
|
1567 { |
|
1568 // If data contains no meta traces, work out if this is a priming trace using heuristics |
|
1569 generalErr = IsInPrimingBatch(traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, traceHeaderSettings.iTimestamp-lastTimestamp, inPrimingData, firstTrace, startOfBatch); |
|
1570 if ( (generalErr != KErrNone) && (returnErr == KErrNone) ) |
|
1571 { |
|
1572 // Set error to return, if this is first error so far |
|
1573 returnErr = generalErr; |
|
1574 } |
|
1575 lastTimestamp = traceHeaderSettings.iTimestamp; |
|
1576 if (inPrimingData) |
|
1577 { |
|
1578 // This is possibly a priming trace, so increase potential number found for this GID |
|
1579 numPotentialPrimingTraces++; |
|
1580 // If data is to be verified, attempt the verification |
|
1581 if (aVerifyData) |
|
1582 { |
|
1583 dataVerificationErr = VerifyPrimingData(data, traceHeaderSettings.iLengthOfPayload, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, elementsFound, traceHeaderSettings.iFromTestWriter, aVerificationData1, aVerificationData2); |
|
1584 } |
|
1585 } |
|
1586 else |
|
1587 { |
|
1588 // If we have enough potential priming traces, assume they are priming traces |
|
1589 if (numPotentialPrimingTraces >= KMinimumPrimingTracesInBatch) |
|
1590 { |
|
1591 aNumPrimingTraces += numPotentialPrimingTraces; |
|
1592 } |
|
1593 numPotentialPrimingTraces = 0; |
|
1594 } |
|
1595 } |
|
1596 } |
|
1597 else |
|
1598 { |
|
1599 // This is not a trace of the correct GID/CID |
|
1600 inPrimingData = EFalse; |
|
1601 } |
|
1602 |
|
1603 // Go to the next trace |
|
1604 data+=traceHeaderSettings.iLengthOfPayload; |
|
1605 } |
|
1606 |
|
1607 if (!useMetaTraces) |
|
1608 { |
|
1609 // If we have enough potential priming traces left over, assume they are priming traces |
|
1610 if (numPotentialPrimingTraces >= KMinimumPrimingTracesInBatch) |
|
1611 { |
|
1612 aNumPrimingTraces += numPotentialPrimingTraces; |
|
1613 } |
|
1614 } |
|
1615 |
|
1616 if ( (dataVerificationErr != KErrNone) && (returnErr == KErrNone) ) |
|
1617 { |
|
1618 // Set error to return, if this is first error so far |
|
1619 returnErr = dataVerificationErr; |
|
1620 } |
|
1621 return returnErr; |
|
1622 } |
|
1623 |
|
1624 /* |
|
1625 * Parse trace data for kernel priming data |
|
1626 * |
|
1627 * Note that this function can only verify priming data if the group ID is EThreadIdentification or EFastMutex, |
|
1628 * otherwise KErrNotSupported is returned if aVerifyData is ETrue |
|
1629 * |
|
1630 * @param aFilePath Full path of file containing the trace data |
|
1631 * @param aFs File system object |
|
1632 * @param aGroupId Group ID of traces to parse |
|
1633 * @param aNumPrimingTraces Output parameter set to number of priming traces found for given group ID |
|
1634 * @param aNumTraces Output parameter set to total number of traces found for given group ID |
|
1635 * @param aVerifyData Flag indicating if priming data should be verified |
|
1636 * @param aVerificationData1 Optional first data required for verifying priming data |
|
1637 * @param aVerificationData1 Optional second data required for verifying priming data |
|
1638 * @return Standard Symbian error code |
|
1639 */ |
|
1640 EXPORT_C TInt TTraceDataParser::ParsePrimingDataL(const TDesC& aFilePath, |
|
1641 RFs& aFs, |
|
1642 TGroupId aGroupId, |
|
1643 TInt& aNumPrimingTraces, |
|
1644 TInt& aNumTraces, |
|
1645 TBool aVerifyData, |
|
1646 TUint32 aVerificationData1, |
|
1647 TUint32 aVerificationData2) |
|
1648 { |
|
1649 aNumPrimingTraces = 0; |
|
1650 aNumTraces = 0; |
|
1651 |
|
1652 RFile file; |
|
1653 |
|
1654 // Open file with trace data |
|
1655 TInt err = file.Open(aFs, aFilePath, EFileRead|EFileShareAny); |
|
1656 if (err != KErrNone) |
|
1657 { |
|
1658 return err; |
|
1659 } |
|
1660 CleanupClosePushL(file); |
|
1661 |
|
1662 // If the output data is to be verified but no verification data provided, try getting it automatically |
|
1663 if (aVerifyData && aVerificationData1 == 0 && aVerificationData2 == 0) |
|
1664 { |
|
1665 err = GetPrimingVerificationDataL(NULL, 0, aGroupId, aVerificationData1, aVerificationData2, &file); |
|
1666 if (err != KErrNone) |
|
1667 { |
|
1668 CleanupStack::PopAndDestroy(&file); // close file |
|
1669 return err; |
|
1670 } |
|
1671 } |
|
1672 |
|
1673 RBuf8 fileBuffer; |
|
1674 TInt filePos = 0; |
|
1675 |
|
1676 // Create file buffer and read first chunk from file |
|
1677 err = CreateFileBuffer(fileBuffer, file); |
|
1678 if (err != KErrNone) |
|
1679 { |
|
1680 CleanupStack::PopAndDestroy(&file); // close file |
|
1681 return err; |
|
1682 } |
|
1683 fileBuffer.CleanupClosePushL(); |
|
1684 |
|
1685 TUint8* data = NULL; |
|
1686 TUint8* startOfData = NULL; |
|
1687 TUint8* endOfData = NULL; |
|
1688 |
|
1689 err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData); |
|
1690 if (err != KErrNone) |
|
1691 { |
|
1692 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
1693 CleanupStack::PopAndDestroy(&file); // close file |
|
1694 return err; |
|
1695 } |
|
1696 |
|
1697 TInt dataVerificationErr = KErrNone; |
|
1698 TInt generalErr = KErrNone; |
|
1699 TBool firstTrace = ETrue; |
|
1700 TBool startOfBatch = ETrue; |
|
1701 TBool inPrimingData = EFalse; |
|
1702 TBool useMetaTraces = EFalse; |
|
1703 TInt numPotentialPrimingTraces = 0; |
|
1704 TUint32 lastTimestamp = 0; |
|
1705 TInt elementsFound = 0; |
|
1706 |
|
1707 TTraceHeaderSettings traceHeaderSettings; |
|
1708 |
|
1709 // Loop through all traces |
|
1710 while (data < endOfData) |
|
1711 { |
|
1712 // Get trace info from header |
|
1713 generalErr = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
1714 |
|
1715 if (generalErr == KErrOverflow) |
|
1716 { |
|
1717 // We don't have all the trace data, so read next chunk from file |
|
1718 generalErr = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData); |
|
1719 if (generalErr == KErrNone) |
|
1720 { |
|
1721 continue; |
|
1722 } |
|
1723 } |
|
1724 if (generalErr != KErrNone) |
|
1725 { |
|
1726 if (err == KErrNone) |
|
1727 { |
|
1728 // Set error to return, if this is first error so far |
|
1729 err = generalErr; |
|
1730 } |
|
1731 break; |
|
1732 } |
|
1733 |
|
1734 // If this is a meta trace, work out if it signifies start of kernel priming data for GID of interest |
|
1735 if (traceHeaderSettings.iCategory == BTrace::EMetaTrace) |
|
1736 { |
|
1737 useMetaTraces = ETrue; |
|
1738 startOfBatch = IsStartOfKernelPrimingBatch(data, aGroupId, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory); |
|
1739 } |
|
1740 |
|
1741 // This is a trace of the correct GID/CID |
|
1742 if ( (traceHeaderSettings.iComponentID == KKernelHooksOSTComponentUID) && (traceHeaderSettings.iCategory == aGroupId) ) |
|
1743 { |
|
1744 // Increase the number of traces for this GID |
|
1745 aNumTraces++; |
|
1746 |
|
1747 if (useMetaTraces) |
|
1748 { |
|
1749 // If data contains meta traces, work out if this is a priming trace |
|
1750 if (startOfBatch) |
|
1751 { |
|
1752 // This is the start of a batch of priming traces |
|
1753 inPrimingData = ETrue; |
|
1754 startOfBatch = EFalse; |
|
1755 } |
|
1756 if (inPrimingData) |
|
1757 { |
|
1758 // This is a priming trace, so increase number found for this GID |
|
1759 aNumPrimingTraces++; |
|
1760 // If data is to be verified, attempt the verification |
|
1761 if (aVerifyData) |
|
1762 { |
|
1763 dataVerificationErr = VerifyPrimingData(data, traceHeaderSettings.iLengthOfPayload, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, elementsFound, traceHeaderSettings.iFromTestWriter, aVerificationData1, aVerificationData2); |
|
1764 } |
|
1765 } |
|
1766 } |
|
1767 else |
|
1768 { |
|
1769 // If data contains no meta traces, work out if this is a priming trace using heuristics |
|
1770 generalErr = IsInPrimingBatch(traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, traceHeaderSettings.iTimestamp-lastTimestamp, inPrimingData, firstTrace, startOfBatch); |
|
1771 if ( (generalErr != KErrNone) && (err == KErrNone) ) |
|
1772 { |
|
1773 // Set error to return, if this is first error so far |
|
1774 err = generalErr; |
|
1775 } |
|
1776 lastTimestamp = traceHeaderSettings.iTimestamp; |
|
1777 if (inPrimingData) |
|
1778 { |
|
1779 // This is possibly a priming trace, so increase potential number found for this GID |
|
1780 numPotentialPrimingTraces++; |
|
1781 // If data is to be verified, attempt the verification |
|
1782 if (aVerifyData) |
|
1783 { |
|
1784 dataVerificationErr = VerifyPrimingData(data, traceHeaderSettings.iLengthOfPayload, traceHeaderSettings.iCategory, traceHeaderSettings.iSubCategory, elementsFound, traceHeaderSettings.iFromTestWriter, aVerificationData1, aVerificationData2); |
|
1785 } |
|
1786 } |
|
1787 else |
|
1788 { |
|
1789 // If we have enough potential priming traces, assume they are priming traces |
|
1790 if (numPotentialPrimingTraces >= KMinimumPrimingTracesInBatch) |
|
1791 { |
|
1792 aNumPrimingTraces += numPotentialPrimingTraces; |
|
1793 } |
|
1794 numPotentialPrimingTraces = 0; |
|
1795 } |
|
1796 } |
|
1797 } |
|
1798 else |
|
1799 { |
|
1800 // This is not a trace of the correct GID/CID |
|
1801 inPrimingData = EFalse; |
|
1802 } |
|
1803 |
|
1804 // Go to the next trace |
|
1805 data+=traceHeaderSettings.iLengthOfPayload; |
|
1806 |
|
1807 if (data == endOfData) |
|
1808 { |
|
1809 // We might not have all the trace data, so read next chunk from file |
|
1810 generalErr = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData); |
|
1811 if (generalErr != KErrNone) |
|
1812 { |
|
1813 if (err == KErrNone) |
|
1814 { |
|
1815 // Set error to return, if this is first error so far |
|
1816 err = generalErr; |
|
1817 } |
|
1818 break; |
|
1819 } |
|
1820 } |
|
1821 } |
|
1822 |
|
1823 if (!useMetaTraces) |
|
1824 { |
|
1825 // If we have enough potential priming traces left over, assume they are priming traces |
|
1826 if (numPotentialPrimingTraces >= KMinimumPrimingTracesInBatch) |
|
1827 { |
|
1828 aNumPrimingTraces += numPotentialPrimingTraces; |
|
1829 } |
|
1830 } |
|
1831 |
|
1832 if ( (dataVerificationErr != KErrNone) && (err == KErrNone) ) |
|
1833 { |
|
1834 // Set error to return, if this is first error so far |
|
1835 err = dataVerificationErr; |
|
1836 } |
|
1837 |
|
1838 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
1839 CleanupStack::PopAndDestroy(&file); // close file |
|
1840 |
|
1841 return err; |
|
1842 } |
|
1843 |
|
1844 TInt TTraceDataParser::CreateFileBuffer(RBuf8& aFileBuffer, |
|
1845 RFile& aFile) |
|
1846 { |
|
1847 TInt fileSize; |
|
1848 TInt err = aFile.Size(fileSize); |
|
1849 if (err == KErrNone) |
|
1850 { |
|
1851 if (fileSize < KFileBufferSize) |
|
1852 { |
|
1853 err = aFileBuffer.Create(fileSize); |
|
1854 } |
|
1855 else |
|
1856 { |
|
1857 err = aFileBuffer.Create(KFileBufferSize); |
|
1858 } |
|
1859 } |
|
1860 return err; |
|
1861 } |
|
1862 |
|
1863 TInt TTraceDataParser::ReadNextChunkFromFile(TDes8& aFileBuffer, |
|
1864 RFile& aFile, |
|
1865 TInt& aFilePosition, |
|
1866 TUint8*& aData, |
|
1867 TUint8*& aStartOfData, |
|
1868 TUint8*& aEndOfData) |
|
1869 { |
|
1870 aFilePosition += aData-aStartOfData; |
|
1871 TInt err = aFile.Read(aFilePosition, aFileBuffer); |
|
1872 if (err == KErrNone) |
|
1873 { |
|
1874 aData = (TUint8*) aFileBuffer.Ptr(); |
|
1875 aStartOfData = aData; |
|
1876 aEndOfData = aData + aFileBuffer.Size(); |
|
1877 } |
|
1878 return err; |
|
1879 } |
|
1880 |
|
1881 /* |
|
1882 * Parse trace data for Printf data, returning the number of occurances of a given string |
|
1883 * |
|
1884 * @param aBuffer Buffer containing the trace data |
|
1885 * @param aFindString String to search for |
|
1886 * @param aNumFound Output parameter set to number of occurances of given string |
|
1887 * @return Standard Symbian error code |
|
1888 */ |
|
1889 EXPORT_C TInt TTraceDataParser::DataHasPrintfString(TDesC8& aBuffer, |
|
1890 const TDesC8& aFindString, |
|
1891 TInt& aNumFound) |
|
1892 { |
|
1893 aNumFound = 0; |
|
1894 |
|
1895 TInt err = KErrNone; |
|
1896 TUint8* data = (TUint8*) aBuffer.Ptr(); |
|
1897 TUint8* endOfData = data + aBuffer.Size(); |
|
1898 |
|
1899 TTraceHeaderSettings traceHeaderSettings; |
|
1900 |
|
1901 while(data < endOfData) |
|
1902 { |
|
1903 err = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
1904 |
|
1905 if (err != KErrNone) |
|
1906 { |
|
1907 break; |
|
1908 } |
|
1909 if (traceHeaderSettings.iPrintfTrace) |
|
1910 { |
|
1911 TPtr8 printfString = ReadTracePrintf(data, traceHeaderSettings.iLengthOfPayload); |
|
1912 if (StringsMatch(aFindString, printfString)) |
|
1913 { |
|
1914 aNumFound++; |
|
1915 } |
|
1916 } |
|
1917 data += traceHeaderSettings.iLengthOfPayload; //go to next trace |
|
1918 } |
|
1919 |
|
1920 return err; |
|
1921 } |
|
1922 |
|
1923 /* |
|
1924 * Parse trace data file for Printf data, returning the number of occurances of a given string |
|
1925 * |
|
1926 * @param aFilePath Full path of file containing the trace data |
|
1927 * @param aFs File system object |
|
1928 * @param aFindString String to search for |
|
1929 * @param aNumFound Output parameter set to number of occurances of given string |
|
1930 * @return Standard Symbian error code |
|
1931 */ |
|
1932 EXPORT_C TInt TTraceDataParser::DataHasPrintfStringL(const TDesC& aFilePath, |
|
1933 RFs& aFs, |
|
1934 const TDesC8& aFindString, |
|
1935 TInt& aNumFound) |
|
1936 { |
|
1937 aNumFound = 0; |
|
1938 |
|
1939 RFile file; |
|
1940 |
|
1941 // Open file with trace data |
|
1942 TInt err = file.Open(aFs, aFilePath, EFileRead|EFileShareAny); |
|
1943 if (err != KErrNone) |
|
1944 { |
|
1945 return err; |
|
1946 } |
|
1947 CleanupClosePushL(file); |
|
1948 |
|
1949 RBuf8 fileBuffer; |
|
1950 TInt filePos = 0; |
|
1951 |
|
1952 // Create file buffer and read first chunk from file |
|
1953 err = CreateFileBuffer(fileBuffer, file); |
|
1954 if (err != KErrNone) |
|
1955 { |
|
1956 CleanupStack::PopAndDestroy(&file); // close file |
|
1957 return err; |
|
1958 } |
|
1959 fileBuffer.CleanupClosePushL(); |
|
1960 |
|
1961 TUint8* data = NULL; |
|
1962 TUint8* startOfData = NULL; |
|
1963 TUint8* endOfData = NULL; |
|
1964 |
|
1965 err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData); |
|
1966 if (err != KErrNone) |
|
1967 { |
|
1968 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
1969 CleanupStack::PopAndDestroy(&file); // close file |
|
1970 return err; |
|
1971 } |
|
1972 |
|
1973 TTraceHeaderSettings traceHeaderSettings; |
|
1974 |
|
1975 while(data < endOfData) |
|
1976 { |
|
1977 err = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
1978 |
|
1979 if (err == KErrOverflow) |
|
1980 { |
|
1981 // We don't have all the trace data, so read next chunk from file |
|
1982 err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData); |
|
1983 if (err == KErrNone) |
|
1984 { |
|
1985 continue; |
|
1986 } |
|
1987 } |
|
1988 if (err != KErrNone) |
|
1989 { |
|
1990 break; |
|
1991 } |
|
1992 if (traceHeaderSettings.iPrintfTrace) |
|
1993 { |
|
1994 TPtr8 printfString = ReadTracePrintf(data, traceHeaderSettings.iLengthOfPayload); |
|
1995 if (StringsMatch(aFindString, printfString)) |
|
1996 { |
|
1997 aNumFound++; |
|
1998 } |
|
1999 } |
|
2000 data += traceHeaderSettings.iLengthOfPayload; //go to next trace |
|
2001 |
|
2002 if (data == endOfData) |
|
2003 { |
|
2004 // We might not have all the trace data, so read next chunk from file |
|
2005 err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData); |
|
2006 if (err != KErrNone) |
|
2007 { |
|
2008 break; |
|
2009 } |
|
2010 } |
|
2011 } |
|
2012 |
|
2013 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
2014 CleanupStack::PopAndDestroy(&file); // close file |
|
2015 |
|
2016 return err; |
|
2017 } |
|
2018 |
|
2019 /* |
|
2020 * Parse trace data file for a sequence of traces |
|
2021 * |
|
2022 * @param aFilePath Full path of file containing the trace data |
|
2023 * @param aFs File system object |
|
2024 * @param aLastNumberFound Output parameter set to number in last occurances of given string |
|
2025 * @param aNumDroppedTraces Output parameter set to number of dropped traces |
|
2026 * @param aFindPrintfPattern Pattern that indicates where in the printf string the number will be, using an asterisk |
|
2027 * This is only used if aGroupId = BTrace::ERDebugPrintf |
|
2028 * @param aGroupId Group ID of traces to parse |
|
2029 * @param aComponentID Component ID of traces to parse |
|
2030 * @return Standard Symbian error code |
|
2031 */ |
|
2032 EXPORT_C TInt TTraceDataParser::DataHasTraceSequenceL(const TDesC& aFilePath, |
|
2033 RFs& aFs, |
|
2034 TInt& aLastNumberFound, |
|
2035 TInt& aNumDroppedTraces, |
|
2036 TDesC8* aFindPrintfPattern, |
|
2037 TGroupId aGroupId, |
|
2038 TComponentId aComponentID) |
|
2039 { |
|
2040 aLastNumberFound = 0; |
|
2041 aNumDroppedTraces = 0; |
|
2042 |
|
2043 RFile file; |
|
2044 |
|
2045 // Open file with trace data |
|
2046 TInt err = file.Open(aFs, aFilePath, EFileRead|EFileShareAny); |
|
2047 if (err != KErrNone) |
|
2048 { |
|
2049 return err; |
|
2050 } |
|
2051 CleanupClosePushL(file); |
|
2052 |
|
2053 RBuf8 fileBuffer; |
|
2054 TInt filePos = 0; |
|
2055 |
|
2056 // Create file buffer and read first chunk from file |
|
2057 err = CreateFileBuffer(fileBuffer, file); |
|
2058 if (err != KErrNone) |
|
2059 { |
|
2060 CleanupStack::PopAndDestroy(&file); // close file |
|
2061 return err; |
|
2062 } |
|
2063 fileBuffer.CleanupClosePushL(); |
|
2064 |
|
2065 TUint8* data = NULL; |
|
2066 TUint8* startOfData = NULL; |
|
2067 TUint8* endOfData = NULL; |
|
2068 |
|
2069 err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData); |
|
2070 if (err != KErrNone) |
|
2071 { |
|
2072 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
2073 CleanupStack::PopAndDestroy(&file); // close file |
|
2074 return err; |
|
2075 } |
|
2076 |
|
2077 TInt currentNumber = 0; |
|
2078 TInt expectedNumber = 1; |
|
2079 TBool gotNumberFromTrace = EFalse; |
|
2080 TBool isDroppedTrace = EFalse; |
|
2081 |
|
2082 TTraceHeaderSettings traceHeaderSettings; |
|
2083 |
|
2084 while(data < endOfData) |
|
2085 { |
|
2086 err = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
2087 |
|
2088 if (err == KErrOverflow) |
|
2089 { |
|
2090 // We don't have all the trace data, so read next chunk from file |
|
2091 err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData); |
|
2092 if (err == KErrNone) |
|
2093 { |
|
2094 continue; |
|
2095 } |
|
2096 } |
|
2097 if (err != KErrNone) |
|
2098 { |
|
2099 break; |
|
2100 } |
|
2101 |
|
2102 gotNumberFromTrace = EFalse; |
|
2103 |
|
2104 if (traceHeaderSettings.iPrintfTrace && aGroupId == BTrace::ERDebugPrintf) |
|
2105 { |
|
2106 TPtr8 printfString = ReadTracePrintf(data, traceHeaderSettings.iLengthOfPayload); |
|
2107 // See if this is a printf that matches given string |
|
2108 if (!aFindPrintfPattern) |
|
2109 { |
|
2110 err = KErrArgument; |
|
2111 break; |
|
2112 } |
|
2113 else if (printfString.Match(*aFindPrintfPattern) != KErrNotFound) |
|
2114 { |
|
2115 // Get the line number from the string |
|
2116 err = ParseStringForNumber(printfString, *aFindPrintfPattern, currentNumber); |
|
2117 if (err != KErrNone) |
|
2118 { |
|
2119 // Could not extract number from printf, so stop and fail |
|
2120 break; |
|
2121 } |
|
2122 gotNumberFromTrace = ETrue; |
|
2123 } |
|
2124 // See if this is a dropped trace |
|
2125 else if (printfString.Compare(KDroppedTrace()) == 0) |
|
2126 { |
|
2127 // If we get 2 dropped trace notifications in a row, return an error |
|
2128 if (isDroppedTrace) |
|
2129 { |
|
2130 err = KErrGeneral; |
|
2131 break; |
|
2132 } |
|
2133 isDroppedTrace = ETrue; |
|
2134 } |
|
2135 else |
|
2136 { |
|
2137 isDroppedTrace = EFalse; |
|
2138 } |
|
2139 } |
|
2140 else if (!traceHeaderSettings.iPrintfTrace && traceHeaderSettings.iCategory == aGroupId && traceHeaderSettings.iComponentID == aComponentID) |
|
2141 { |
|
2142 // check dropped trace flag |
|
2143 if (traceHeaderSettings.iHeaderFlags & BTrace::EMissingRecord) |
|
2144 { |
|
2145 // If we get 2 dropped trace notifications in a row, return an error |
|
2146 if (isDroppedTrace) |
|
2147 { |
|
2148 err = KErrGeneral; |
|
2149 break; |
|
2150 } |
|
2151 isDroppedTrace = ETrue; |
|
2152 } |
|
2153 else |
|
2154 { |
|
2155 isDroppedTrace = EFalse; |
|
2156 } |
|
2157 |
|
2158 if (traceHeaderSettings.iLengthOfPayload >= 4) |
|
2159 { |
|
2160 currentNumber = (TInt) Swap(ReadUint32FromBuf(data, traceHeaderSettings.iFromTestWriter)); |
|
2161 traceHeaderSettings.iLengthOfPayload -= 4; |
|
2162 gotNumberFromTrace = ETrue; |
|
2163 } |
|
2164 else |
|
2165 { |
|
2166 // Could not get number from trace, so stop and fail |
|
2167 err = KErrGeneral; |
|
2168 break; |
|
2169 } |
|
2170 } |
|
2171 |
|
2172 if (gotNumberFromTrace) |
|
2173 { |
|
2174 if (currentNumber < expectedNumber) |
|
2175 { |
|
2176 // Start of a new sequence, so stop |
|
2177 break; |
|
2178 } |
|
2179 aLastNumberFound = currentNumber; |
|
2180 if (aLastNumberFound != expectedNumber && !isDroppedTrace) |
|
2181 { |
|
2182 // A printf has been missed out with no notification, so stop and fail |
|
2183 err = KErrGeneral; |
|
2184 break; |
|
2185 } |
|
2186 else if (aLastNumberFound == expectedNumber && isDroppedTrace) |
|
2187 { |
|
2188 // A printf hasn't been missed out despite notification, so stop and fail |
|
2189 err = KErrGeneral; |
|
2190 break; |
|
2191 } |
|
2192 |
|
2193 aNumDroppedTraces += (aLastNumberFound - expectedNumber); |
|
2194 expectedNumber = aLastNumberFound + 1; |
|
2195 |
|
2196 if (traceHeaderSettings.iPrintfTrace) |
|
2197 { |
|
2198 isDroppedTrace = EFalse; |
|
2199 } |
|
2200 } |
|
2201 |
|
2202 data += traceHeaderSettings.iLengthOfPayload; //go to next trace |
|
2203 |
|
2204 if (data == endOfData) |
|
2205 { |
|
2206 // We might not have all the trace data, so read next chunk from file |
|
2207 err = ReadNextChunkFromFile(fileBuffer, file, filePos, data, startOfData, endOfData); |
|
2208 if (err != KErrNone) |
|
2209 { |
|
2210 break; |
|
2211 } |
|
2212 } |
|
2213 } |
|
2214 |
|
2215 CleanupStack::PopAndDestroy(&fileBuffer); // close file buffer |
|
2216 CleanupStack::PopAndDestroy(&file); // close file |
|
2217 |
|
2218 return err; |
|
2219 } |
|
2220 |
|
2221 /* |
|
2222 * Get Printf string from single trace data |
|
2223 * |
|
2224 * @param aBuffer Buffer containing the trace data |
|
2225 * @param aPrintfString Output parameter set to the print string in the trace data |
|
2226 * @return Standard Symbian error code |
|
2227 */ |
|
2228 EXPORT_C TInt TTraceDataParser::GetPrintfFromTrace(TDesC8& aBuffer, TDes8& aPrintfString) |
|
2229 { |
|
2230 TUint8* data = (TUint8*) aBuffer.Ptr(); |
|
2231 |
|
2232 TTraceHeaderSettings traceHeaderSettings; |
|
2233 |
|
2234 TInt err = ParseHeader(data, aBuffer.Size(), traceHeaderSettings); |
|
2235 |
|
2236 if (err == KErrNone && traceHeaderSettings.iPrintfTrace) |
|
2237 { |
|
2238 aPrintfString.Copy(ReadTracePrintf(data, traceHeaderSettings.iLengthOfPayload)); |
|
2239 } |
|
2240 |
|
2241 return err; |
|
2242 } |
|
2243 |
|
2244 /* |
|
2245 * Parse trace data for multipart data, returning the number of traces found and total size of trace data. |
|
2246 * The data is expected to contain a sequence of integers, starting at 0 |
|
2247 * |
|
2248 * @param aBuffer Buffer containing the trace data |
|
2249 * @param aGroupId Group ID of traces to parse |
|
2250 * @param aComponentID Component ID of traces to parse |
|
2251 * @param aMultipartDataSize Output parameter set to total size of data in multipart trace |
|
2252 * @param aNumMultipartTraces Output parameter set to number of traces that make up multipart trace |
|
2253 * @return Standard Symbian error code |
|
2254 */ |
|
2255 EXPORT_C TInt TTraceDataParser::ValidateMultipartTraces(TDesC8& aBuffer, |
|
2256 TGroupId aGroupID, |
|
2257 TComponentId aComponentID, |
|
2258 TInt& aMultipartDataSize, |
|
2259 TInt& aNumMultipartTraces) |
|
2260 { |
|
2261 aMultipartDataSize = 0; |
|
2262 aNumMultipartTraces = 0; |
|
2263 |
|
2264 TInt err = KErrNone; |
|
2265 TUint8* data = (TUint8*) aBuffer.Ptr(); |
|
2266 TUint8* endOfData = data + aBuffer.Size(); |
|
2267 TUint8 currentNumber = 0; |
|
2268 TUint8 expectedNumber = 0; |
|
2269 TUint32 expectedMultiPartTraceID = 0; |
|
2270 TBool foundStartOfMultipart = EFalse; |
|
2271 TBool foundEndOfMultipart = EFalse; |
|
2272 TBool isMultipartTrace = EFalse; |
|
2273 |
|
2274 TTraceHeaderSettings traceHeaderSettings; |
|
2275 |
|
2276 while(data < endOfData) |
|
2277 { |
|
2278 err = ParseHeader(data, endOfData-data, traceHeaderSettings); |
|
2279 if (err != KErrNone) |
|
2280 { |
|
2281 return err; |
|
2282 } |
|
2283 |
|
2284 // Only look at traces with correct group ID / component ID |
|
2285 if (traceHeaderSettings.iCategory == aGroupID && traceHeaderSettings.iComponentID == aComponentID) |
|
2286 { |
|
2287 isMultipartTrace = EFalse; |
|
2288 if (traceHeaderSettings.iMultiPartType == BTrace::EMultipartFirst || |
|
2289 traceHeaderSettings.iMultiPartType == BTrace::EMultipartMiddle || |
|
2290 traceHeaderSettings.iMultiPartType == BTrace::EMultipartLast) |
|
2291 { |
|
2292 isMultipartTrace = ETrue; |
|
2293 } |
|
2294 |
|
2295 if (!isMultipartTrace) |
|
2296 { |
|
2297 // If not a multipart trace, then this one trace should contain all data |
|
2298 aNumMultipartTraces = 1; |
|
2299 aMultipartDataSize = traceHeaderSettings.iLengthOfPayload; |
|
2300 // If already found some of the data then we shouldn't have this trace |
|
2301 if (foundStartOfMultipart || foundEndOfMultipart) |
|
2302 { |
|
2303 return KErrCorrupt; |
|
2304 } |
|
2305 foundStartOfMultipart = ETrue; |
|
2306 foundEndOfMultipart = ETrue; |
|
2307 |
|
2308 // Validate payload |
|
2309 while (traceHeaderSettings.iLengthOfPayload > 0) |
|
2310 { |
|
2311 currentNumber = (TInt) data[0]; |
|
2312 data++; |
|
2313 // Adjust length of payload remaining |
|
2314 traceHeaderSettings.iLengthOfPayload -= 1; |
|
2315 if (currentNumber != expectedNumber) |
|
2316 { |
|
2317 if (traceHeaderSettings.iLengthOfPayload >= 4 || currentNumber != 0) |
|
2318 { |
|
2319 // Data is 4-byte aligned, so it's ok to have up to 3 zeros at the end of payload |
|
2320 return KErrCorrupt; |
|
2321 } |
|
2322 // This byte is zero padding, so not part of data |
|
2323 aMultipartDataSize--; |
|
2324 } |
|
2325 expectedNumber++; |
|
2326 } |
|
2327 } |
|
2328 // Only look at multipart traces with correct multipart trace ID |
|
2329 else if (traceHeaderSettings.iMultiPartTraceID == expectedMultiPartTraceID || expectedMultiPartTraceID == 0) |
|
2330 { |
|
2331 aNumMultipartTraces++; |
|
2332 |
|
2333 // If already found all data then we shouldn't get another trace with this ID |
|
2334 if (foundEndOfMultipart) |
|
2335 { |
|
2336 return KErrCorrupt; |
|
2337 } |
|
2338 |
|
2339 // Trace is start of multipart |
|
2340 if (traceHeaderSettings.iMultiPartType == BTrace::EMultipartFirst) |
|
2341 { |
|
2342 // If already found start of data then we shouldn't get this part |
|
2343 if (foundStartOfMultipart) |
|
2344 { |
|
2345 return KErrCorrupt; |
|
2346 } |
|
2347 foundStartOfMultipart = ETrue; |
|
2348 aMultipartDataSize = 0; |
|
2349 |
|
2350 // Set the expected multipart trace ID |
|
2351 expectedMultiPartTraceID = traceHeaderSettings.iMultiPartTraceID; |
|
2352 } |
|
2353 else if (traceHeaderSettings.iMultiPartType == BTrace::EMultipartMiddle || |
|
2354 traceHeaderSettings.iMultiPartType == BTrace::EMultipartLast) |
|
2355 { |
|
2356 // If not yet found start of data then we shouldn't get this part |
|
2357 if (!foundStartOfMultipart) |
|
2358 { |
|
2359 return KErrCorrupt; |
|
2360 } |
|
2361 } |
|
2362 |
|
2363 // Add length of payload to size of total data found |
|
2364 aMultipartDataSize += traceHeaderSettings.iLengthOfPayload; |
|
2365 |
|
2366 while (traceHeaderSettings.iLengthOfPayload > 0) |
|
2367 { |
|
2368 // Validate the next part of payload |
|
2369 currentNumber = (TInt) data[0]; |
|
2370 data++; |
|
2371 // Adjust length of payload remaining |
|
2372 traceHeaderSettings.iLengthOfPayload -= 1; |
|
2373 if (currentNumber != expectedNumber) |
|
2374 { |
|
2375 if (traceHeaderSettings.iLengthOfPayload >= 4 || currentNumber != 0) |
|
2376 { |
|
2377 // Data is 4-byte aligned, so it's ok to have up to 3 zeros at the end of payload |
|
2378 return KErrCorrupt; |
|
2379 } |
|
2380 // This byte is zero padding, so not part of data |
|
2381 aMultipartDataSize--; |
|
2382 } |
|
2383 expectedNumber++; |
|
2384 } |
|
2385 |
|
2386 if (traceHeaderSettings.iMultiPartType == BTrace::EMultipartLast) |
|
2387 { |
|
2388 // Found end of trace data |
|
2389 foundEndOfMultipart = ETrue; |
|
2390 } |
|
2391 } |
|
2392 } |
|
2393 |
|
2394 data += traceHeaderSettings.iLengthOfPayload; //go to next trace |
|
2395 } |
|
2396 |
|
2397 if (!foundEndOfMultipart) |
|
2398 { |
|
2399 // Did not find end of trace data, so return KErrNotFound |
|
2400 err = KErrNotFound; |
|
2401 } |
|
2402 return err; |
|
2403 } |