|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 using System; |
|
19 using System.Collections.Generic; |
|
20 using System.Text; |
|
21 using SymbianUtils.BasicTypes; |
|
22 using SymbianStructuresLib.Arm; |
|
23 using SymbianStructuresLib.Arm.Exceptions; |
|
24 using SymbianETMLib.Common.Types; |
|
25 using SymbianETMLib.Common.Packets; |
|
26 using SymbianETMLib.Common.Utilities; |
|
27 using SymbianETMLib.Common.Exception; |
|
28 |
|
29 namespace SymbianETMLib.Common.State |
|
30 { |
|
31 public class ETMDecodeStatePHeader : ETMDecodeState |
|
32 { |
|
33 #region Constructors |
|
34 public ETMDecodeStatePHeader( ETMStateData aManager ) |
|
35 : base( aManager ) |
|
36 { |
|
37 } |
|
38 |
|
39 static ETMDecodeStatePHeader() |
|
40 { |
|
41 // ARM branch instructions |
|
42 iBranchMask_ARM_BOrBL = new SymMask( "#### 101 # ######## ######## ########" ); |
|
43 iBranchMask_ARM_BLX_BranchToThumb = new SymMask( "1111 101 # ######## ######## ########" ); |
|
44 |
|
45 // THUMB branch instructions |
|
46 iBranchMask_THUMB_B1 = new SymMask( "1101 #### ########" ); |
|
47 iBranchMask_THUMB_B2 = new SymMask( "11100 ###########" ); |
|
48 iBranchMask_THUMB_BLX_Part1 = new SymMask( "11110 ###########" ); // Multi-instruction branch |
|
49 iBranchMask_THUMB_BLX_Part2 = new SymMask( "111#1 ###########" ); // Multi-instruction branch |
|
50 } |
|
51 #endregion |
|
52 |
|
53 #region API |
|
54 public override ETMDecodeState HandleByte( SymByte aByte ) |
|
55 { |
|
56 ETMDecodeState nextState = new ETMDecodeStateSynchronized( base.StateData ); |
|
57 // |
|
58 ETMPcktBase packet = Packets.Factory.ETMPacketFactory.Create( aByte ); |
|
59 if ( packet is ETMPcktPHeaderFormat1 ) |
|
60 { |
|
61 ETMPcktPHeaderFormat1 pHeader1 = (ETMPcktPHeaderFormat1) packet; |
|
62 ProcessFormat1Conditions( pHeader1 ); |
|
63 } |
|
64 else if ( packet is ETMPcktPHeaderFormat2 ) |
|
65 { |
|
66 ETMPcktPHeaderFormat2 pHeader2 = (ETMPcktPHeaderFormat2) packet; |
|
67 ProcessFormat2Conditions( pHeader2 ); |
|
68 } |
|
69 else |
|
70 { |
|
71 throw new ETMException( "ERROR: P-HEADER is not supported" ); |
|
72 } |
|
73 // |
|
74 return nextState; |
|
75 } |
|
76 #endregion |
|
77 |
|
78 #region Properties |
|
79 #endregion |
|
80 |
|
81 #region Internal enumerations |
|
82 private enum TMultiPartThumbBranch |
|
83 { |
|
84 ETHUMBBL = 0x3, |
|
85 ETHUMBBLX = 0x1, |
|
86 } |
|
87 #endregion |
|
88 |
|
89 #region Internal methods |
|
90 private void ProcessFormat1Conditions( ETMPcktPHeaderFormat1 aHeader ) |
|
91 { |
|
92 string pass = aHeader.ConditionCountPassed > 0 ? string.Format( "{0} x PASS", aHeader.ConditionCountPassed ) : string.Empty; |
|
93 string fail = aHeader.ConditionCountFailed > 0 ? string.Format( ", {0} x FAIL", aHeader.ConditionCountFailed ) : string.Empty; |
|
94 base.Trace( "{0} - {1} {2}", base.MakeTracePacketPrefix( "P-HEADER(1)" ), pass, fail ); |
|
95 |
|
96 // Get the total number of instructions processed |
|
97 int totalExecutedInstructionCount = aHeader.ConditionCountPassed + aHeader.ConditionCountFailed; |
|
98 |
|
99 // Trace passed instructions |
|
100 for ( int i = 0; i < aHeader.ConditionCountPassed; i++ ) |
|
101 { |
|
102 uint address = base.StateData.CurrentAddress; |
|
103 ETMInstruction instruction = base.StateData.FetchInstruction( address ); |
|
104 // |
|
105 TraceAtom( ETMPcktPHeaderBase.TAtomType.EAtomE_Passed, instruction ); |
|
106 |
|
107 // We will now check the current instruction to see if it's a branch. |
|
108 // If it is, then we don't need to increment the instruction address, because |
|
109 // the explicit branch will set a new PC location. |
|
110 // |
|
111 // Note that in the case of a thumb BLX, i.e. two 16-bit instructions which |
|
112 // interpreted together form a +/-4mb branch address, we also need |
|
113 // to ensure that the |
|
114 bool branched = CheckForBranch( instruction ); |
|
115 if ( !branched ) |
|
116 { |
|
117 base.StateData.IncrementPC(); |
|
118 } |
|
119 } |
|
120 |
|
121 // Trace and failed instructions |
|
122 if ( aHeader.ConditionCountFailed > 0 ) |
|
123 { |
|
124 uint address = base.StateData.CurrentAddress; |
|
125 ETMInstruction instruction = base.StateData.FetchInstruction( address ); |
|
126 // |
|
127 TraceAtom( ETMPcktPHeaderBase.TAtomType.EAtomN_Failed, instruction ); |
|
128 base.StateData.IncrementPC(); |
|
129 } |
|
130 |
|
131 // Spacer - to make the verbose output easier to read... |
|
132 base.Trace( string.Empty ); |
|
133 } |
|
134 |
|
135 private void ProcessFormat2Conditions( ETMPcktPHeaderFormat2 aHeader ) |
|
136 { |
|
137 string atom1TypeName = TraceAtomTypeName( aHeader.Atom1Type ); |
|
138 string atom2TypeName = TraceAtomTypeName( aHeader.Atom2Type ); |
|
139 base.Trace( "{0} - 1 x {1}, 1 x {2}", base.MakeTracePacketPrefix( "P-HEADER(2)" ), atom1TypeName, atom2TypeName ); |
|
140 |
|
141 // First instruction |
|
142 { |
|
143 uint address1 = base.StateData.CurrentAddress; |
|
144 ETMInstruction inst1 = base.StateData.FetchInstruction( address1 ); |
|
145 TraceAtom( aHeader.Atom1Type, inst1 ); |
|
146 if ( aHeader.Atom1Type == ETMPcktPHeaderBase.TAtomType.EAtomE_Passed ) |
|
147 { |
|
148 bool branched = CheckForBranch( inst1 ); |
|
149 if ( !branched ) |
|
150 { |
|
151 base.StateData.IncrementPC(); |
|
152 } |
|
153 } |
|
154 else |
|
155 { |
|
156 base.StateData.IncrementPC(); |
|
157 } |
|
158 } |
|
159 |
|
160 // Second instruction |
|
161 { |
|
162 uint address2 = base.StateData.CurrentAddress; |
|
163 ETMInstruction inst2 = base.StateData.FetchInstruction( address2 ); |
|
164 TraceAtom( aHeader.Atom2Type, inst2 ); |
|
165 if ( aHeader.Atom2Type == ETMPcktPHeaderBase.TAtomType.EAtomE_Passed ) |
|
166 { |
|
167 bool branched = CheckForBranch( inst2 ); |
|
168 if ( !branched ) |
|
169 { |
|
170 base.StateData.IncrementPC(); |
|
171 } |
|
172 } |
|
173 else |
|
174 { |
|
175 base.StateData.IncrementPC(); |
|
176 } |
|
177 } |
|
178 |
|
179 // Spacer - to make the verbose output easier to read... |
|
180 base.Trace( string.Empty ); |
|
181 } |
|
182 |
|
183 private bool HandleTHUMBMultiInstructionBranch( uint aInstruction1, uint aInstruction2 ) |
|
184 { |
|
185 bool branched = false; |
|
186 |
|
187 // THUMB multi branch with link exchange instruction - consumes 32 bits |
|
188 // of the instruction pipeline, i.e. instructions @ aIndex and aIndex+1 both |
|
189 // consumed. |
|
190 // |
|
191 // Check the signature is correct: |
|
192 // |
|
193 // NB: |
|
194 // The first Thumb instruction has H == 10 and supplies the high part of the |
|
195 // branch offset. This instruction sets up for the subroutine call and is |
|
196 // shared between the BL and BLX forms. |
|
197 // |
|
198 // The second Thumb instruction has H == 11 (for BL) or H == 01 (for BLX). It |
|
199 // supplies the low part of the branch offset and causes the subroutine call |
|
200 // to take place. |
|
201 // |
|
202 // 15 14 13 12 11 10 0 |
|
203 // ---------------------------------------------------- |
|
204 // 1 1 1 H <--- offset_11 --> |
|
205 // |
|
206 // mask1 = 11 00000000000 |
|
207 // value1 = 10 00000000000 |
|
208 // 111 11 10111010101 |
|
209 // mask2 = 1 00000000000 |
|
210 // value2 = 1 00000000000 |
|
211 // 111 10 11111111111 |
|
212 bool inst1Valid = ( ( aInstruction1 & 0x1800 ) == 0x1000 ); |
|
213 bool inst2Valid = ( ( aInstruction2 & 0x0800 ) == 0x0800 ); |
|
214 |
|
215 if ( inst1Valid && inst2Valid ) |
|
216 { |
|
217 TArmInstructionSet newInstructionSet = TArmInstructionSet.ETHUMB; |
|
218 TMultiPartThumbBranch branchType = TMultiPartThumbBranch.ETHUMBBL; |
|
219 if ( ( aInstruction2 & 0x1800 ) == 0x0800 ) |
|
220 { |
|
221 branchType = TMultiPartThumbBranch.ETHUMBBLX; |
|
222 newInstructionSet = TArmInstructionSet.EARM; |
|
223 } |
|
224 |
|
225 // We subtract two, because we're already handling the second instruction |
|
226 // and the address is relative to the first. |
|
227 uint address = base.StateData.CurrentAddress - 2; |
|
228 |
|
229 // 111 10 00000000100 |
|
230 // 100000000000000 |
|
231 // |
|
232 int instImmediate1 = SignExtend11BitTo32BitTHUMB( aInstruction1 & 0x7FF, 12 ); |
|
233 address = (uint) ( address + instImmediate1 ); |
|
234 address += 4; |
|
235 |
|
236 // 111 01 11101011010 |
|
237 // 11111111111 (0x7FF) |
|
238 // 11101011010 = 0x75A * 2 = EB4 |
|
239 // |
|
240 // 111 01 11011100010 |
|
241 // 11011100010 = 0X6E2 * 2 = DC4 |
|
242 // |
|
243 // |
|
244 |
|
245 // Second instruction |
|
246 uint instImmediate2 = ( aInstruction2 & 0x7FF ) * 2; |
|
247 address += instImmediate2; |
|
248 |
|
249 // For BLX, the resulting address is forced to be word-aligned by |
|
250 // clearing bit[1]. |
|
251 if ( branchType == TMultiPartThumbBranch.ETHUMBBLX ) |
|
252 { |
|
253 address = address & 0xFFFFFFFD; |
|
254 } |
|
255 |
|
256 base.StateData.SetPC( address, newInstructionSet ); |
|
257 branched = true; |
|
258 } |
|
259 else |
|
260 { |
|
261 // Oops. We ran out of instructions. This shouldn't ever happen |
|
262 // assuming that the P-HEADER's are synched properly. |
|
263 throw new ETMException( "ERROR - synchronisation lost with P-HEADERS - 2nd THUMB BLX instruction missing" ); |
|
264 } |
|
265 |
|
266 return branched; |
|
267 } |
|
268 |
|
269 private bool CheckForBranch( ETMInstruction aInstruction ) |
|
270 { |
|
271 bool branched = false; |
|
272 TArmInstructionSet originalInstructionSet = base.StateData.CurrentInstructionSet; |
|
273 SymAddress originalAddress = new SymAddress( base.StateData.CurrentAddress.Address ); |
|
274 // |
|
275 if ( base.StateData.LastBranch.IsKnown ) |
|
276 { |
|
277 uint address = base.StateData.CurrentAddress; |
|
278 TArmInstructionSet instructionSet = base.StateData.CurrentInstructionSet; |
|
279 // |
|
280 if ( instructionSet == TArmInstructionSet.EARM ) |
|
281 { |
|
282 if ( iBranchMask_ARM_BOrBL.IsMatch( aInstruction ) ) |
|
283 { |
|
284 // 1110 101 0 111111111111111111111101 |
|
285 int offset = SignExtend24BitTo32BitARM( aInstruction & 0x00FFFFFF ); |
|
286 base.StateData.SetPC( (uint) ( address + offset ) ); |
|
287 branched = true; |
|
288 } |
|
289 else if ( iBranchMask_ARM_BLX_BranchToThumb.IsMatch( aInstruction ) ) |
|
290 { |
|
291 // TODO: verify this - no data to test at the moment |
|
292 int offset = SignExtend24BitTo32BitARM( aInstruction & 0x00FFFFFF ); |
|
293 base.StateData.SetPC( (uint) ( address + offset ), TArmInstructionSet.ETHUMB ); |
|
294 branched = true; |
|
295 } |
|
296 } |
|
297 else if ( instructionSet == TArmInstructionSet.ETHUMB ) |
|
298 { |
|
299 if ( iBranchMask_THUMB_B1.IsMatch( aInstruction ) ) |
|
300 { |
|
301 // 15 14 13 12 11 -> 8 7 -> 0 |
|
302 // ----------------------------------------- |
|
303 // 1 1 0 1 cond signed_immed_8 |
|
304 int offset = SignExtend8BitTo32BitTHUMB( aInstruction & 0xFF ); |
|
305 base.StateData.SetPC( (uint) ( address + offset ) ); |
|
306 branched = true; |
|
307 } |
|
308 else if ( iBranchMask_THUMB_B2.IsMatch( aInstruction ) ) |
|
309 { |
|
310 // 15 14 13 12 11 10 -> 0 |
|
311 // ----------------------------------------- |
|
312 // 1 1 0 1 1 signed_immed_11 |
|
313 int offset = SignExtend11BitTo32BitTHUMB( aInstruction & 0x7FF ); |
|
314 base.StateData.SetPC( (uint) ( address + offset ) ); |
|
315 branched = true; |
|
316 } |
|
317 else |
|
318 { |
|
319 ETMInstruction inst1 = base.StateData.LastInstruction; |
|
320 bool inst1Match = iBranchMask_THUMB_BLX_Part1.IsMatch( inst1.AIRawValue ); |
|
321 ETMInstruction inst2 = aInstruction; |
|
322 bool inst2Match = iBranchMask_THUMB_BLX_Part2.IsMatch( inst2.AIRawValue ); |
|
323 // |
|
324 if ( inst1Match && inst2Match ) |
|
325 { |
|
326 branched = HandleTHUMBMultiInstructionBranch( inst1.AIRawValue, inst2.AIRawValue ); |
|
327 System.Diagnostics.Debug.Assert( branched == true ); |
|
328 } |
|
329 } |
|
330 } |
|
331 else |
|
332 { |
|
333 throw new NotSupportedException(); |
|
334 } |
|
335 } |
|
336 if ( branched ) |
|
337 { |
|
338 base.StateData.IncrementProcessedInstructionCounter(); |
|
339 TraceDirectBranch( originalAddress, originalInstructionSet, base.StateData.CurrentAddress, base.StateData.CurrentInstructionSet ); |
|
340 } |
|
341 |
|
342 // Always cache the last processed instruction |
|
343 base.StateData.LastInstruction = aInstruction; |
|
344 return branched; |
|
345 } |
|
346 |
|
347 private void TraceDirectBranch( SymAddress aOriginalAddress, TArmInstructionSet aOriginalISet, SymAddress aNewAddress, TArmInstructionSet aNewISet ) |
|
348 { |
|
349 StringBuilder lines = new StringBuilder(); |
|
350 lines.AppendLine( " BRANCH-D" ); |
|
351 // |
|
352 if ( base.StateData.LastBranch.IsKnown ) |
|
353 { |
|
354 lines.AppendLine( string.Format( " from: {0} 0x{1:x8} {2}", ETMDecodeState.MakeInstructionSetPrefix( aOriginalISet ), aOriginalAddress, StateData.Engine.LookUpSymbol( aOriginalAddress ) ) ); |
|
355 lines.AppendLine( string.Format( " to: {0} 0x{1:x8} {2}", ETMDecodeState.MakeInstructionSetPrefix( aNewISet ), aNewAddress, StateData.Engine.LookUpSymbol( aNewAddress ) ) ); |
|
356 } |
|
357 else |
|
358 { |
|
359 } |
|
360 // |
|
361 base.Trace( lines.ToString() ); |
|
362 } |
|
363 |
|
364 #region Utilities |
|
365 private static string TraceAtomTypeName( ETMPcktPHeaderBase.TAtomType aType ) |
|
366 { |
|
367 switch ( aType ) |
|
368 { |
|
369 default: |
|
370 case ETMPcktPHeaderBase.TAtomType.EAtomNotApplicable: |
|
371 return " "; |
|
372 case ETMPcktPHeaderBase.TAtomType.EAtomE_Passed: |
|
373 return " PASS "; |
|
374 case ETMPcktPHeaderBase.TAtomType.EAtomN_Failed: |
|
375 return "* FAIL *"; |
|
376 case ETMPcktPHeaderBase.TAtomType.EAtomW_CycleBoundary: |
|
377 return " CYBNDR "; |
|
378 } |
|
379 } |
|
380 |
|
381 private void TraceAtom( ETMPcktPHeaderBase.TAtomType aType, ETMInstruction aInstruction ) |
|
382 { |
|
383 string atomTypeName = TraceAtomTypeName( aType ); |
|
384 // |
|
385 StringBuilder text = new StringBuilder(); |
|
386 text.AppendFormat( "{0} 0x{1}: {2} {3}", |
|
387 base.StateData.NumberOfProcessedInstructions.ToString().PadLeft( 6, ' ' ), |
|
388 base.StateData.CurrentAddress.AddressHex, |
|
389 base.StateData.CurrentAddress.AddressBinary, |
|
390 atomTypeName |
|
391 ); |
|
392 // |
|
393 if ( base.StateData.LastBranch.IsKnown ) |
|
394 { |
|
395 string disasm = aInstruction.ToString(); |
|
396 text.Append( " " + disasm ); |
|
397 } |
|
398 // |
|
399 base.Trace( text.ToString() ); |
|
400 } |
|
401 |
|
402 private static int SignExtend24BitTo32BitARM( uint aImmediate ) |
|
403 { |
|
404 int offset; |
|
405 // |
|
406 unchecked |
|
407 { |
|
408 if ( ( aImmediate & 0x00800000 ) == 0x00800000 ) |
|
409 { |
|
410 offset = (int) ( 0xff000000 | aImmediate ); |
|
411 } |
|
412 else |
|
413 { |
|
414 offset = (int) aImmediate; |
|
415 } |
|
416 } |
|
417 // |
|
418 offset <<= 2; |
|
419 offset += 8; // pipeline |
|
420 return offset; |
|
421 } |
|
422 |
|
423 private static int SignExtend11BitTo32BitTHUMB( uint aImmediate ) |
|
424 { |
|
425 int offset = SignExtend11BitTo32BitTHUMB( aImmediate, 1 ); |
|
426 offset += 4; // pipeline |
|
427 return offset; |
|
428 } |
|
429 |
|
430 private static int SignExtend11BitTo32BitTHUMB( uint aImmediate, int aLeftShiftCount ) |
|
431 { |
|
432 int offset; |
|
433 // |
|
434 unchecked |
|
435 { |
|
436 // 10 9 8 7 6 5 4 3 2 1 0 |
|
437 // ---------------------------------- |
|
438 // 1 0 0 0 0 0 0 0 0 0 0 |
|
439 if ( ( aImmediate & 0x00000400 ) == 0x00000400 ) |
|
440 { |
|
441 // 11111111111111111111100000000000 |
|
442 // 10000000000 |
|
443 offset = (int) ( 0xFFFFF800 | aImmediate ); |
|
444 } |
|
445 else |
|
446 { |
|
447 offset = (int) aImmediate; |
|
448 } |
|
449 } |
|
450 // |
|
451 offset <<= aLeftShiftCount; |
|
452 return offset; |
|
453 } |
|
454 |
|
455 private static int SignExtend8BitTo32BitTHUMB( uint aImmediate ) |
|
456 { |
|
457 int offset; |
|
458 // |
|
459 unchecked |
|
460 { |
|
461 // 7 6 5 4 3 2 1 0 |
|
462 // ------------------------ |
|
463 // 1 0 0 0 0 0 0 0 |
|
464 if ( ( aImmediate & 0x00000080 ) == 0x00000080 ) |
|
465 { |
|
466 // 11111111111111111111111100000000 |
|
467 // 10000000 |
|
468 offset = (int) ( 0xFFFFFF00 | aImmediate ); |
|
469 } |
|
470 else |
|
471 { |
|
472 offset = (int) aImmediate; |
|
473 } |
|
474 } |
|
475 // |
|
476 offset <<= 1; |
|
477 offset += 4; // pipeline |
|
478 return offset; |
|
479 } |
|
480 #endregion |
|
481 |
|
482 #endregion |
|
483 |
|
484 #region From System.Object |
|
485 #endregion |
|
486 |
|
487 #region Data members |
|
488 private static readonly SymMask iBranchMask_ARM_BOrBL; |
|
489 private static readonly SymMask iBranchMask_ARM_BLX_BranchToThumb; |
|
490 private static readonly SymMask iBranchMask_THUMB_B1; |
|
491 private static readonly SymMask iBranchMask_THUMB_B2; |
|
492 private static readonly SymMask iBranchMask_THUMB_BLX_Part1; |
|
493 private static readonly SymMask iBranchMask_THUMB_BLX_Part2; |
|
494 #endregion |
|
495 } |
|
496 } |