Index: experimental/visual_studio_plugin/src/NaClVsx.Package/DebugSupport/DWARF/SymbolDatabase.cs |
diff --git a/experimental/visual_studio_plugin/src/NaClVsx.Package/DebugSupport/DWARF/SymbolDatabase.cs b/experimental/visual_studio_plugin/src/NaClVsx.Package/DebugSupport/DWARF/SymbolDatabase.cs |
deleted file mode 100644 |
index 290a8f5546119a8f4099785282306898d77aa1b9..0000000000000000000000000000000000000000 |
--- a/experimental/visual_studio_plugin/src/NaClVsx.Package/DebugSupport/DWARF/SymbolDatabase.cs |
+++ /dev/null |
@@ -1,514 +0,0 @@ |
-// Copyright (c) 2011 The Native Client Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#region |
- |
-using System.Collections.Generic; |
-using System.Linq; |
-using NaClVsx; |
- |
-#endregion |
- |
-namespace Google.NaClVsx.DebugSupport.DWARF { |
- public class SymbolDatabase { |
- // Tables |
- public Dictionary<ulong, DebugInfoAttribute> Attributes { |
- get { return attributes_; } |
- } |
- |
- public Dictionary<ulong, CallFrame> CallFrames { |
- get { return callFrames_; } |
- } |
- |
- public Dictionary<ulong, DebugInfoEntry> Entries { |
- get { return entries_; } |
- } |
- |
- public Dictionary<ulong, SourceFile> Files { |
- get { return files_; } |
- } |
- |
- public Dictionary<ulong, SourceLocation> Locations { |
- get { return locations_; } |
- } |
- |
- public Dictionary<ulong, List<LocListEntry>> LocLists { |
- get { return locLists_; } |
- } |
- |
- /// <summary> |
- /// Described from the inside out: |
- /// A rangelist is a dictionary mapping lowPC values to the RangeListEntries in which they |
- /// occur. The "RangeLists" field is another dictionary mapping offsets to Rangelists. |
- /// </summary> |
- public Dictionary<ulong, Dictionary<ulong, RangeListEntry>> RangeLists { |
- get { return rangeLists_; } |
- } |
- |
- public Dictionary<ulong, ScopeTransition> ScopeTransitions { |
- get { return scopeTransitions_; } |
- } |
- |
- public Dictionary<ulong, List<DebugInfoEntry>> EntriesByParent { |
- get { return entriesByParent_; } |
- } |
- |
- public Dictionary<ulong, List<SourceLocation>> LocationsByFile { |
- get { return locationsByFile_; } |
- } |
- |
- /// <summary> |
- /// For most lookups, range lists have to be matched to a DIE. This mapping exists in order |
- /// to make that easier. It is generated by BuildIndices(). |
- /// </summary> |
- public Dictionary<ulong, Dictionary<ulong, RangeListEntry>> RangeListsByDIE { |
- get { return rangeListsByDIE_; } |
- } |
- |
- public Dictionary<string, List<SourceFile>> SourceFilesByFilename { |
- get { return sourceFilesByFilename_; } |
- } |
- |
- // Query methods |
- public SourceLocation GetLocationForAddress(ulong address) { |
- return GetRowForAddress(address, locations_, locationAddresses_); |
- } |
- |
- /// <summary> |
- /// This function returns a list of code locations that occur in the given |
- /// scope, sorted by their line numbers. |
- /// </summary> |
- /// <param name = "scope"> |
- /// The scope for which lines are being required. |
- /// </param> |
- /// <param name = "address"> |
- /// The address within the scope, for which lines are being required. |
- /// This is used to disambiguate between range list entries. |
- /// </param> |
- /// <returns> |
- /// A list of source locations. |
- /// </returns> |
- public IEnumerable<SourceLocation> GetLocationsByLine( |
- DebugInfoEntry scope, ulong address) { |
- IEnumerable<SourceLocation> locationsByLine = null; |
- |
- if (scope.HasAttribute(DwarfAttribute.DW_AT_low_pc)) { |
- var scopeAddress = scope.GetLowPC(); |
- if (scopeToLocationsByLine_.ContainsKey(scopeAddress)) { |
- locationsByLine = scopeToLocationsByLine_[scopeAddress]; |
- } |
- } else if (scope.HasAttribute(DwarfAttribute.DW_AT_ranges)) { |
- var range = GetRangeForAddress(address, scope); |
- var absoluteRangeAddress = ulong.MaxValue; |
- // We need to add either the range's base address or the compilation unit's lowPC address. |
- if (ulong.MaxValue != range.BaseAddress) { |
- absoluteRangeAddress = range.BaseAddress + range.LowPC; |
- } else { |
- var compilationUnitEntry = |
- scope.GetNearestAncestorWithTag(DwarfTag.DW_TAG_compile_unit); |
- if (null != compilationUnitEntry && |
- compilationUnitEntry.HasAttribute(DwarfAttribute.DW_AT_low_pc)) { |
- absoluteRangeAddress = compilationUnitEntry.GetLowPC() + range.LowPC; |
- } |
- } |
- if (absoluteRangeAddress != ulong.MaxValue) { |
- locationsByLine = scopeToLocationsByLine_[absoluteRangeAddress]; |
- } |
- } |
- |
- return locationsByLine ?? (new List<SourceLocation>()); |
- } |
- |
- /// <summary> |
- /// Returns the rangelist entry that contains the given address, provided there is one. |
- /// Note that this function will always try to return a rangelist entry so it is up to the |
- /// caller to first verify that the address is contained in a rangelist. |
- /// </summary> |
- /// <param name = "address">An address which is thought to be contained in a rangelist.</param> |
- /// <returns>A RangeListEntry whose LowPC's absolute address is less than |address|.</returns> |
- public RangeListEntry GetRangeForAddress(ulong address, DebugInfoEntry scope) { |
- RangeListEntry range = null; |
- if (scope.HasAttribute(DwarfAttribute.DW_AT_ranges)) { |
- var rangeListKeys = new List<ulong>(); |
- rangeListKeys.AddRange(scope.RangeListsByAddress.Keys); |
- rangeListKeys.Sort(); |
- range = GetRowForAddress(address, scope.RangeListsByAddress, rangeListKeys); |
- } |
- return range; |
- } |
- |
- /// <summary> |
- /// Locates the scope entry which contains a given address and returns the scope entry |
- /// point. |
- /// </summary> |
- /// <param name = "address">The address for which a scope is needed.</param> |
- public ulong GetScopeAddress(ulong address) { |
- var row = GetRowForAddress(address, scopeTransitions_, scopeTransitionAddresses_); |
- return row.Address; |
- } |
- |
- public DebugInfoEntry GetScopeForAddress(ulong address) { |
- var row = GetRowForAddress(address, scopeTransitions_, scopeTransitionAddresses_); |
- return row.Entry; |
- } |
- |
- public CallFrame GetCallFrameForAddress(ulong address) { |
- return GetRowForAddress(address, callFrames_, callFrameAddresses_); |
- } |
- |
- public IEnumerable<DebugInfoEntry> GetChildrenForEntry(ulong entryKey) { |
- List<DebugInfoEntry> result; |
- if (!entriesByParent_.TryGetValue(entryKey, out result)) { |
- result = new List<DebugInfoEntry>(); |
- } |
- return result; |
- } |
- |
- /// <summary> |
- /// This function generates all the "secondary" look-up tables that constitute the |
- /// SymbolDatabase. This is basically a post-processing step for the binary data. The |
- /// lookup structures that are generated here are as follows: |
- /// - entriesByParent: For finding the children of any given DIE. |
- /// - sourceFilesByFilename: For locating source files. |
- /// - locationsByFile: For retrieving all of the SourceLocations in any given file. This |
- /// is used for setting breakpoints. |
- /// - locationAddresses: The addresses of the SourceLocations, sorted to allow quick |
- /// inexact lookups at runtime. They are used as keys into locations_. |
- /// - scopeTransitionAddresses: The addresses of the scope transitions. Used to allow |
- /// quick inexact lookups by address into the scopeTransitions table at runtime. |
- /// - callFrameAddresses: The addresses of the call frames. Used to allow quick inexact |
- /// lookups by address into the callFrames_ table at runtime. |
- /// - scopeToLocationsByLine: A mapping of scope addresses to lists of code locations that |
- /// are sorted by line number. This is to quickly find the right line of code within a |
- /// given scope at runtime. |
- /// The function also post-processes the RangeLists to add them scope transitions and make |
- /// them searchable by the Address of the DIE to which they belong. |
- /// </summary> |
- public void BuildIndices() { |
- BuildIndex(entries_, entriesByParent_, r => r.ParentKey); |
- BuildIndex(files_, sourceFilesByFilename_, r => r.Filename); |
- BuildIndex(locations_, locationsByFile_, r => r.SourceFileKey); |
- |
- locationAddresses_.AddRange(locations_.Keys); |
- locationAddresses_.Sort(); |
- |
- scopeTransitionAddresses_.AddRange(scopeTransitions_.Keys); |
- scopeTransitionAddresses_.Sort(); |
- |
- callFrameAddresses_.AddRange(callFrames_.Keys); |
- callFrameAddresses_.Sort(); |
- |
- // This must be called after scopeTransitionAddresses is created. |
- BuildRangeListsByDIE(); |
- AddRangesToScopeTransitions(); |
- |
- var scopeToLocations = new Dictionary<ulong, List<SourceLocation>>(); |
- foreach (var sourceLocation in locations_) { |
- var scopeStart = GetScopeAddress(sourceLocation.Key); |
- if (!scopeToLocations.ContainsKey(scopeStart)) { |
- scopeToLocations.Add(scopeStart, new List<SourceLocation>()); |
- } |
- scopeToLocations[scopeStart].Add(sourceLocation.Value); |
- } |
- |
- foreach (var entry in scopeToLocations) { |
- if (!scopeToLocationsByLine_.ContainsKey(entry.Key)) { |
- scopeToLocationsByLine_.Add(entry.Key, null); |
- } |
- scopeToLocationsByLine_[entry.Key] = entry.Value.OrderBy(r => r.Line); |
- } |
- } |
- |
- #region Private Implementation |
- |
- private readonly Dictionary<ulong, DebugInfoAttribute> attributes_ = |
- new Dictionary<ulong, DebugInfoAttribute>(); |
- |
- private readonly List<ulong> callFrameAddresses_ = new List<ulong>(); |
- |
- private readonly Dictionary<ulong, CallFrame> callFrames_ = |
- new Dictionary<ulong, CallFrame>(); |
- |
- // Indices |
- private readonly Dictionary<ulong, List<DebugInfoEntry>> entriesByParent_ = |
- new Dictionary<ulong, List<DebugInfoEntry>>(); |
- |
- private readonly Dictionary<ulong, DebugInfoEntry> entries_ = |
- new Dictionary<ulong, DebugInfoEntry>(); |
- |
- private readonly Dictionary<ulong, SourceFile> files_ = |
- new Dictionary<ulong, SourceFile>(); |
- |
- private readonly Dictionary<ulong, List<LocListEntry>> locLists_ = |
- new Dictionary<ulong, List<LocListEntry>>(); |
- |
- private readonly List<ulong> locationAddresses_ = new List<ulong>(); |
- |
- private readonly Dictionary<ulong, List<SourceLocation>> locationsByFile_ = |
- new Dictionary<ulong, List<SourceLocation>>(); |
- |
- private readonly Dictionary<ulong, SourceLocation> locations_ = |
- new Dictionary<ulong, SourceLocation>(); |
- |
- private readonly Dictionary<ulong, Dictionary<ulong, RangeListEntry>> rangeListsByDIE_ = |
- new Dictionary<ulong, Dictionary<ulong, RangeListEntry>>(); |
- |
- private readonly Dictionary<ulong, Dictionary<ulong, RangeListEntry>> rangeLists_ = |
- new Dictionary<ulong, Dictionary<ulong, RangeListEntry>>(); |
- |
- private readonly Dictionary<ulong, IEnumerable<SourceLocation>> |
- scopeToLocationsByLine_ = |
- new Dictionary<ulong, IEnumerable<SourceLocation>>(); |
- |
- // Sorted address lists |
- private readonly List<ulong> scopeTransitionAddresses_ = new List<ulong>(); |
- |
- private readonly Dictionary<ulong, ScopeTransition> scopeTransitions_ = |
- new Dictionary<ulong, ScopeTransition>(); |
- |
- private readonly Dictionary<string, List<SourceFile>> sourceFilesByFilename_ |
- = new Dictionary<string, List<SourceFile>>(); |
- |
- #endregion |
- |
- #region Private Implementation |
- |
- private static void BuildIndex<TRow, TColumn>( |
- IEnumerable<KeyValuePair<ulong, TRow>> table, |
- IDictionary<TColumn, List<TRow>> index, |
- FieldAccessor<TRow, TColumn> accessor) { |
- // Clear out the index so we can rebuild it |
- index.Clear(); |
- |
- // Iterate over each row in the table and insert it |
- // into the appropriate entry in the index. |
- foreach (var pair in table) { |
- List<TRow> indexList; |
- var columnValue = accessor(pair.Value); |
- |
- // If the index doesn't yet have a list for this value, |
- // add one. |
- if (!index.TryGetValue(columnValue, out indexList)) { |
- indexList = new List<TRow>(); |
- index.Add(columnValue, indexList); |
- } |
- indexList.Add(pair.Value); |
- } |
- } |
- |
- /// <summary> |
- /// Retrieves a row in a table for a given address. |
- /// TODO(mlinck): This does not recognize when a value is out of bounds. |
- /// </summary> |
- /// <typeparam name = "T">The type of the lookup table to use.</typeparam> |
- /// <param name = "address">The address to use as key.</param> |
- /// <param name = "table">The lookup table to use.</param> |
- /// <param name = "index">The index to allow for quicker lookup.</param> |
- /// <returns>An entry in the table that frames the address or the last |
- /// value in the table if the address is out of bounds.</returns> |
- private static T GetRowForAddress<T>(ulong address, |
- IDictionary<ulong, T> table, |
- List<ulong> index) where T : class { |
- T result = null; |
- |
- var pos = index.BinarySearch(address); |
- if (pos < 0) { |
- // a negative value means there was no exact match. The |
- // value is the two's complement of the next largest match |
- // (which is not what we want; we want the next smaller match) |
- pos = (~pos) - 1; |
- } |
- if (pos >= 0) { |
- var closestAddress = index[pos]; |
- result = table[closestAddress]; |
- } |
- return result; |
- } |
- |
- /// <summary> |
- /// This function goes through each DIE that has a RangeList and adds |
- /// scope entries for each range in the list. BuildRangeListsByDIE has to |
- /// be run in order for this to succeed. |
- /// </summary> |
- private void AddRangesToScopeTransitions() { |
- foreach (var dieToRangeList in RangeListsByDIE) { |
- var rangeList = dieToRangeList.Value; |
- foreach (var range in rangeList.Values) { |
- var scopeAddress = range.LowPC; |
- var scopeEndAddress = range.HighPC; |
- var die = Entries[dieToRangeList.Key]; |
- if (range.BaseAddress != ulong.MaxValue) { |
- scopeAddress += range.BaseAddress; |
- scopeEndAddress += range.BaseAddress; |
- } else { |
- var compileUnit = |
- die.GetNearestAncestorWithTag(DwarfTag.DW_TAG_compile_unit); |
- if (compileUnit != null && |
- compileUnit.HasAttribute(DwarfAttribute.DW_AT_low_pc) && |
- compileUnit.GetLowPC() != 0) { |
- scopeAddress += compileUnit.GetLowPC(); |
- scopeEndAddress += compileUnit.GetLowPC(); |
- } |
- } |
- die.AddRangeListEntryByAddress(scopeAddress, range); |
- var scopeTransition = new ScopeTransition { |
- Address = scopeAddress, |
- Entry = die |
- }; |
- if (ScopeTransitions.ContainsKey(scopeAddress)) { |
- // If the DIE that has this Key is a child of this DIE, don't add |
- // our own entry. Otherwise, overwrite it since the current DIE |
- // is a more specific scope. |
- var collidingTransition = ScopeTransitions[scopeAddress]; |
- if (die.HasAsAncestor(collidingTransition.Entry.Key)) { |
- InsertRangeScopeTransition(scopeTransition, scopeEndAddress, false); |
- } |
- } else { |
- InsertRangeScopeTransition(scopeTransition, scopeEndAddress, true); |
- } |
- } |
- } |
- } |
- |
- /// <summary> |
- /// This mapping is useful because it allows us to skip the step where we |
- /// always have to search DIEs for the correct range list offset. |
- /// </summary> |
- private void BuildRangeListsByDIE() { |
- var entriesWithRanges = |
- from entry in Entries |
- where entry.Value.HasAttribute(DwarfAttribute.DW_AT_ranges) |
- select entry.Value; |
- foreach (var entry in entriesWithRanges) { |
- var rangesKey = entry.GetRangesOffset(); |
- var rangeList = RangeLists[rangesKey]; |
- RangeListsByDIE.Add(entry.Key, rangeList); |
- } |
- } |
- |
- /// <summary> |
- /// This function assumes that the decision to add the scope transition |
- /// has been finalized. It will only make sure that the transition is |
- /// added in the correct order and that, if appropriate, a transition back |
- /// to the parent scope is added as well. |
- /// </summary> |
- private void InsertRangeScopeTransition(ScopeTransition scopeTransition, |
- ulong highPC, |
- bool isNewEntry) { |
- var previousScopeAddress = GetScopeAddress(scopeTransition.Address); |
- var nextScopeIndex = |
- scopeTransitionAddresses_.IndexOf(previousScopeAddress) + 1; |
- var nextScopeAddress = scopeTransitionAddresses_[nextScopeIndex]; |
- |
- // If the range and its parent entry end on the same address, we need to |
- // add a transition back to the parent. |
- var needsReturnScope = (nextScopeAddress >= highPC); |
- ScopeTransitions[scopeTransition.Address] = scopeTransition; |
- if (isNewEntry) { |
- // Since we needed this sorted in order to proceed, we keep it sorted |
- // to save time. |
- scopeTransitionAddresses_.Insert( |
- nextScopeIndex++, scopeTransition.Address); |
- } |
- if (needsReturnScope) { |
- var parentDIE = ScopeTransitions[previousScopeAddress].Entry; |
- var parentScopeTransition = new ScopeTransition { |
- Address = highPC, |
- Entry = parentDIE |
- }; |
- ScopeTransitions[highPC] = parentScopeTransition; |
- scopeTransitionAddresses_.Insert( |
- nextScopeIndex, parentScopeTransition.Address); |
- } |
- } |
- |
- #endregion |
- |
- #region Private Implementation |
- |
- private delegate TColumn FieldAccessor<TRow, TColumn>(TRow row); |
- |
- #endregion |
- |
- #region Nested type: CallFrame |
- |
- public class CallFrame { |
- public ulong Address; //use as key |
- |
- public List<Rule> Rules = new List<Rule>(); |
- |
- #region Nested type: Rule |
- |
- public class Rule { |
- public ulong Address; |
- public int RegisterId; |
- |
- public IDwarfReader.CfiRuleType RuleType; |
- public int BaseRegister; |
- public int Offset; |
- public byte[] Expression; |
- } |
- |
- #endregion |
- } |
- |
- #endregion |
- |
- #region Nested type: DebugInfoAttribute |
- |
- public class DebugInfoAttribute { |
- // Offset from beginning of dwarf section. |
- public ulong Key; |
- // Key of the DebugInfoEntry that this attribute helps describe. |
- public ulong ParentKey; |
- public DwarfAttribute Tag; |
- public object Value; |
- } |
- |
- #endregion |
- |
- #region Nested type: LocListEntry |
- |
- public class LocListEntry { |
- public ulong StartAddress; |
- public ulong EndAddress; |
- public byte[] Data; |
- } |
- |
- #endregion |
- |
- #region Nested type: ScopeTransition |
- |
- public class ScopeTransition { |
- public ulong Address; |
- public DebugInfoEntry Entry; |
- } |
- |
- #endregion |
- |
- #region Nested type: SourceFile |
- |
- public class SourceFile { |
- public ulong Key; |
- public string Filename; |
- public string RelativePath; |
- public string CurrentAbsolutePath; |
- } |
- |
- #endregion |
- |
- #region Nested type: SourceLocation |
- |
- public class SourceLocation { |
- public ulong StartAddress; // Use as key, since it is unique |
- public ulong Length; |
- |
- public ulong SourceFileKey; |
- public uint Line; |
- public uint Column; |
- } |
- |
- #endregion |
- } |
-} |