|
1 /* |
|
2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions are met: |
|
7 * |
|
8 * - Redistributions of source code must retain the above copyright notice, |
|
9 * this list of conditions and the following disclaimer. |
|
10 * - Redistributions in binary form must reproduce the above copyright notice, |
|
11 * this list of conditions and the following disclaimer in the documentation |
|
12 * and/or other materials provided with the distribution. |
|
13 * - Neither the name of Nokia Corporation nor the names of its contributors |
|
14 * may be used to endorse or promote products derived from this software |
|
15 * without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
27 * POSSIBILITY OF SUCH DAMAGE. |
|
28 * |
|
29 * Initial Contributors: |
|
30 * Nokia Corporation - initial contribution. |
|
31 * |
|
32 * Contributors: |
|
33 * |
|
34 * Description: |
|
35 * |
|
36 */ |
|
37 |
|
38 #define SUPPORT_OLD_MEMSPY_KERNEL_HEAP_DUMPS |
|
39 |
|
40 using System; |
|
41 using System.Collections.Generic; |
|
42 using System.Text; |
|
43 using System.Text.RegularExpressions; |
|
44 using HeapLib.Reconstructor.Misc; |
|
45 using HeapLib.Reconstructor.DataSources.Analyser.Interpreter; |
|
46 using SymbianUtils; |
|
47 |
|
48 namespace HeapLib.Reconstructor.DataSources.Analyser.Extractor.Implementations |
|
49 { |
|
50 internal sealed class ExtractorText : Extractor |
|
51 { |
|
52 #region Constructors & destructor |
|
53 public ExtractorText() |
|
54 { |
|
55 } |
|
56 #endregion |
|
57 |
|
58 #region API |
|
59 public override bool CanExtractFrom( string aLine ) |
|
60 { |
|
61 // CASE 1: Original file format, logging via trace |
|
62 // |
|
63 // HeapData - EComServer::!ecomserver - HEAP INFO FOR THREAD 'EComServer::!ecomserver' |
|
64 // HeapData - EComServer::!ecomserver - ============================================== |
|
65 // HeapData - EComServer::!ecomserver - HeapInfo - heapBaseAddress: 0x00700074 |
|
66 // HeapData - EComServer::!ecomserver - HeapInfo - heapSize: 745352 |
|
67 // HeapData - EComServer::!ecomserver - HeapInfo - heapChunkSize: 745472 |
|
68 // ... |
|
69 // HeapData - EComServer::!ecomserver - 00700084: 00 00 00 00 03 03 03 03 03 03 03 03 03 03 03 03 ................ |
|
70 // HeapData - EComServer::!ecomserver - 00700094: 03 03 03 03 03 03 03 03 28 00 00 00 ec 47 28 80 ........(....G(. |
|
71 // HeapData - EComServer::!ecomserver - 007000a4: d8 0c 70 00 58 0d 70 00 f8 0c 70 00 03 03 03 03 ..p.X.p...p..... |
|
72 // HeapData - EComServer::!ecomserver - 007000b4: 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 ................ |
|
73 // HeapData - EComServer::!ecomserver - 007000c4: 48 00 00 00 e8 2b 30 80 00 2c 30 80 ec 02 70 00 H....+0..,0...p. |
|
74 // |
|
75 // CASE 2: Original file format, logging to file |
|
76 // |
|
77 // HEAP INFO FOR THREAD 'ecomserver::!ecomserver' |
|
78 // ============================================== |
|
79 // HeapInfo - heapBaseAddress: 0x0f8c0074 |
|
80 // HeapInfo - heapSize: 262028 |
|
81 // |
|
82 // CASE 3: Original file format, logging to file - kernel - the thread name is omitted! |
|
83 // |
|
84 // HeapInfo - heapBaseAddress: 0xc809b074 |
|
85 // HeapInfo - heapSize: 3374984 |
|
86 // HeapInfo - heapMinSize: 720892 |
|
87 // HeapInfo - heapMaxSize: 17408000 |
|
88 // HeapInfo - heapFreeCellAddress: 0xc809b04c |
|
89 // HeapInfo - heapFreeCellLength: 0 |
|
90 // HeapInfo - heapMinCellSize: 40 |
|
91 // HeapInfo - heapUsingDebugAlloc: 0 |
|
92 // HeapInfo - chunkName: ekern.exe[100041af]0001::SvHeap |
|
93 // HeapInfo - heapCellAllocCount: 15216 |
|
94 // HeapInfo - heapAllocSpace: 3171512 |
|
95 // |
|
96 // CASE 4: New file format, still text, logging via trace |
|
97 // |
|
98 // HeapData - ApsExe::AppArcServerThread - HEAP INFO FOR THREAD 'APSEXE::APPARCSERVERTHREAD' |
|
99 // HeapData - ApsExe::AppArcServerThread - ================================================= |
|
100 // HeapData - ApsExe::AppArcServerThread - |
|
101 // HeapData - ApsExe::AppArcServerThread - Meta Data |
|
102 // HeapData - ApsExe::AppArcServerThread - ========= |
|
103 // HeapData - ApsExe::AppArcServerThread - Type: Symbian OS RHeap |
|
104 // HeapData - ApsExe::AppArcServerThread - Chunk Name: ApsExe.exe[10003a3f]0001::AppArcServerThread::$HEAP |
|
105 // HeapData - ApsExe::AppArcServerThread - Chunk Size: 319488 |
|
106 // HeapData - ApsExe::AppArcServerThread - Chunk Base Address: 0x00600000 |
|
107 // HeapData - ApsExe::AppArcServerThread - Debug Allocator: 0 |
|
108 // |
|
109 |
|
110 // First step is to identify the prefix. We do this by looking for the common line which remains |
|
111 // unchanged in all text file formats, and that is the "HEAP INFO FOR THREAD" item. |
|
112 // |
|
113 // If the data included tracing prefixes (e.g. Musti), these will already have been removed. |
|
114 bool ret = false; |
|
115 |
|
116 string line = aLine; |
|
117 |
|
118 #if SUPPORT_OLD_MEMSPY_KERNEL_HEAP_DUMPS |
|
119 if ( line.Contains( "HeapInfo - heapBaseAddress: 0xc" ) ) |
|
120 { |
|
121 // This is a work around for a problem with an old version of MemSpy in which |
|
122 // the kernel thread name was not included in the heap data listing. This |
|
123 // results in Heap Analyser discarding the thread entirely. |
|
124 // |
|
125 // Spoof the line |
|
126 int startPos = line.IndexOf( "HeapInfo - heapBaseAddress: 0xc" ); |
|
127 line = line.Substring( 0, startPos ) + "HEAP INFO FOR THREAD \'ekern.exe[100041af]0001::Supervisor\' "; |
|
128 } |
|
129 #endif |
|
130 |
|
131 Match heapInfoForThreadMatch = KHeapInfoInitialRegEx.Match( line ); |
|
132 if ( heapInfoForThreadMatch.Success ) |
|
133 { |
|
134 // Work out if there is a prefix prior to the HEAP INFO element... |
|
135 int pos = heapInfoForThreadMatch.Index; |
|
136 if ( pos == 0 ) |
|
137 { |
|
138 // There's no prefix |
|
139 } |
|
140 else |
|
141 { |
|
142 // There is some kind of standard prefix |
|
143 iPrefix = line.Substring( 0, pos ); |
|
144 |
|
145 // Check if there is the "HeapData -" prefix also. If there is we may need to strip off a musti timestamp: |
|
146 // |
|
147 // E.g.: |
|
148 // 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). |
|
149 // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600a84: 00 00 00 00 d8 11 00 00 03 03 03 03 03 03 03 03 ................ |
|
150 // 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... |
|
151 // 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.......... |
|
152 // 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,. |
|
153 // 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`. |
|
154 // 10:54:29.672 HeapData - !MsvServer::!MsvServer - 00600ad4: 28 00 00 00 a4 1f 60 00 14 00 bf 00 c1 00 cb 00 (.....`......... |
|
155 // 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...`..... |
|
156 // 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. |
|
157 if ( iPrefix.Contains( KHeapDataPrefix ) ) |
|
158 { |
|
159 int pos2 = iPrefix.IndexOf( KHeapDataPrefix ); |
|
160 iPrefix = iPrefix.Substring( pos2 ); |
|
161 } |
|
162 } |
|
163 |
|
164 // Either way, we need the thread name as we use this |
|
165 // as the identifier for the data source, i.e. the hash |
|
166 iThreadName = heapInfoForThreadMatch.Groups[ "ThreadName" ].Value; |
|
167 |
|
168 // Save data after the prefix |
|
169 base.PrimaryLine = line.Substring( heapInfoForThreadMatch.Index ); |
|
170 |
|
171 ret = true; |
|
172 } |
|
173 |
|
174 return ret; |
|
175 } |
|
176 |
|
177 public override bool ExtractFrom( string aLine, bool aForceExtractionOfThreadIdentifier ) |
|
178 { |
|
179 // First pass identification stage |
|
180 string line = aLine; |
|
181 bool handled = ( iPrefix.Length == 0 ); |
|
182 if ( !handled ) |
|
183 { |
|
184 // Check for prefix match |
|
185 handled = aLine.Contains( iPrefix ); |
|
186 if ( handled ) |
|
187 { |
|
188 // Check that it's not the start of a new data set |
|
189 if ( !aForceExtractionOfThreadIdentifier && aLine.Contains( KHeapDataDataSetStartMarker ) ) // "HEAP INFO FOR THREAD" |
|
190 { |
|
191 handled = false; |
|
192 } |
|
193 else |
|
194 { |
|
195 int pos = aLine.IndexOf( iPrefix ); |
|
196 line = aLine.Substring( pos + iPrefix.Length ); |
|
197 } |
|
198 } |
|
199 } |
|
200 |
|
201 // Data processing stage |
|
202 if ( handled ) |
|
203 { |
|
204 ExtractedData data = PrepareExtractedData( line, aLine ); |
|
205 base.Interpreter.Interpret( data ); |
|
206 } |
|
207 |
|
208 // Done |
|
209 return handled; |
|
210 } |
|
211 #endregion |
|
212 |
|
213 #region Properties |
|
214 public override string Hash |
|
215 { |
|
216 get { return iThreadName; } |
|
217 } |
|
218 #endregion |
|
219 |
|
220 #region Internal methods |
|
221 private ExtractedData PrepareExtractedData( string aLine, string aOriginalLine ) |
|
222 { |
|
223 ExtractedData ret = null; |
|
224 |
|
225 // We need the heap base address before we are able to start |
|
226 // extracting binary data. |
|
227 DataSource ds = Interpreter.DataSource; |
|
228 Elements.MetaData metaData = ds.MetaData; |
|
229 Elements.Groups.GpHeap heapInfo = metaData.Heap; |
|
230 uint baseAddress = heapInfo.HeapBaseAddress; |
|
231 if ( baseAddress != 0 ) |
|
232 { |
|
233 // We can now work out the next expected address |
|
234 uint nextExpectedAddress = baseAddress + (uint) metaData.HeapData.Count; |
|
235 |
|
236 // Build our regex string that will match the binary heap data. |
|
237 string prefix = string.Format( "{0:x8}: ", nextExpectedAddress ); |
|
238 int pos = aLine.IndexOf( prefix ); |
|
239 if ( pos >= 0 ) |
|
240 { |
|
241 Match m = KHeapDataRegEx.Match( aLine ); |
|
242 if ( m.Success ) |
|
243 { |
|
244 List<byte> bytes = new List<byte>(); |
|
245 // |
|
246 CaptureCollection data = m.Groups[ "Data" ].Captures; |
|
247 foreach ( Capture dataItem in data ) |
|
248 { |
|
249 string hexValue = dataItem.Value.Trim(); |
|
250 uint byteVal = System.Convert.ToUInt32( hexValue, KBaseHex ); |
|
251 bytes.Add( (byte) byteVal ); |
|
252 } |
|
253 // |
|
254 ret = ExtractedData.NewBinaryData( bytes.ToArray(), aOriginalLine ); |
|
255 } |
|
256 } |
|
257 // |
|
258 if ( ret == null ) |
|
259 { |
|
260 ret = ExtractedData.NewText( aLine, aOriginalLine ); |
|
261 } |
|
262 } |
|
263 else |
|
264 { |
|
265 ret = ExtractedData.NewText( aLine, aOriginalLine ); |
|
266 } |
|
267 // |
|
268 return ret; |
|
269 } |
|
270 #endregion |
|
271 |
|
272 #region Internal constants |
|
273 private const int KBaseHex = 16; |
|
274 private const string KHeapDataPrefix = "HeapData -"; |
|
275 private const string KHeapDataDataSetStartMarker = "HEAP INFO FOR THREAD"; |
|
276 #endregion |
|
277 |
|
278 #region Internal regular expressions |
|
279 private static readonly Regex KHeapInfoInitialRegEx = new Regex( |
|
280 @"HEAP INFO FOR THREAD \'(?<ThreadName>.+)\'", |
|
281 RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase ); |
|
282 private static readonly Regex KHeapDataRegEx = new Regex( |
|
283 @"\x3A" + |
|
284 @"\s{1}" + |
|
285 @"(?<Data>[a-fA-F0-9]{2}\s{1}){1,16}" + |
|
286 @"(?<Padding>\s{1}){0,44}", |
|
287 RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.IgnoreCase ); |
|
288 #endregion |
|
289 |
|
290 #region Data members |
|
291 private string iPrefix = string.Empty; |
|
292 private string iThreadName = string.Empty; |
|
293 #endregion |
|
294 } |
|
295 } |