|
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 using System; |
|
18 using System.Collections.Generic; |
|
19 using System.Text; |
|
20 using SymbianUtils.Tracer; |
|
21 using SymbianDebugLib.PluginAPI.Types.Symbol; |
|
22 using SymbianStructuresLib.Debug.Symbols; |
|
23 using SymbianStructuresLib.Arm; |
|
24 using SymbianStructuresLib.Arm.Registers; |
|
25 using SymbianStructuresLib.Arm.Registers; |
|
26 using SymbianStackAlgorithmAccurate.CPU; |
|
27 using SymbianStackAlgorithmAccurate.Code; |
|
28 using SymbianStackAlgorithmAccurate.Engine; |
|
29 using SymbianStackAlgorithmAccurate.Interfaces; |
|
30 using SymbianStackAlgorithmAccurate.Instructions; |
|
31 |
|
32 namespace SymbianStackAlgorithmAccurate.Prologue |
|
33 { |
|
34 internal class ArmPrologueHelper |
|
35 { |
|
36 #region Constructors |
|
37 public ArmPrologueHelper( AccurateEngine aEngine ) |
|
38 { |
|
39 iEngine = aEngine; |
|
40 |
|
41 // Make a new PC register, since we're going to manipulate it... |
|
42 iPC = new ArmRegister( aEngine.CPU.PC ); |
|
43 |
|
44 // Create offsets |
|
45 iOffsetValues.AddDefaults(); |
|
46 iOffsetValues.SetAll( uint.MaxValue ); |
|
47 } |
|
48 #endregion |
|
49 |
|
50 #region API |
|
51 public void Build() |
|
52 { |
|
53 // First, work out how many instructions we need to read from |
|
54 // the code data in order to reach the current PC value. |
|
55 // We currently cap this at 20 instructions. |
|
56 CalculatePrologueInstructionCount(); |
|
57 |
|
58 // Get Prologue instructions |
|
59 GetPrologueInstructions(); |
|
60 |
|
61 // Update iPC with Prologue starting address - needed for PC-relative |
|
62 // instructions |
|
63 PrepareInitialPCValue(); |
|
64 |
|
65 // Process the instructions until exhausted |
|
66 ProcessPrologueInstructions(); |
|
67 } |
|
68 |
|
69 public int IncrementNumberOfWordsPushedOnStack( TArmRegisterType aRegister ) |
|
70 { |
|
71 uint offset = (uint) iNumberOfWordsPushedOnStack * 4; |
|
72 int ret = iNumberOfWordsPushedOnStack++; |
|
73 iEngine.Trace( "[PLG] IncrementNumberOfWordsPushedOnStack - register: {0}, offset: 0x{1:x4}, DWORDs now on stack: {2:d2}", aRegister, offset, NumberOfWordsPushedOnStack ); |
|
74 return ret; |
|
75 } |
|
76 |
|
77 public int AddToNumberOfWordsPushedOnStack( int aExtraWords ) |
|
78 { |
|
79 iNumberOfWordsPushedOnStack += aExtraWords; |
|
80 iEngine.Trace( "[PLG] AddToNumberOfWordsPushedOnStack - DWORDs added: {0}, prior SP adjustment: 0x{1:x8} ({2} x DWORDs), new SP adjustment: 0x{3:x8} ({4} x DWORDs)", |
|
81 aExtraWords, |
|
82 ( iNumberOfWordsPushedOnStack - aExtraWords ) * 4, |
|
83 iNumberOfWordsPushedOnStack - aExtraWords, |
|
84 iNumberOfWordsPushedOnStack * 4, |
|
85 iNumberOfWordsPushedOnStack |
|
86 ); |
|
87 // |
|
88 return iNumberOfWordsPushedOnStack; |
|
89 } |
|
90 #endregion |
|
91 |
|
92 #region Properties |
|
93 public int PrologueInstructionCount |
|
94 { |
|
95 get |
|
96 { |
|
97 int ret = iPrologueInstructionCount; |
|
98 // |
|
99 if ( ret > KMaxPrologueInstructionCount ) |
|
100 { |
|
101 ret = KMaxPrologueInstructionCount; |
|
102 iEngine.Trace( "[PLG] Capping the amount of Prologue instructions to read to: " + ret ); |
|
103 } |
|
104 // |
|
105 return ret; |
|
106 } |
|
107 set |
|
108 { |
|
109 iPrologueInstructionCount = value; |
|
110 } |
|
111 } |
|
112 |
|
113 public string FunctionName |
|
114 { |
|
115 get { return iFunctionName; } |
|
116 } |
|
117 |
|
118 public TArmInstructionSet FunctionInstructionSet |
|
119 { |
|
120 get |
|
121 { |
|
122 TArmInstructionSet ret = TArmInstructionSet.EARM; |
|
123 // |
|
124 if ( ( FunctionStartingAddress & 0x1 ) == 0x1 ) |
|
125 { |
|
126 ret = TArmInstructionSet.ETHUMB; |
|
127 } |
|
128 // |
|
129 return ret; |
|
130 } |
|
131 } |
|
132 |
|
133 public uint FunctionStartingAddress |
|
134 { |
|
135 get { return iFunctionStartAddress; } |
|
136 } |
|
137 |
|
138 public uint FunctionStartingAddressWithoutType |
|
139 { |
|
140 get { return iFunctionStartAddress & KInstructionSetMask; } |
|
141 } |
|
142 |
|
143 public uint FunctionOffsetToPC |
|
144 { |
|
145 get |
|
146 { |
|
147 uint funcAddrWithoutInstructionSetType = FunctionStartingAddressWithoutType; |
|
148 uint offset = iPC - funcAddrWithoutInstructionSetType; |
|
149 return offset; |
|
150 } |
|
151 } |
|
152 |
|
153 public ArmRegister ProloguePC |
|
154 { |
|
155 get { return iPC; } |
|
156 } |
|
157 |
|
158 public int NumberOfWordsPushedOnStack |
|
159 { |
|
160 get { return iNumberOfWordsPushedOnStack; } |
|
161 set { iNumberOfWordsPushedOnStack = value; } |
|
162 } |
|
163 #endregion |
|
164 |
|
165 #region Internal methods |
|
166 private void CalculatePrologueInstructionCount() |
|
167 { |
|
168 DbgViewSymbol symbolView = iEngine.DebugEngineView.Symbols; |
|
169 |
|
170 // Get the PC and try to match it to a function |
|
171 SymbolCollection collection = null; |
|
172 Symbol symbol = symbolView.Lookup( iPC, out collection ); |
|
173 if ( symbol != null ) |
|
174 { |
|
175 iFunctionStartAddress = symbol.Address; |
|
176 iFunctionName = symbol.Name; |
|
177 // |
|
178 uint offset = FunctionOffsetToPC; |
|
179 uint instructionSize = SingleInstructionSize; |
|
180 uint prologueInstructionCount = ( offset / instructionSize ); |
|
181 // |
|
182 iEngine.Trace( "[PLG] Prologue function: 0x{0:x8} = {1} [+{2:x4}], {3} instructions", iPC.Value, iFunctionName, offset, PrologueInstructionCount ); |
|
183 PrologueInstructionCount = (int) prologueInstructionCount; |
|
184 } |
|
185 else |
|
186 { |
|
187 // We could not locate the symbol for the corresponding program counter address. |
|
188 // In this situation, there's nothing we can do - if we cannot work out the offset |
|
189 // within the function, then we cannot identify how many Prologue instructions to |
|
190 // attempt to read. |
|
191 // |
|
192 // If the symbol was not found because no code segment claims ownership of this address |
|
193 // then that might indicate premature dll unload or bad crash data (missing code segments) |
|
194 if ( collection == null ) |
|
195 { |
|
196 throw new APESymbolNotFoundCodeSegmentUnavailable( iPC ); |
|
197 } |
|
198 else |
|
199 { |
|
200 throw new APESymbolNotFound( iPC, string.Format( "Code segment \'{0}\' should describe symbol, but none was found for requested program counter address", collection.FileName ) ); |
|
201 } |
|
202 } |
|
203 } |
|
204 |
|
205 private void GetPrologueInstructions() |
|
206 { |
|
207 TArmInstructionSet instSet = CPU.CurrentProcessorMode; |
|
208 uint address = FunctionStartingAddressWithoutType; |
|
209 |
|
210 // Let's get unadulterated instruction counts |
|
211 int instCount = iPrologueInstructionCount; |
|
212 if ( address > 0 && instCount > 0 ) |
|
213 { |
|
214 iInstructions = CodeHelper.LoadInstructions( address, instCount, instSet ); |
|
215 } |
|
216 else |
|
217 { |
|
218 iInstructions = new AccInstructionList(); |
|
219 } |
|
220 |
|
221 // Verify that we have the expected number of instructions. |
|
222 // If, for some reason, the code provider does not supply |
|
223 // any Prologue instructions, then we should bail out. |
|
224 int actual = iInstructions.Count; |
|
225 if ( actual != instCount ) |
|
226 { |
|
227 throw new Exception( string.Format( "Prologue instructions unavailable or insufficient @ address: 0x{0:x8} - expected: {1}, received: {2}", FunctionStartingAddressWithoutType, instCount, actual ) ); |
|
228 } |
|
229 |
|
230 // Since we fetch all the instructions from a function (leading up to the current address) |
|
231 // we may have lots more instructions that we'd ideally normally expect to see form part |
|
232 // of the function prologue. Normally, we cap the prologue instruction count at ~19 instructions, |
|
233 // so therefore we should disable any instructions beyond this maximum. |
|
234 for ( int i = KMaxPrologueInstructionCount - 1; i < iInstructions.Count; i++ ) |
|
235 { |
|
236 iInstructions[ i ].Ignored = true; |
|
237 } |
|
238 |
|
239 // Run the instructions through the pre-filter. We tell the |
|
240 // instruction list how many instructions through the current function |
|
241 // we are because this helps to identify whether a branch has been |
|
242 // executed as the last instruction, or whether we artificially limited |
|
243 // the preamble, in which case the branch was "probably" not taken. |
|
244 iInstructions.Prefilter( iPrologueInstructionCount ); |
|
245 iInstructions.DebugPrint( iEngine as ITracer ); |
|
246 } |
|
247 |
|
248 private void PrepareInitialPCValue() |
|
249 { |
|
250 // Update the program counter so that we skip past the start of |
|
251 // the function. According to Tom G, this is two instructions past |
|
252 // the function entry address |
|
253 uint newPC = FunctionStartingAddress; |
|
254 newPC += (uint) ( 2 * SingleInstructionSize ); |
|
255 |
|
256 // Zero the non-address bits for sanity |
|
257 uint clearBitMask = (uint) ( SingleInstructionSize - 1 ); |
|
258 newPC &= ~clearBitMask; |
|
259 iPC.Value = newPC; |
|
260 |
|
261 string sym = iEngine.DebugEngineView.Symbols.PlainText[ iPC.Value ]; |
|
262 iEngine.Trace( "[PLG] PrepareInitialPCValue - new PC value: 0x{0:x8} = {1}", iPC.Value, sym ); |
|
263 } |
|
264 |
|
265 private void ProcessPrologueInstructions() |
|
266 { |
|
267 uint sp = iEngine.CPU[ TArmRegisterType.EArmReg_SP ]; |
|
268 iEngine.Trace( "[PLG] ProcessPrologueInstructions - initial PC: 0x{0:x8}, SP: 0x{1:x8}", iPC.Value, sp ); |
|
269 |
|
270 // We've got the necessary instructions so continue as normal... |
|
271 int actual = iInstructions.Count; |
|
272 while ( actual > 0 ) |
|
273 { |
|
274 // Get instruction |
|
275 AccInstruction inst = iInstructions.Deque(); |
|
276 |
|
277 // Don't process any ignored instructions |
|
278 if ( inst.Ignored == false ) |
|
279 { |
|
280 iEngine.Trace( "[PLG] ProcessPrologueInstructions - PC: 0x{0:x8}, SP: 0x{1:x8}, I: {2}", iPC.Value, sp + ( iNumberOfWordsPushedOnStack * 4 ), inst.ToString() ); |
|
281 iEngine.SetIndent( 1 ); |
|
282 |
|
283 // Process it to update offsets & register values |
|
284 inst.Process( this ); |
|
285 |
|
286 // Update Prologue program counter value |
|
287 iPC.Value += SingleInstructionSize; |
|
288 |
|
289 // Finished with indentation |
|
290 iEngine.SetIndent( 0 ); |
|
291 } |
|
292 |
|
293 // Update count |
|
294 actual = iInstructions.Count; |
|
295 } |
|
296 } |
|
297 #endregion |
|
298 |
|
299 #region Internal properties |
|
300 internal ArmCpu CPU |
|
301 { |
|
302 get { return iEngine.CPU; } |
|
303 } |
|
304 |
|
305 internal ArmCodeHelper CodeHelper |
|
306 { |
|
307 get { return iEngine.CodeHelper; } |
|
308 } |
|
309 |
|
310 internal ArmRegisterCollection OffsetValues |
|
311 { |
|
312 get { return iOffsetValues; } |
|
313 } |
|
314 |
|
315 private uint SingleInstructionSize |
|
316 { |
|
317 get |
|
318 { |
|
319 uint size = ArmCpuUtils.InstructionSize( CPU.CurrentProcessorMode ); |
|
320 return size; |
|
321 } |
|
322 } |
|
323 #endregion |
|
324 |
|
325 #region Internal constants |
|
326 private const int KMaxPrologueInstructionCount = 19; |
|
327 private const uint KInstructionSetMask = 0xFFFFFFFE; |
|
328 #endregion |
|
329 |
|
330 #region Data members |
|
331 private readonly AccurateEngine iEngine; |
|
332 private readonly ArmRegister iPC; |
|
333 private int iPrologueInstructionCount = 0; |
|
334 private string iFunctionName = string.Empty; |
|
335 private uint iFunctionStartAddress = 0; |
|
336 private int iNumberOfWordsPushedOnStack = 0; |
|
337 private AccInstructionList iInstructions = new AccInstructionList(); |
|
338 private ArmRegisterCollection iOffsetValues = new ArmRegisterCollection(); |
|
339 #endregion |
|
340 } |
|
341 } |