diff --git a/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Desktop/modules.cs b/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Desktop/modules.cs index e4b3124..95b5b95 100644 --- a/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Desktop/modules.cs +++ b/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Desktop/modules.cs @@ -1,20 +1,15 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Text.RegularExpressions; using Address = System.UInt64; -using System.Text; -using System.Collections; using System.IO; -using System.Reflection; -using Microsoft.Diagnostics.Runtime; using System.Runtime.InteropServices; using Microsoft.Diagnostics.Runtime.Utilities; using Dia2Lib; namespace Microsoft.Diagnostics.Runtime.Desktop { - abstract class DesktopBaseModule : ClrModule + public abstract class DesktopBaseModule : ClrModule { internal abstract Address GetDomainModule(ClrAppDomain appDomain); @@ -28,7 +23,7 @@ internal virtual IMetadata GetMetadataImport() public int Revision { get; set; } } - class DesktopModule : DesktopBaseModule + public class DesktopModule : DesktopBaseModule { bool m_reflection, m_isPE; string m_name, m_assemblyName; @@ -45,7 +40,6 @@ class DesktopModule : DesktopBaseModule SymbolModule m_symbols; PEFile m_peFile; - public override SourceLocation GetSourceInformation(ClrMethod method, int ilOffset) { if (method == null) @@ -65,6 +59,14 @@ public override SourceLocation GetSourceInformation(uint token, int ilOffset) return m_symbols.SourceLocationForManagedCode(token, ilOffset); } + public IList GetSourceLocationsForMethod(uint token) + { + if (m_symbols == null) + return null; + + return m_symbols.SourceLocationsForMethod(token); + } + public override bool IsPdbLoaded { get { return m_symbols != null; } } public override bool IsMatchingPdb(string pdbPath) @@ -90,7 +92,6 @@ public override void LoadPdb(string path) m_symbols = new SymbolModule(m_runtime.DataTarget.SymbolReader, path); } - public override object PdbInterface { get @@ -124,8 +125,7 @@ public override string TryDownloadPdb(ISymbolNotification notification) return reader.FindSymbolFilePath(pdbName, pdbGuid, rev, notification); } - - public DesktopModule(DesktopRuntimeBase runtime, ulong address, IModuleData data, string name, string assemblyName, ulong size) + internal DesktopModule(DesktopRuntimeBase runtime, ulong address, IModuleData data, string name, string assemblyName, ulong size) { Revision = runtime.Revision; m_imageBase = data.ImageBase; @@ -176,8 +176,6 @@ public override IEnumerable EnumerateTypes() m_typesLoaded = true; } - - } public override string AssemblyName diff --git a/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Utilities/SymbolReader.cs b/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Utilities/SymbolReader.cs index 2f65ce8..fb16306 100644 --- a/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Utilities/SymbolReader.cs +++ b/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/Utilities/SymbolReader.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; // For Win32Excption; using System.Diagnostics; @@ -1128,7 +1129,6 @@ public IDiaSession Session } } - /// /// Finds a (method) symbolic name for a given relative virtual address of some code. /// Returns an empty string if a name could not be found. @@ -1158,7 +1158,7 @@ public string FindNameForRva(uint rva) // TODO FIX NOW, should not need to do this hand-unmangling. if (ret.Contains("@")) { - // TODO relativel inefficient. + // TODO relatively inefficient. string unmangled = null; symbol.get_undecoratedNameEx(0x1000, out unmangled); if (unmangled != null) @@ -1209,6 +1209,7 @@ public SourceLocation SourceLocationForRva(uint rva) var sourceLocation = new SourceLocation(sourceLoc); return sourceLocation; } + /// /// Managed code is shipped as IL, so RVA to NATIVE mapping can't be placed in the PDB. Instead /// what is placed in the PDB is a mapping from a method's meta-data token and IL offset to source @@ -1270,12 +1271,45 @@ public SourceLocation SourceLocationForManagedCode(uint methodMetaDataToken, int var sourceLocation = new SourceLocation(sourceLoc); return sourceLocation; } + + /// + /// Get the full list of SourceLocations (with corresponding ILOffset) for the given method + /// Based on the commented out code from "SourceLocationForManagedCode(uint methodMetaDataToken, int ilOffset)" + /// + public IList SourceLocationsForMethod(uint methodMetaDataToken) + { + //m_reader.m_log.WriteLine("SourceLocationForManagedCode: Looking up method token {0:x}", methodMetaDataToken); + + IDiaSymbol methodSym; + m_session.findSymbolByToken(methodMetaDataToken, SymTagEnum.SymTagFunction, out methodSym); + if (methodSym == null) + { + m_reader.m_log.WriteLine("SourceLocationForManagedCode: No symbol for token {0:x}", methodMetaDataToken); + return null; + } + + IDiaEnumLineNumbers sourceLocs; + IList sourceLocations = new List(); + m_session.findLinesByRVA(methodSym.relativeVirtualAddress, 256, out sourceLocs); + for (int i = 0; ; i++) + { + IDiaLineNumber sourceLoc; + uint fetchCount; + sourceLocs.Next(1, out sourceLoc, out fetchCount); + if (fetchCount == 0) + break; + uint ilOffset = sourceLoc.relativeVirtualAddress - methodSym.relativeVirtualAddress; + sourceLocations.Add(new ILOffsetSourceLocation(ilOffset, new SourceLocation(sourceLoc))); + } + + return sourceLocations; + } + /// /// Returns a list of all source files referenced in the PDB /// public IEnumerable AllSourceFiles() { - IDiaEnumTables tables; m_session.getEnumTables(out tables); @@ -1308,6 +1342,7 @@ public IEnumerable AllSourceFiles() /// The a unique identifier that is used to relate the DLL and its PDB. /// public Guid PdbGuid { get { return m_session.globalScope.guid; } } + /// /// Along with the PdbGuid, there is a small integer /// call the age is also used to find the PDB (it represents the differnet diff --git a/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/public.cs b/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/public.cs index 86effd0..a8af6c6 100644 --- a/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/public.cs +++ b/Microsoft.Diagnostics.Runtime/CLRMD/ClrMemDiag/public.cs @@ -1538,6 +1538,24 @@ internal SourceLocation(IDiaLineNumber source) #endregion } + /// + /// Contains the mapping of IL Offset -> Source Location + /// + public class ILOffsetSourceLocation + { + private readonly uint ilOffset; + public uint ILOffset { get { return ilOffset; } } + + private readonly SourceLocation sourceLocation; + public SourceLocation SourceLocation { get { return sourceLocation; } } + + internal ILOffsetSourceLocation(uint ilOffset, SourceLocation sourceLocation) + { + this.ilOffset = ilOffset; + this.sourceLocation = sourceLocation; + } + } + /// /// Defines the state of the thread from the runtime's perspective. /// @@ -2841,7 +2859,9 @@ internal SymbolReader SymbolReader get { if (m_symbolReader == null) + { m_symbolReader = new SymbolReader(TextWriter.Null, m_symPath); + } return m_symbolReader; } diff --git a/Microsoft.Diagnostics.Runtime/CLRMD/MachineCode/Program.cs b/Microsoft.Diagnostics.Runtime/CLRMD/MachineCode/Program.cs index 4ba6720..f91efb7 100644 --- a/Microsoft.Diagnostics.Runtime/CLRMD/MachineCode/Program.cs +++ b/Microsoft.Diagnostics.Runtime/CLRMD/MachineCode/Program.cs @@ -84,7 +84,10 @@ static void Main(string[] args) File.ReadAllLines( @"C:\Users\warma11\Documents\Visual Studio 2013\Projects\JITterOptimisations\JITterOptimisations\Program.cs"); - PrintILToNativeOffsets(method, startAddress, lines); + PrintILToNativeOffsetAlternative(method, lines); + + // This doesn't seem to work as expected, using alternative method (above) + //PrintILToNativeOffsets(method, startAddress, lines); // This is what we expect it to be //--- c:\Users\warma11\Documents\Visual Studio 2013\Projects\JITterOptimisations\JITterOptimisations\Program.cs @@ -131,6 +134,40 @@ static void Main(string[] args) } } + private static void PrintILToNativeOffsetAlternative(ClrMethod method, string[] lines) + { + DesktopModule module = (DesktopModule) @method.Type.Module; + if (!module.IsPdbLoaded) + { + // Have to load the Pdb, if it's not already loaded!! + string val = module.TryDownloadPdb(null); + if (val != null) + module.LoadPdb(val); + } + + foreach (var location in module.GetSourceLocationsForMethod(@method.MetadataToken)) + { + ILOffsetSourceLocation ILLocation = location; + var ilMaps = @method.ILOffsetMap.Where(il => il.ILOffset == ILLocation.ILOffset); + Console.WriteLine("{0:X8} -> {1}:{2}", + location.ILOffset, + Path.GetFileName(location.SourceLocation.FilePath), + location.SourceLocation.LineNumber); + Console.WriteLine(" " + String.Join("\n ", + ilMaps.Select( + ilMap => + String.Format("[{0:X8}-{1:X8} ({2:X8}-{3:X8})] ILOffset: {4:X2}", + ilMap.StartAddress - @method.NativeCode, + ilMap.EndAddress - @method.NativeCode, + ilMap.StartAddress, ilMap.EndAddress, ilMap.ILOffset)))); + var indent = 7; + Console.WriteLine("{0,6}:{1}", location.SourceLocation.LineNumber, lines[location.SourceLocation.LineNumber - 1]); + Console.WriteLine(new string(' ', location.SourceLocation.ColStart - 1 + indent) + + new string('*', location.SourceLocation.ColEnd - location.SourceLocation.ColStart)); + } + Console.WriteLine(); + } + private static void PrintILToNativeOffsets(ClrMethod method, ulong startAddress, string[] lines) { Console.WriteLine("IL -> Native Offsets:");