| 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
|
| - }
|
| -}
|
|
|