OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #region | |
6 | |
7 using System; | |
8 using System.Collections.Generic; | |
9 using System.Diagnostics; | |
10 using System.IO; | |
11 using System.Linq; | |
12 using Google.MsAd7.BaseImpl; | |
13 using Google.MsAd7.BaseImpl.DebugProperties; | |
14 using Google.MsAd7.BaseImpl.Interfaces; | |
15 using Google.MsAd7.BaseImpl.Interfaces.SimpleSymbolTypes; | |
16 using Google.NaClVsx.DebugSupport.DWARF; | |
17 using NaClVsx; | |
18 | |
19 #endregion | |
20 | |
21 namespace Google.NaClVsx.DebugSupport { | |
22 /// <summary> | |
23 /// The NaClSymbolProvider provides generic address and code lookups. | |
24 /// </summary> | |
25 public class NaClSymbolProvider : ISimpleSymbolProvider { | |
26 public NaClSymbolProvider(ISimpleDebugger dbg) { | |
27 BaseAddress = 0; | |
28 dbg_ = dbg; | |
29 } | |
30 | |
31 public ulong BaseAddress { get; set; } | |
32 | |
33 /// <summary> | |
34 /// Internally MSVX uses 0-indexed positions. However, DWARF and MSVC's ow
n user interface | |
35 /// do not. This function exists because having the += 1 and -= 1 calcula
tions all over the | |
36 /// place, is extremely error-prone and confusing. | |
37 /// </summary> | |
38 /// <param name = "dwarfLineIndex">A 1-based index.</param> | |
39 /// <returns>The 0-based index.</returns> | |
40 public static uint GetMSVCLineIndex(uint dwarfLineIndex) { | |
41 return dwarfLineIndex - 1; | |
42 } | |
43 | |
44 /// <summary> | |
45 /// Internally MSVX uses 0-indexed positions. However, DWARF and MSVC's ow
n user interface | |
46 /// do not. This function exists because having the += 1 and -= 1 calcula
tions all over the | |
47 /// place, is extremely error-prone and confusing. | |
48 /// </summary> | |
49 /// <param name = "msvcLineIndex">A 0-based index.</param> | |
50 /// <returns>The 1-based index</returns> | |
51 public static uint GetDwarfLineIndex(uint msvcLineIndex) { | |
52 return msvcLineIndex + 1; | |
53 } | |
54 | |
55 /// <summary> | |
56 /// Uses a CallFrame record from the Symbol Database to apply a set of | |
57 /// rules to the current registerset, in order to derive the register | |
58 /// state for the next outer stack frame. | |
59 /// This function currently uses a short cut and does not result in a | |
60 /// completely accurate reproduction of the outer frame. Support for | |
61 /// that will require a more detailed implementation of the CFI analysis | |
62 /// specified by DWARF and will be added as a feature later. | |
63 /// </summary> | |
64 /// <param name = "currentRegisters">The state of the registers in the | |
65 /// current call frame.</param> | |
66 /// <returns>The outer callframe's register state.</returns> | |
67 public RegisterSet GetPreviousFrameState(RegisterSet currentRegisters) { | |
68 var rip = currentRegisters["RIP"]; | |
69 var pc = rip - BaseAddress; | |
70 if (pc > BaseAddress) { | |
71 return null; | |
72 } | |
73 var frame = | |
74 db_.GetCallFrameForAddress(rip - BaseAddress); | |
75 if (frame == null) { | |
76 return null; | |
77 } | |
78 | |
79 var result = currentRegisters.Clone() as RegisterSet; | |
80 var rules = new Dictionary<int, SymbolDatabase.CallFrame.Rule>(); | |
81 | |
82 // Find all of the rules that apply at the current address. | |
83 // Rules are stored in ascending order of address. If two | |
84 // rules exist for the same register, then the one with the | |
85 // highest address wins. | |
86 foreach (var rule in frame.Rules) { | |
87 if (rule.Address > rip) { | |
88 break; | |
89 } | |
90 rules[rule.RegisterId] = rule; | |
91 } | |
92 | |
93 // First we will hit the CFA rule and calculate the value of the previous | |
94 // Frame offset. Once we have that, the rest of the registers are | |
95 // updated using memory locations that are relative to the previous CFA. | |
96 // TODO(mlinck): This seems to end up with stackframes that represent the | |
97 // functions' return locations, not the call site. | |
98 foreach (var rule in rules.Values) { | |
99 switch (rule.RuleType) { | |
100 case IDwarfReader.CfiRuleType.Expression: | |
101 throw new NotImplementedException(); | |
102 case IDwarfReader.CfiRuleType.Offset: | |
103 var addr = | |
104 (ulong) ((long) result[rule.BaseRegister] + rule.Offset); | |
105 Debug.WriteLine( | |
106 "SymbolProvider:: result[rule.BaseRegister]: " + | |
107 String.Format( | |
108 "{0,4:X}", | |
109 result[rule.BaseRegister]) + | |
110 " rule.Offset: " + rule.Offset + | |
111 " addr: " + String.Format("{0,4:X}", addr) + | |
112 " rule.Address: " + String.Format( | |
113 "{0,4:X}", | |
114 rule.Address) + | |
115 " BaseAddress: " + String.Format( | |
116 "{0,4:X}", | |
117 BaseAddress)); | |
118 var newValue = dbg_.GetU64(addr - BaseAddress); | |
119 result[rule.RegisterId] = newValue; | |
120 break; | |
121 case IDwarfReader.CfiRuleType.Register: | |
122 result[rule.RegisterId] = result[rule.BaseRegister]; | |
123 break; | |
124 case IDwarfReader.CfiRuleType.SameValue: | |
125 // this rule seems to exist only to restore values that | |
126 // have gotten munged earlier. | |
127 result[rule.RegisterId] = currentRegisters[rule.RegisterId]; | |
128 break; | |
129 case IDwarfReader.CfiRuleType.Undefined: | |
130 // do nothing | |
131 break; | |
132 case IDwarfReader.CfiRuleType.ValExpression: | |
133 throw new NotImplementedException(); | |
134 case IDwarfReader.CfiRuleType.ValOffset: | |
135 var baseValue = (long) result[rule.BaseRegister]; | |
136 var offset = (long) rule.Offset; | |
137 newValue = (ulong) (baseValue + offset); | |
138 result[rule.RegisterId] = newValue; | |
139 break; | |
140 default: | |
141 throw new IndexOutOfRangeException("Bad rule type for CFI"); | |
142 } | |
143 } | |
144 return result; | |
145 } | |
146 | |
147 /// <summary> | |
148 /// Attempts to determine the symbol type for the symbol at the given addr
ess. | |
149 /// </summary> | |
150 /// <param name = "address">An address. Notes: This address needs to be an
address of a DIE | |
151 /// for an actual symbol. The address is the address of the DIE in the bi
nary file, also | |
152 /// known as its "key" in the Entries dictionary of the SymbolDatabase</pa
ram> | |
153 /// <returns>The windows debugger SymbolType.</returns> | |
154 public SymbolType GetSymbolType(ulong address) { | |
155 var result = new SymbolType { | |
156 Key = 0, | |
157 Name = "unknown", | |
158 SizeOf = 0, | |
159 TypeOf = BaseType.Unknown, | |
160 }; | |
161 DebugInfoEntry symbolEntry; | |
162 | |
163 // If we do not find this symbol, then return unknown. | |
164 if (!db_.Entries.TryGetValue(address, out symbolEntry)) { | |
165 return result; | |
166 } | |
167 | |
168 | |
169 if (symbolEntry.Attributes.ContainsKey(DwarfAttribute.DW_AT_type)) { | |
170 var val = | |
171 (DwarfReference) symbolEntry.Attributes[DwarfAttribute.DW_AT_type]; | |
172 result.Key = val.offset; | |
173 } else { | |
174 return result; | |
175 } | |
176 result.Name = ""; | |
177 // Process the linked list of modifiers as right associative to the base t
ype; | |
178 while (symbolEntry.Attributes.ContainsKey(DwarfAttribute.DW_AT_type)) { | |
179 var val = | |
180 (DwarfReference) symbolEntry.Attributes[DwarfAttribute.DW_AT_type]; | |
181 | |
182 if (!db_.Entries.TryGetValue(val.offset, out symbolEntry)) { | |
183 result.Key = 0; | |
184 result.Name = null; | |
185 return result; | |
186 } | |
187 | |
188 // Set the size of the symbol to the "right most" sized component such t
hat | |
189 // char *p is size 4 since '*' is size 4. | |
190 if (symbolEntry.Attributes.ContainsKey(DwarfAttribute.DW_AT_byte_size))
{ | |
191 var attrib = symbolEntry.Attributes[DwarfAttribute.DW_AT_byte_size]; | |
192 if (0 == result.SizeOf) { | |
193 result.SizeOf = (uint) (ulong) attrib; | |
194 } | |
195 } | |
196 | |
197 switch (symbolEntry.Tag) { | |
198 case DwarfTag.DW_TAG_const_type: | |
199 result.Name = " const" + result.Name; | |
200 break; | |
201 | |
202 case DwarfTag.DW_TAG_pointer_type: | |
203 result.Name = " *" + result.Name; | |
204 if (BaseType.Unknown == result.TypeOf) { | |
205 result.TypeOf = BaseType.Pointer; | |
206 } | |
207 break; | |
208 | |
209 case DwarfTag.DW_TAG_reference_type: | |
210 result.Name = " &" + result.Name; | |
211 break; | |
212 | |
213 case DwarfTag.DW_TAG_volatile_type: | |
214 result.Name = " volatile" + result.Name; | |
215 break; | |
216 | |
217 case DwarfTag.DW_TAG_restrict_type: | |
218 result.Name = " restrict" + result.Name; | |
219 break; | |
220 | |
221 case DwarfTag.DW_TAG_base_type: | |
222 result.Name = | |
223 (string) symbolEntry.Attributes[DwarfAttribute.DW_AT_name] + | |
224 result.Name; | |
225 if (BaseType.Unknown == result.TypeOf) { | |
226 var enc = | |
227 (DwarfEncoding) | |
228 (ulong) symbolEntry.Attributes[DwarfAttribute.DW_AT_encoding]; | |
229 switch (enc) { | |
230 case DwarfEncoding.DW_ATE_address: | |
231 result.TypeOf = BaseType.Pointer; | |
232 break; | |
233 | |
234 case DwarfEncoding.DW_ATE_boolean: | |
235 result.TypeOf = BaseType.Bool; | |
236 break; | |
237 | |
238 case DwarfEncoding.DW_ATE_signed_char: | |
239 case DwarfEncoding.DW_ATE_unsigned_char: | |
240 result.TypeOf = BaseType.Char; | |
241 break; | |
242 | |
243 case DwarfEncoding.DW_ATE_signed: | |
244 result.TypeOf = BaseType.Int; | |
245 break; | |
246 | |
247 case DwarfEncoding.DW_ATE_unsigned: | |
248 result.TypeOf = BaseType.UInt; | |
249 break; | |
250 | |
251 case DwarfEncoding.DW_ATE_float: | |
252 result.TypeOf = BaseType.Float; | |
253 break; | |
254 } | |
255 } | |
256 return result; | |
257 | |
258 case DwarfTag.DW_TAG_structure_type: | |
259 if (symbolEntry.HasAttribute(DwarfAttribute.DW_AT_name)) { | |
260 result.Name = | |
261 (string) symbolEntry.Attributes[DwarfAttribute.DW_AT_name] + | |
262 result.Name; | |
263 } | |
264 if (BaseType.Unknown == result.TypeOf) { | |
265 result.TypeOf = BaseType.Struct; | |
266 } | |
267 break; | |
268 | |
269 case DwarfTag.DW_TAG_subroutine_type: { | |
270 result.Name = " (" + result.Name.TrimStart(null) + ")("; | |
271 foreach ( | |
272 var parms in | |
273 db_.GetChildrenForEntry(val.offset)) { | |
274 if (parms.Tag == DwarfTag.DW_TAG_formal_parameter) { | |
275 result.Name += GetSymbolType(parms.Key).Name + ", "; | |
276 } | |
277 } | |
278 char[] trim = {',', ' '}; | |
279 result.Name = result.Name.TrimEnd(trim) + ")"; | |
280 break; | |
281 } | |
282 | |
283 case DwarfTag.DW_TAG_typedef: | |
284 result.Name = | |
285 (string) symbolEntry.Attributes[DwarfAttribute.DW_AT_name] + | |
286 result.Name; | |
287 break; | |
288 | |
289 default: | |
290 result.Name = "Parse Err"; | |
291 result.Key = 0; | |
292 break; | |
293 } | |
294 } | |
295 | |
296 return result; | |
297 } | |
298 | |
299 #region Implementation of ISimpleSymbolProvider | |
300 | |
301 public IBreakpointInfo GetBreakpointInfo() { | |
302 return new BreakpointInfo(db_, this); | |
303 } | |
304 | |
305 public ulong GetBaseAddress() { | |
306 return BaseAddress; | |
307 } | |
308 | |
309 public IEnumerable<ulong> AddressesFromPosition(DocumentPosition pos) { | |
310 var fname = Path.GetFileName(pos.Path); | |
311 if (!db_.SourceFilesByFilename.ContainsKey(fname)) { | |
312 return null; | |
313 } | |
314 | |
315 var files = db_.SourceFilesByFilename[fname]; | |
316 | |
317 if (files.Count() > 1) { | |
318 // TODO(ilewis): disambiguate | |
319 } else if (files.Count() == 0) { | |
320 return null; | |
321 } | |
322 | |
323 // Remember the path that was passed in, since that's where | |
324 // the current debugging session knows where to find this | |
325 // file | |
326 files[0].CurrentAbsolutePath = pos.Path; | |
327 | |
328 // Internally, MSVC uses zero-based lines. This is in contrast | |
329 // to both DWARF and MSVC's own user interface, but whatever. | |
330 // | |
331 var line = pos.BeginPos.dwLine + 1; | |
332 | |
333 return from loc in db_.LocationsByFile[files.First().Key] | |
334 where loc.Line == line | |
335 select loc.StartAddress + BaseAddress; | |
336 } | |
337 | |
338 | |
339 public DocumentPosition PositionFromAddress(ulong address) { | |
340 var loc = | |
341 db_.GetLocationForAddress(address - BaseAddress); | |
342 if (loc != null) { | |
343 // The DWARF line is 1-based; switch to zero-based for MSVC's benefit. | |
344 var line = loc.Line - 1; | |
345 return | |
346 new DocumentPosition( | |
347 db_.Files[loc.SourceFileKey].CurrentAbsolutePath, line); | |
348 } | |
349 return null; | |
350 } | |
351 | |
352 public IEnumerable<UInt64> GetAddressesInScope(UInt64 programCounter) { | |
353 var result = new List<UInt64>(); | |
354 programCounter -= BaseAddress; | |
355 | |
356 // Get the scope, current function, and frame pointer | |
357 var scopeEntry = | |
358 db_.GetScopeForAddress(programCounter); | |
359 if (scopeEntry == null) { | |
360 return result; | |
361 } | |
362 | |
363 // Find the parent most DIE which represents this function | |
364 var fnEntry = scopeEntry; | |
365 while (fnEntry.Tag != DwarfTag.DW_TAG_subprogram | |
366 && fnEntry.OuterScope != null) { | |
367 fnEntry = fnEntry.OuterScope; | |
368 } | |
369 | |
370 var functionLowPC = | |
371 (ulong) | |
372 fnEntry.Attributes.GetValueOrDefault(DwarfAttribute.DW_AT_low_pc, 0); | |
373 var fnMax = | |
374 (ulong) | |
375 fnEntry.Attributes.GetValueOrDefault(DwarfAttribute.DW_AT_high_pc, 0); | |
376 | |
377 | |
378 functionLowPC += BaseAddress; | |
379 fnMax += BaseAddress; | |
380 while (functionLowPC < fnMax) { | |
381 result.Add(functionLowPC); | |
382 functionLowPC = GetNextLocation(functionLowPC); | |
383 } | |
384 | |
385 return result; | |
386 } | |
387 | |
388 /// <summary> | |
389 /// This function retrieves the DebugInformationEntries for symbols that | |
390 /// are in scope at a given instruction address. | |
391 /// </summary> | |
392 /// <param name = "instructionAddress">The address for whose scope symbols | |
393 /// are being requested.</param> | |
394 /// <returns>A list of symbol descriptors for all the symbols that are in | |
395 /// scope at this location in the program.</returns> | |
396 public IEnumerable<Symbol> GetSymbolsInScope(ulong instructionAddress) { | |
397 var result = new List<Symbol>(); | |
398 // Adjust for the base of the untrusted code space. | |
399 instructionAddress -= BaseAddress; | |
400 | |
401 // Get the scope, current function, and frame pointer. The frame pointer | |
402 // will be used to determine what source code location applies to our | |
403 // current scope. | |
404 var scopeEntry = db_.GetScopeForAddress(instructionAddress); | |
405 if (scopeEntry == null) { | |
406 return result; | |
407 } | |
408 var functionEntry = | |
409 scopeEntry.GetNearestAncestorWithTag(DwarfTag.DW_TAG_subprogram); | |
410 var functionFrameBase = functionEntry.GetFrameBase(); | |
411 | |
412 // The code locations are given addresses relative to the compilation | |
413 // unit that contains them, so we have to make sure we can come up with | |
414 // that same offset. | |
415 var compilationUnitEntry = | |
416 functionEntry.GetNearestAncestorWithTag(DwarfTag.DW_TAG_compile_unit); | |
417 ulong compilationUnitLowPC = 0; | |
418 if (compilationUnitEntry.HasAttribute(DwarfAttribute.DW_AT_low_pc)) { | |
419 compilationUnitLowPC = compilationUnitEntry.GetLowPC(); | |
420 } else if (compilationUnitEntry.HasAttribute(DwarfAttribute.DW_AT_ranges))
{ | |
421 // This should never really happen. In case it does, it warrants some | |
422 // explanation. The reason we look for the functionFrameBase is because | |
423 // we need the rangelist entry for the location of the function, within | |
424 // the compilation unit. Any addresses in nested scopes would then be | |
425 // treated as relative addresses to that offset. | |
426 var rangeListEntry = db_.GetRangeForAddress(functionFrameBase, compilati
onUnitEntry); | |
427 if (rangeListEntry != null) { | |
428 compilationUnitLowPC += rangeListEntry.LowPC; | |
429 } | |
430 } | |
431 | |
432 var codeAddress = instructionAddress - compilationUnitLowPC; | |
433 // The VM inputs object handles feeding the VM whatever it asks for. | |
434 // This VM will execute the DWARF state machine to do any necessary | |
435 // low-level address calculations. | |
436 var vmInputs = new VirtualMachineInputs(dbg_, 0); | |
437 PrimeVMInputs(codeAddress, functionFrameBase, vmInputs); | |
438 | |
439 while (scopeEntry != null) { | |
440 foreach ( | |
441 var entry in | |
442 db_.GetChildrenForEntry(scopeEntry.Key)) { | |
443 // The assumption here is that all useful symbols have a location and | |
444 // a name. | |
445 if (entry.Attributes.ContainsKey(DwarfAttribute.DW_AT_location) | |
446 && entry.Attributes.ContainsKey(DwarfAttribute.DW_AT_name)) { | |
447 var name = (string) entry.Attributes[DwarfAttribute.DW_AT_name]; | |
448 var loc = entry.Attributes[DwarfAttribute.DW_AT_location] as byte[]; | |
449 // Program counter will not be used by ResolveLocation in this case | |
450 // because the loc we're handing in is always a byte array. | |
451 var symbolAddr = ResolveLocation(loc, vmInputs); | |
452 // store the symbolAddr and variable name. Note that symbolAddr is | |
453 // relative to the base address of the NaCl app. The base address | |
454 // is something like 0xC00000000, but the base gets added to this | |
455 // relative address (symbolAddr) later in functions like GetMemory | |
456 // (located in NaClDebugger.cs). | |
457 result.Add( | |
458 new Symbol { | |
459 Key = entry.Key, | |
460 Name = name, | |
461 Offset = symbolAddr, | |
462 TypeOf = GetSymbolType(entry.Key) | |
463 }); | |
464 } | |
465 } | |
466 scopeEntry = scopeEntry.OuterScope; | |
467 } | |
468 return result; | |
469 } | |
470 | |
471 /// <summary> | |
472 /// Determines what function the given address is in. | |
473 /// </summary> | |
474 /// <param name = "address">The address whose function is needed.</param> | |
475 /// <returns>The windows debugger representation of the containing function.
</returns> | |
476 public Function FunctionFromAddress(ulong address) { | |
477 var result = new Function { | |
478 Id = 0, | |
479 Name = "<unknown function>", | |
480 }; | |
481 | |
482 var scopeEntry = | |
483 db_.GetScopeForAddress(address - BaseAddress); | |
484 if (null != scopeEntry) { | |
485 var fnEntry = | |
486 scopeEntry.GetNearestAncestorWithTag(DwarfTag.DW_TAG_subprogram); | |
487 if (null != fnEntry) { | |
488 result.Id = fnEntry.Key; | |
489 result.Name = | |
490 (string) fnEntry.Attributes[DwarfAttribute.DW_AT_name]; | |
491 } | |
492 } | |
493 | |
494 return result; | |
495 } | |
496 | |
497 public FunctionDetails GetFunctionDetails(Function fn) { | |
498 throw new NotImplementedException(); | |
499 } | |
500 | |
501 public bool LoadModule(string path, ulong loadOffset, out string status) { | |
502 // TODO(ilewis): this should be per-module, not per-database (unless | |
503 // we decide to make database a per-module thing too) | |
504 BaseAddress = loadOffset; | |
505 try { | |
506 DwarfParser.DwarfParseElf(path, new DwarfReaderImpl(db_)); | |
507 db_.BuildIndices(); | |
508 status = "ELF/DWARF symbols loaded"; | |
509 return true; | |
510 } | |
511 catch (Exception e) { | |
512 status = e.Message; | |
513 return false; | |
514 } | |
515 } | |
516 | |
517 public ulong GetNextLocation(ulong addr) { | |
518 var loc = | |
519 db_.GetLocationForAddress(addr - BaseAddress); | |
520 return loc.StartAddress + loc.Length + BaseAddress; | |
521 } | |
522 | |
523 #endregion | |
524 | |
525 #region ISimpleSymbolProvider Members | |
526 | |
527 public String SymbolValueToString(ulong key, ArraySegment<Byte> arrBytes) { | |
528 var result = GetSymbolType(key); | |
529 var bytes = arrBytes.Array; | |
530 | |
531 // If we don't have enough data | |
532 if (bytes.Count() < result.SizeOf) { | |
533 return "INVALID"; | |
534 } | |
535 | |
536 // Or if we were unable to determine the type | |
537 if (result.TypeOf == BaseType.Unknown) { | |
538 return "INVALID"; | |
539 } | |
540 | |
541 Int64 i64 = 0; | |
542 double d64 = 0; | |
543 | |
544 try { | |
545 switch (result.SizeOf) { | |
546 case 1: | |
547 // We don't need to convert to number first because the switch | |
548 // statement below will convert byte[0] to string val. | |
549 break; | |
550 | |
551 case 2: | |
552 i64 = BitConverter.ToInt16(bytes, 0); | |
553 break; | |
554 | |
555 case 4: | |
556 i64 = BitConverter.ToInt32(bytes, 0); | |
557 d64 = BitConverter.ToSingle(bytes, 0); | |
558 break; | |
559 | |
560 case 8: | |
561 i64 = BitConverter.ToInt64(bytes, 0); | |
562 d64 = BitConverter.ToDouble(bytes, 0); | |
563 break; | |
564 } | |
565 } | |
566 catch (Exception e) { | |
567 // Without a catch here, the VSX SDK catches the exception and we | |
568 // just don't get a value back... Printing helps us realize this | |
569 // is happening (when we had a bad conversion for case 1 previously) | |
570 // and also lets us set a breakpoint inside the catch. | |
571 Debug.WriteLine( | |
572 "An exception was caught when calling BitConverter!" + | |
573 e); | |
574 } | |
575 | |
576 | |
577 var typeInfo = result.TypeOf; | |
578 Debug.WriteLine("typeOf: " + typeInfo + " size: " + result.SizeOf); | |
579 switch (result.TypeOf) { | |
580 case BaseType.Pointer: | |
581 return i64.ToString("X"); | |
582 | |
583 case BaseType.Bool: | |
584 if (0 != i64) { | |
585 return "True"; | |
586 } else { | |
587 return "False"; | |
588 } | |
589 | |
590 case BaseType.Char: | |
591 return bytes[0].ToString(); | |
592 | |
593 case BaseType.Int: | |
594 return i64.ToString(); | |
595 | |
596 case BaseType.UInt: | |
597 return ((UInt64) i64).ToString(); | |
598 | |
599 case BaseType.Float: | |
600 return d64.ToString(); | |
601 | |
602 case BaseType.Struct: | |
603 return "{" + result.Name + "}"; | |
604 } | |
605 return "INVALID"; | |
606 } | |
607 | |
608 #endregion | |
609 | |
610 #region Private Implementation | |
611 | |
612 readonly SymbolDatabase db_ = new SymbolDatabase(); | |
613 private readonly ISimpleDebugger dbg_; | |
614 | |
615 #endregion | |
616 | |
617 #region Private Implementation | |
618 | |
619 /// <summary> | |
620 /// Calculates the address on the stack, of a given location in the | |
621 /// instruction queue. | |
622 /// </summary> | |
623 /// <param name = "loc">The location in the instruction space.</param> | |
624 /// <param name = "vm">The virtual machine that is to be used to calculate | |
625 /// the stack address. It must be primed with context.</param> | |
626 /// <returns>The stack address corresponding to loc.</returns> | |
627 private static ulong ResolveLocation(byte[] loc, | |
628 VirtualMachineInputs vm) { | |
629 if (vm == null) { | |
630 throw new ArgumentNullException("vm"); | |
631 } | |
632 // A byte[] location is a Dwarf VM program, not an actual location. | |
633 // We need to run the VM and (possibly) supply inputs. | |
634 var stackAddress = DwarfParser.DwarfParseVM(vm, loc); | |
635 | |
636 if (stackAddress < (ulong) DwarfOpcode.DW_OP_regX) { | |
637 Debug.WriteLine("WARNING: Register vars not currently supported"); | |
638 } | |
639 return stackAddress; | |
640 } | |
641 | |
642 /// <summary> | |
643 /// Primes the inputs that will be handed to the DWARF VM, by giving it | |
644 /// relevant context. | |
645 /// </summary> | |
646 /// <param name = "codeAddress">The code address for which context will be | |
647 /// needed.</param> | |
648 /// <param name = "functionFrameBase">The frame base of the function that | |
649 /// contains the code address.</param> | |
650 /// <param name = "vmInputs">This parameter is modified. It is primed with | |
651 /// A framebase that is calculated for the current context so that future | |
652 /// DWARF address calculations can be peformed.</param> | |
653 private void PrimeVMInputs(ulong codeAddress, | |
654 ulong functionFrameBase, | |
655 VirtualMachineInputs vmInputs) { | |
656 var frameBase = ulong.MaxValue; | |
657 var loclist = | |
658 db_.LocLists[functionFrameBase]; | |
659 foreach (var locListEntry in loclist) { | |
660 if (locListEntry.StartAddress == ulong.MaxValue) { | |
661 frameBase = locListEntry.EndAddress; | |
662 break; | |
663 } | |
664 // Try to determine whether this is the address of a symbol and | |
665 // return the referenced address in memory. | |
666 if (locListEntry.StartAddress <= codeAddress | |
667 && codeAddress <= locListEntry.EndAddress) { | |
668 frameBase = DwarfParser.DwarfParseVM(vmInputs, locListEntry.Data); | |
669 break; | |
670 } | |
671 } | |
672 | |
673 if (frameBase < (ulong) DwarfOpcode.DW_OP_regX) { | |
674 Debug.WriteLine("WARNING: Register vars not currently supported"); | |
675 } | |
676 vmInputs.FrameBase = frameBase; | |
677 } | |
678 | |
679 #endregion | |
680 } | |
681 } | |
OLD | NEW |