diff -r 8e12a575a9b5 -r 15296fd0af4a sysperfana/heapanalyser/Libraries/Engine/HeapLib/Reconstructor/DataSources/Analyser/Extractor/Implementations/ExtractorText.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sysperfana/heapanalyser/Libraries/Engine/HeapLib/Reconstructor/DataSources/Analyser/Extractor/Implementations/ExtractorText.cs Tue Jun 15 12:47:20 2010 +0300 @@ -0,0 +1,295 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* - Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* - Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* - Neither the name of Nokia Corporation nor the names of its contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#define SUPPORT_OLD_MEMSPY_KERNEL_HEAP_DUMPS + +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using HeapLib.Reconstructor.Misc; +using HeapLib.Reconstructor.DataSources.Analyser.Interpreter; +using SymbianUtils; + +namespace HeapLib.Reconstructor.DataSources.Analyser.Extractor.Implementations +{ + internal sealed class ExtractorText : Extractor + { + #region Constructors & destructor + public ExtractorText() + { + } + #endregion + + #region API + public override bool CanExtractFrom( string aLine ) + { + // CASE 1: Original file format, logging via trace + // + // HeapData - EComServer::!ecomserver - HEAP INFO FOR THREAD 'EComServer::!ecomserver' + // HeapData - EComServer::!ecomserver - ============================================== + // HeapData - EComServer::!ecomserver - HeapInfo - heapBaseAddress: 0x00700074 + // HeapData - EComServer::!ecomserver - HeapInfo - heapSize: 745352 + // HeapData - EComServer::!ecomserver - HeapInfo - heapChunkSize: 745472 + // ... + // HeapData - EComServer::!ecomserver - 00700084: 00 00 00 00 03 03 03 03 03 03 03 03 03 03 03 03 ................ + // HeapData - EComServer::!ecomserver - 00700094: 03 03 03 03 03 03 03 03 28 00 00 00 ec 47 28 80 ........(....G(. + // HeapData - EComServer::!ecomserver - 007000a4: d8 0c 70 00 58 0d 70 00 f8 0c 70 00 03 03 03 03 ..p.X.p...p..... + // HeapData - EComServer::!ecomserver - 007000b4: 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 ................ + // HeapData - EComServer::!ecomserver - 007000c4: 48 00 00 00 e8 2b 30 80 00 2c 30 80 ec 02 70 00 H....+0..,0...p. + // + // CASE 2: Original file format, logging to file + // + // HEAP INFO FOR THREAD 'ecomserver::!ecomserver' + // ============================================== + // HeapInfo - heapBaseAddress: 0x0f8c0074 + // HeapInfo - heapSize: 262028 + // + // CASE 3: Original file format, logging to file - kernel - the thread name is omitted! + // + // HeapInfo - heapBaseAddress: 0xc809b074 + // HeapInfo - heapSize: 3374984 + // HeapInfo - heapMinSize: 720892 + // HeapInfo - heapMaxSize: 17408000 + // HeapInfo - heapFreeCellAddress: 0xc809b04c + // HeapInfo - heapFreeCellLength: 0 + // HeapInfo - heapMinCellSize: 40 + // HeapInfo - heapUsingDebugAlloc: 0 + // HeapInfo - chunkName: ekern.exe[100041af]0001::SvHeap + // HeapInfo - heapCellAllocCount: 15216 + // HeapInfo - heapAllocSpace: 3171512 + // + // CASE 4: New file format, still text, logging via trace + // + // HeapData - ApsExe::AppArcServerThread - HEAP INFO FOR THREAD 'APSEXE::APPARCSERVERTHREAD' + // HeapData - ApsExe::AppArcServerThread - ================================================= + // HeapData - ApsExe::AppArcServerThread - + // HeapData - ApsExe::AppArcServerThread - Meta Data + // HeapData - ApsExe::AppArcServerThread - ========= + // HeapData - ApsExe::AppArcServerThread - Type: Symbian OS RHeap + // HeapData - ApsExe::AppArcServerThread - Chunk Name: ApsExe.exe[10003a3f]0001::AppArcServerThread::$HEAP + // HeapData - ApsExe::AppArcServerThread - Chunk Size: 319488 + // HeapData - ApsExe::AppArcServerThread - Chunk Base Address: 0x00600000 + // HeapData - ApsExe::AppArcServerThread - Debug Allocator: 0 + // + + // First step is to identify the prefix. We do this by looking for the common line which remains + // unchanged in all text file formats, and that is the "HEAP INFO FOR THREAD" item. + // + // If the data included tracing prefixes (e.g. Musti), these will already have been removed. + bool ret = false; + + string line = aLine; + +#if SUPPORT_OLD_MEMSPY_KERNEL_HEAP_DUMPS + if ( line.Contains( "HeapInfo - heapBaseAddress: 0xc" ) ) + { + // This is a work around for a problem with an old version of MemSpy in which + // the kernel thread name was not included in the heap data listing. This + // results in Heap Analyser discarding the thread entirely. + // + // Spoof the line + int startPos = line.IndexOf( "HeapInfo - heapBaseAddress: 0xc" ); + line = line.Substring( 0, startPos ) + "HEAP INFO FOR THREAD \'ekern.exe[100041af]0001::Supervisor\' "; + } +#endif + + Match heapInfoForThreadMatch = KHeapInfoInitialRegEx.Match( line ); + if ( heapInfoForThreadMatch.Success ) + { + // Work out if there is a prefix prior to the HEAP INFO element... + int pos = heapInfoForThreadMatch.Index; + if ( pos == 0 ) + { + // There's no prefix + } + else + { + // There is some kind of standard prefix + iPrefix = line.Substring( 0, pos ); + + // Check if there is the "HeapData -" prefix also. If there is we may need to strip off a musti timestamp: + // + // E.g.: + // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600a74: 00 00 00 00 20 00 00 00 04 00 00 00 57 4c 29 80 ............WL). + // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600a84: 00 00 00 00 d8 11 00 00 03 03 03 03 03 03 03 03 ................ + // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600a94: 28 00 00 00 64 f9 52 80 00 24 60 00 50 00 00 10 (...d.R..$`.P... + // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600aa4: 69 3c 00 10 d6 72 20 10 00 00 00 00 01 00 00 00 i<...r.......... + // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600ab4: 38 21 60 00 00 00 00 00 40 00 00 00 c4 4c 2c 80 8!`.....@....L,. + // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600ac4: 38 00 00 00 20 00 00 00 40 00 00 00 28 43 60 00 8.......@...(C`. + // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600ad4: 28 00 00 00 a4 1f 60 00 14 00 bf 00 c1 00 cb 00 (.....`......... + // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600ae4: 10 4e 40 00 ad 2f 37 80 a8 1f 60 00 03 03 03 03 .N@../7...`..... + // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600af4: 03 03 03 03 03 03 03 03 98 04 00 00 94 f6 52 80 ..............R. + if ( iPrefix.Contains( KHeapDataPrefix ) ) + { + int pos2 = iPrefix.IndexOf( KHeapDataPrefix ); + iPrefix = iPrefix.Substring( pos2 ); + } + } + + // Either way, we need the thread name as we use this + // as the identifier for the data source, i.e. the hash + iThreadName = heapInfoForThreadMatch.Groups[ "ThreadName" ].Value; + + // Save data after the prefix + base.PrimaryLine = line.Substring( heapInfoForThreadMatch.Index ); + + ret = true; + } + + return ret; + } + + public override bool ExtractFrom( string aLine, bool aForceExtractionOfThreadIdentifier ) + { + // First pass identification stage + string line = aLine; + bool handled = ( iPrefix.Length == 0 ); + if ( !handled ) + { + // Check for prefix match + handled = aLine.Contains( iPrefix ); + if ( handled ) + { + // Check that it's not the start of a new data set + if ( !aForceExtractionOfThreadIdentifier && aLine.Contains( KHeapDataDataSetStartMarker ) ) // "HEAP INFO FOR THREAD" + { + handled = false; + } + else + { + int pos = aLine.IndexOf( iPrefix ); + line = aLine.Substring( pos + iPrefix.Length ); + } + } + } + + // Data processing stage + if ( handled ) + { + ExtractedData data = PrepareExtractedData( line, aLine ); + base.Interpreter.Interpret( data ); + } + + // Done + return handled; + } + #endregion + + #region Properties + public override string Hash + { + get { return iThreadName; } + } + #endregion + + #region Internal methods + private ExtractedData PrepareExtractedData( string aLine, string aOriginalLine ) + { + ExtractedData ret = null; + + // We need the heap base address before we are able to start + // extracting binary data. + DataSource ds = Interpreter.DataSource; + Elements.MetaData metaData = ds.MetaData; + Elements.Groups.GpHeap heapInfo = metaData.Heap; + uint baseAddress = heapInfo.HeapBaseAddress; + if ( baseAddress != 0 ) + { + // We can now work out the next expected address + uint nextExpectedAddress = baseAddress + (uint) metaData.HeapData.Count; + + // Build our regex string that will match the binary heap data. + string prefix = string.Format( "{0:x8}: ", nextExpectedAddress ); + int pos = aLine.IndexOf( prefix ); + if ( pos >= 0 ) + { + Match m = KHeapDataRegEx.Match( aLine ); + if ( m.Success ) + { + List bytes = new List(); + // + CaptureCollection data = m.Groups[ "Data" ].Captures; + foreach ( Capture dataItem in data ) + { + string hexValue = dataItem.Value.Trim(); + uint byteVal = System.Convert.ToUInt32( hexValue, KBaseHex ); + bytes.Add( (byte) byteVal ); + } + // + ret = ExtractedData.NewBinaryData( bytes.ToArray(), aOriginalLine ); + } + } + // + if ( ret == null ) + { + ret = ExtractedData.NewText( aLine, aOriginalLine ); + } + } + else + { + ret = ExtractedData.NewText( aLine, aOriginalLine ); + } + // + return ret; + } + #endregion + + #region Internal constants + private const int KBaseHex = 16; + private const string KHeapDataPrefix = "HeapData -"; + private const string KHeapDataDataSetStartMarker = "HEAP INFO FOR THREAD"; + #endregion + + #region Internal regular expressions + private static readonly Regex KHeapInfoInitialRegEx = new Regex( + @"HEAP INFO FOR THREAD \'(?.+)\'", + RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase ); + private static readonly Regex KHeapDataRegEx = new Regex( + @"\x3A" + + @"\s{1}" + + @"(?[a-fA-F0-9]{2}\s{1}){1,16}" + + @"(?\s{1}){0,44}", + RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase ); + #endregion + + #region Data members + private string iPrefix = string.Empty; + private string iThreadName = string.Empty; + #endregion + } +}