diff options
30 files changed, 1478 insertions, 653 deletions
diff --git a/build.proj b/build.proj index f3a9d40537..7df2904e36 100644 --- a/build.proj +++ b/build.proj @@ -19,6 +19,7 @@ <!-- Override clean from dir.traversal.targets and just remove the full BinDir --> <Target Name="Clean"> + <Delete Files="$(BinDir)SOS.NETCore.*" /> <Delete Files="$(BinDir)mscorlib.*" /> <Delete Files="$(BinDir)System.Private.CoreLib.*" /> </Target> @@ -27,4 +28,4 @@ <Exec Command="$(DnuRestoreCommand) "$(SourceDir).nuget/init/project.json" --source https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" /> </Target> -</Project>
\ No newline at end of file +</Project> @@ -82,7 +82,7 @@ <!-- Output paths --> <PropertyGroup> - <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == ''">$(RootBinDir)obj/</BaseIntermediateOutputPath> + <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == ''">$(RootBinDir)obj\</BaseIntermediateOutputPath> <IntermediateOutputPath Condition="'$(IntermediateOutputPath)' == ''">$(BaseIntermediateOutputPath)\$(BuildOS).$(BuildArch).$(BuildType)</IntermediateOutputPath> <OutputPath Condition="'$(OutputPath)' == ''">$(BaseIntermediateOutputPath)\$(BuildOS).$(BuildArch).$(BuildType)</OutputPath> <FinalOutputPath Condition="'$(FinalOutputPath)' == ''">$(BinDir)</FinalOutputPath> diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/debian/Microsoft.NETCore.Runtime.CoreCLR.pkgproj b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/debian/Microsoft.NETCore.Runtime.CoreCLR.pkgproj index 0a7e5cbfcb..2709e18690 100644 --- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/debian/Microsoft.NETCore.Runtime.CoreCLR.pkgproj +++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/debian/Microsoft.NETCore.Runtime.CoreCLR.pkgproj @@ -22,6 +22,7 @@ <ArchitectureSpecificNativeFile Include="$(BinDir)System.Private.CoreLib.ni.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)mscorlib.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" /> + <ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" /> <ArchitectureSpecificToolFile Include="$(BinDir)crossgen" /> <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" /> <File Include="@(ArchitectureSpecificNativeFile)"> @@ -53,4 +54,4 @@ </File> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/fedora/23/Microsoft.NETCore.Runtime.CoreCLR.pkgproj b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/fedora/23/Microsoft.NETCore.Runtime.CoreCLR.pkgproj index 657ccca6d4..3e3533d089 100644 --- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/fedora/23/Microsoft.NETCore.Runtime.CoreCLR.pkgproj +++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/fedora/23/Microsoft.NETCore.Runtime.CoreCLR.pkgproj @@ -22,6 +22,7 @@ <ArchitectureSpecificNativeFile Include="$(BinDir)System.Private.CoreLib.ni.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)mscorlib.dll" /> + <ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" /> <ArchitectureSpecificToolFile Include="$(BinDir)crossgen" /> <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" /> <File Include="@(ArchitectureSpecificNativeFile)"> @@ -53,4 +54,4 @@ </File> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/opensuse/13.2/Microsoft.NETCore.Runtime.CoreCLR.pkgproj b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/opensuse/13.2/Microsoft.NETCore.Runtime.CoreCLR.pkgproj index 1c50503710..cc8c206bbe 100644 --- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/opensuse/13.2/Microsoft.NETCore.Runtime.CoreCLR.pkgproj +++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/opensuse/13.2/Microsoft.NETCore.Runtime.CoreCLR.pkgproj @@ -22,6 +22,7 @@ <ArchitectureSpecificNativeFile Include="$(BinDir)System.Private.CoreLib.ni.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)mscorlib.dll" /> + <ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" /> <ArchitectureSpecificToolFile Include="$(BinDir)crossgen" /> <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" /> <File Include="@(ArchitectureSpecificNativeFile)"> @@ -53,4 +54,4 @@ </File> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/osx/Microsoft.NETCore.Runtime.CoreCLR.pkgproj b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/osx/Microsoft.NETCore.Runtime.CoreCLR.pkgproj index a244b8878d..f076019bb0 100644 --- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/osx/Microsoft.NETCore.Runtime.CoreCLR.pkgproj +++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/osx/Microsoft.NETCore.Runtime.CoreCLR.pkgproj @@ -20,6 +20,7 @@ <ArchitectureSpecificNativeFile Include="$(BinDir)System.Private.CoreLib.ni.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)mscorlib.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" /> + <ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" /> <ArchitectureSpecificToolFile Include="$(BinDir)crossgen" /> <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" /> <File Include="@(ArchitectureSpecificNativeFile)"> @@ -51,4 +52,4 @@ </File> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/rhel/Microsoft.NETCore.Runtime.CoreCLR.pkgproj b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/rhel/Microsoft.NETCore.Runtime.CoreCLR.pkgproj index eaa6e34ed5..200abce48a 100644 --- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/rhel/Microsoft.NETCore.Runtime.CoreCLR.pkgproj +++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/rhel/Microsoft.NETCore.Runtime.CoreCLR.pkgproj @@ -22,6 +22,7 @@ <ArchitectureSpecificNativeFile Include="$(BinDir)System.Private.CoreLib.ni.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)mscorlib.dll" /> + <ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" /> <ArchitectureSpecificToolFile Include="$(BinDir)crossgen" /> <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" /> <File Include="@(ArchitectureSpecificNativeFile)"> @@ -53,4 +54,4 @@ </File> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/14.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/14.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj index a0110d5ee3..8996273628 100644 --- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/14.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj +++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/14.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj @@ -22,6 +22,7 @@ <ArchitectureSpecificNativeFile Include="$(BinDir)System.Private.CoreLib.ni.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)mscorlib.dll" /> + <ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" /> <ArchitectureSpecificToolFile Include="$(BinDir)crossgen" /> <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" /> <File Include="@(ArchitectureSpecificNativeFile)"> @@ -53,4 +54,4 @@ </File> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/16.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/16.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj index 14e86cd500..f12132de6f 100644 --- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/16.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj +++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/16.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj @@ -22,6 +22,7 @@ <ArchitectureSpecificNativeFile Include="$(BinDir)System.Private.CoreLib.ni.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)mscorlib.dll" /> + <ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" /> <ArchitectureSpecificToolFile Include="$(BinDir)crossgen" /> <ArchitectureSpecificNativeFile Include="@(NativeSplittableBinary)" /> <File Include="@(ArchitectureSpecificNativeFile)"> @@ -53,4 +54,4 @@ </File> </ItemGroup> <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/win/Microsoft.NETCore.Runtime.CoreCLR.pkgproj b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/win/Microsoft.NETCore.Runtime.CoreCLR.pkgproj index 930d277b8c..41a38875fe 100644 --- a/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/win/Microsoft.NETCore.Runtime.CoreCLR.pkgproj +++ b/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/win/Microsoft.NETCore.Runtime.CoreCLR.pkgproj @@ -19,6 +19,7 @@ <ArchitectureSpecificNativeFile Include="$(BinDir)System.Private.CoreLib.ni.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)System.Private.CoreLib.dll" /> <ArchitectureSpecificLibFile Include="$(BinDir)mscorlib.dll" /> + <ArchitectureSpecificLibFile Include="$(BinDir)SOS.NETCore.dll" /> <ArchitectureSpecificToolFile Include="$(BinDir)crossgen.exe" /> <CrossArchitectureSpecificToolFile Include="$(BinDir)$(CrossTargetComponentFolder)\crossgen.exe" /> <CrossArchitectureSpecificToolFile Include="$(BinDir)$(CrossTargetComponentFolder)\mscordaccore.dll" /> diff --git a/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj b/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj new file mode 100644 index 0000000000..e8e2b7e0bd --- /dev/null +++ b/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + + <PropertyGroup> + <AssemblyName>SOS.NETCore</AssemblyName> + <AssemblyVersion>1.0.0.0</AssemblyVersion> + <ProjectGuid>{20513BA2-A156-4A17-4C70-5AC2DBD4F833}</ProjectGuid> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <OutputType>Library</OutputType> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <NoStdLib>true</NoStdLib> + <NoCompilerStandardLib>true</NoCompilerStandardLib> + </PropertyGroup> + + <!-- Default configurations to help VS understand the options --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'" /> + + <!-- Configuration specific properties --> + <PropertyGroup Condition="'$(Configuration)' == 'Debug' or '$(Configuration)' == 'Checked'"> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <DefineConstants>_DEBUG;DEBUG;TRACE;$(DefineConstants)</DefineConstants> + </PropertyGroup> + + <PropertyGroup Condition="'$(OsEnvironment)' == 'Unix'"> + <DebugSymbols>false</DebugSymbols> + <DebugType>none</DebugType> + </PropertyGroup> + + <ItemGroup> + <Compile Include="SymbolReader.cs" /> + </ItemGroup> + + <ItemGroup> + <None Include="project.json" /> + </ItemGroup> + + <Target Name="CopyItemsToDirectory" AfterTargets="Build"> + <Copy + SourceFiles="$(OutputPath)$(AssemblyName).dll" + DestinationFolder="$(BinDir)" + SkipUnchangedFiles="false" + OverwriteReadOnlyFiles="false" + UseHardlinksIfPossible="false"> + </Copy> + + <Copy + Condition="'$(OsEnvironment)' != 'Unix'" + SourceFiles="$(OutputPath)$(AssemblyName).pdb" + DestinationFolder="$(BinDir)\PDB" + SkipUnchangedFiles="false" + OverwriteReadOnlyFiles="false" + UseHardlinksIfPossible="false"> + </Copy> + </Target> + + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/src/ToolBox/SOS/NETCore/SOS.NETCore.sln b/src/ToolBox/SOS/NETCore/SOS.NETCore.sln new file mode 100644 index 0000000000..0106883b9c --- /dev/null +++ b/src/ToolBox/SOS/NETCore/SOS.NETCore.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SOS.NETCore", "SOS.NETCore.csproj", "{20513BA2-A156-4A17-4C70-5AC2DBD4F833}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Debug|Any CPU.Build.0 = Debug|Any CPU + {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Release|Any CPU.ActiveCfg = Release|Any CPU + {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/ToolBox/SOS/NETCore/SymbolReader.cs b/src/ToolBox/SOS/NETCore/SymbolReader.cs new file mode 100644 index 0000000000..c4c1dc89d2 --- /dev/null +++ b/src/ToolBox/SOS/NETCore/SymbolReader.cs @@ -0,0 +1,680 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; +using System.Runtime.InteropServices; + +namespace SOS +{ + internal class SymbolReader + { + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct DebugInfo + { + public int lineNumber; + public int ilOffset; + public string fileName; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MethodDebugInfo + { + public IntPtr points; + public int size; + } + + /// <summary> + /// Read memory callback + /// </summary> + /// <returns>number of bytes read or 0 for error</returns> + internal unsafe delegate int ReadMemoryDelegate(IntPtr address, byte* buffer, int count); + + private sealed class OpenedReader : IDisposable + { + public readonly MetadataReaderProvider Provider; + public readonly MetadataReader Reader; + + public OpenedReader(MetadataReaderProvider provider, MetadataReader reader) + { + Debug.Assert(provider != null); + Debug.Assert(reader != null); + + Provider = provider; + Reader = reader; + } + + public void Dispose() => Provider.Dispose(); + } + + /// <summary> + /// Stream implementation to read debugger target memory for in-memory PDBs + /// </summary> + private class TargetStream : Stream + { + readonly IntPtr _address; + readonly ReadMemoryDelegate _readMemory; + + public override long Position { get; set; } + public override long Length { get; } + public override bool CanSeek { get { return true; } } + public override bool CanRead { get { return true; } } + public override bool CanWrite { get { return false; } } + + public TargetStream(IntPtr address, int size, ReadMemoryDelegate readMemory) + : base() + { + _address = address; + _readMemory = readMemory; + Length = size; + Position = 0; + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (Position + count > Length) + { + throw new ArgumentOutOfRangeException(); + } + unsafe + { + fixed (byte* p = &buffer[offset]) + { + int read = _readMemory(new IntPtr(_address.ToInt64() + Position), p, count); + Position += read; + return read; + } + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + Position = offset; + break; + case SeekOrigin.End: + Position = Length + offset; + break; + case SeekOrigin.Current: + Position += offset; + break; + } + return Position; + } + + public override void Flush() + { + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + } + + /// <summary> + /// Checks availability of debugging information for given assembly. + /// </summary> + /// <param name="assemblyPath"> + /// File path of the assembly or null if the module is in-memory or dynamic (generated by Reflection.Emit) + /// </param> + /// <param name="isFileLayout">type of in-memory PE layout, if true, file based layout otherwise, loaded layout</param> + /// <param name="loadedPeAddress"> + /// Loaded PE image address or zero if the module is dynamic (generated by Reflection.Emit). + /// Dynamic modules have their PDBs (if any) generated to an in-memory stream + /// (pointed to by <paramref name="inMemoryPdbAddress"/> and <paramref name="inMemoryPdbSize"/>). + /// </param> + /// <param name="loadedPeSize">loaded PE image size</param> + /// <param name="inMemoryPdbAddress">in memory PDB address or zero</param> + /// <param name="inMemoryPdbSize">in memory PDB size</param> + /// <returns>Symbol reader handle or zero if error</returns> + internal static IntPtr LoadSymbolsForModule(string assemblyPath, bool isFileLayout, IntPtr loadedPeAddress, int loadedPeSize, + IntPtr inMemoryPdbAddress, int inMemoryPdbSize, ReadMemoryDelegate readMemory) + { + TargetStream peStream = null; + if (assemblyPath == null && loadedPeAddress != IntPtr.Zero) + { + peStream = new TargetStream(loadedPeAddress, loadedPeSize, readMemory); + } + TargetStream pdbStream = null; + if (inMemoryPdbAddress != IntPtr.Zero) + { + pdbStream = new TargetStream(inMemoryPdbAddress, inMemoryPdbSize, readMemory); + } + OpenedReader openedReader = GetReader(assemblyPath, isFileLayout, peStream, pdbStream); + if (openedReader == null) + return IntPtr.Zero; + + GCHandle gch = GCHandle.Alloc(openedReader); + return GCHandle.ToIntPtr(gch); + } + + /// <summary> + /// Cleanup and dispose of symbol reader handle + /// </summary> + /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param> + internal static void Dispose(IntPtr symbolReaderHandle) + { + Debug.Assert(symbolReaderHandle != IntPtr.Zero); + try + { + GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle); + ((OpenedReader)gch.Target).Dispose(); + gch.Free(); + } + catch + { + } + } + + /// <summary> + /// Returns method token and IL offset for given source line number. + /// </summary> + /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param> + /// <param name="filePath">source file name and path</param> + /// <param name="lineNumber">source line number</param> + /// <param name="methodToken">method token return</param> + /// <param name="ilOffset">IL offset return</param> + /// <returns> true if information is available</returns> + internal static bool ResolveSequencePoint(IntPtr symbolReaderHandle, string filePath, int lineNumber, out int methodToken, out int ilOffset) + { + Debug.Assert(symbolReaderHandle != IntPtr.Zero); + methodToken = 0; + ilOffset = 0; + + GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle); + MetadataReader reader = ((OpenedReader)gch.Target).Reader; + + try + { + string fileName = Path.GetFileName(filePath); + foreach (MethodDebugInformationHandle methodDebugInformationHandle in reader.MethodDebugInformation) + { + MethodDebugInformation methodDebugInfo = reader.GetMethodDebugInformation(methodDebugInformationHandle); + SequencePointCollection sequencePoints = methodDebugInfo.GetSequencePoints(); + foreach (SequencePoint point in sequencePoints) + { + string sourceName = reader.GetString(reader.GetDocument(point.Document).Name); + if (point.StartLine == lineNumber && Path.GetFileName(sourceName) == fileName) + { + methodToken = MetadataTokens.GetToken(methodDebugInformationHandle.ToDefinitionHandle()); + ilOffset = point.Offset; + return true; + } + } + } + } + catch + { + } + return false; + } + + /// <summary> + /// Returns source line number and source file name for given IL offset and method token. + /// </summary> + /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param> + /// <param name="methodToken">method token</param> + /// <param name="ilOffset">IL offset</param> + /// <param name="lineNumber">source line number return</param> + /// <param name="fileName">source file name return</param> + /// <returns> true if information is available</returns> + internal static bool GetLineByILOffset(IntPtr symbolReaderHandle, int methodToken, long ilOffset, out int lineNumber, out IntPtr fileName) + { + lineNumber = 0; + fileName = IntPtr.Zero; + + string sourceFileName = null; + + if (!GetSourceLineByILOffset(symbolReaderHandle, methodToken, ilOffset, out lineNumber, out sourceFileName)) + { + return false; + } + fileName = Marshal.StringToBSTR(sourceFileName); + sourceFileName = null; + return true; + } + + /// <summary> + /// Helper method to return source line number and source file name for given IL offset and method token. + /// </summary> + /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param> + /// <param name="methodToken">method token</param> + /// <param name="ilOffset">IL offset</param> + /// <param name="lineNumber">source line number return</param> + /// <param name="fileName">source file name return</param> + /// <returns> true if information is available</returns> + private static bool GetSourceLineByILOffset(IntPtr symbolReaderHandle, int methodToken, long ilOffset, out int lineNumber, out string fileName) + { + Debug.Assert(symbolReaderHandle != IntPtr.Zero); + lineNumber = 0; + fileName = null; + + GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle); + MetadataReader reader = ((OpenedReader)gch.Target).Reader; + + try + { + Handle handle = MetadataTokens.Handle(methodToken); + if (handle.Kind != HandleKind.MethodDefinition) + return false; + + MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle(); + MethodDebugInformation methodDebugInfo = reader.GetMethodDebugInformation(methodDebugHandle); + SequencePointCollection sequencePoints = methodDebugInfo.GetSequencePoints(); + + SequencePoint nearestPoint = sequencePoints.GetEnumerator().Current; + foreach (SequencePoint point in sequencePoints) + { + if (point.Offset < ilOffset) + { + nearestPoint = point; + } + else + { + if (point.Offset == ilOffset) + nearestPoint = point; + + if (nearestPoint.StartLine == 0 || nearestPoint.StartLine == SequencePoint.HiddenLine) + return false; + + lineNumber = nearestPoint.StartLine; + fileName = reader.GetString(reader.GetDocument(nearestPoint.Document).Name); + return true; + } + } + } + catch + { + } + return false; + } + + /// <summary> + /// Returns local variable name for given local index and IL offset. + /// </summary> + /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param> + /// <param name="methodToken">method token</param> + /// <param name="localIndex">local variable index</param> + /// <param name="localVarName">local variable name return</param> + /// <returns>true if name has been found</returns> + internal static bool GetLocalVariableName(IntPtr symbolReaderHandle, int methodToken, int localIndex, out IntPtr localVarName) + { + localVarName = IntPtr.Zero; + + string localVar = null; + if (!GetLocalVariableByIndex(symbolReaderHandle, methodToken, localIndex, out localVar)) + return false; + + localVarName = Marshal.StringToBSTR(localVar); + localVar = null; + return true; + } + + /// <summary> + /// Helper method to return local variable name for given local index and IL offset. + /// </summary> + /// <param name="symbolReaderHandle">symbol reader handle returned by LoadSymbolsForModule</param> + /// <param name="methodToken">method token</param> + /// <param name="localIndex">local variable index</param> + /// <param name="localVarName">local variable name return</param> + /// <returns>true if name has been found</returns> + internal static bool GetLocalVariableByIndex(IntPtr symbolReaderHandle, int methodToken, int localIndex, out string localVarName) + { + Debug.Assert(symbolReaderHandle != IntPtr.Zero); + localVarName = null; + + GCHandle gch = GCHandle.FromIntPtr(symbolReaderHandle); + MetadataReader reader = ((OpenedReader)gch.Target).Reader; + + try + { + Handle handle = MetadataTokens.Handle(methodToken); + if (handle.Kind != HandleKind.MethodDefinition) + return false; + + MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle(); + LocalScopeHandleCollection localScopes = reader.GetLocalScopes(methodDebugHandle); + foreach (LocalScopeHandle scopeHandle in localScopes) + { + LocalScope scope = reader.GetLocalScope(scopeHandle); + LocalVariableHandleCollection localVars = scope.GetLocalVariables(); + foreach (LocalVariableHandle varHandle in localVars) + { + LocalVariable localVar = reader.GetLocalVariable(varHandle); + if (localVar.Index == localIndex) + { + if (localVar.Attributes == LocalVariableAttributes.DebuggerHidden) + return false; + + localVarName = reader.GetString(localVar.Name); + return true; + } + } + } + } + catch + { + } + return false; + } + + /// <summary> + /// Returns source name, line numbers and IL offsets for given method token. + /// </summary> + /// <param name="assemblyPath">file path of the assembly</param> + /// <param name="methodToken">method token</param> + /// <param name="debugInfo">structure with debug information return</param> + /// <returns>true if information is available</returns> + /// <remarks>used by the gdb JIT support (not SOS). Does not support in-memory PEs or PDBs</remarks> + internal static bool GetInfoForMethod(string assemblyPath, int methodToken, ref MethodDebugInfo debugInfo) + { + List<DebugInfo> points = null; + + if (!GetDebugInfoForMethod(assemblyPath, methodToken, out points)) + { + return false; + } + var structSize = Marshal.SizeOf<DebugInfo>(); + + debugInfo.size = points.Count; + var ptr = debugInfo.points; + + foreach (var info in points) + { + Marshal.StructureToPtr(info, ptr, false); + ptr = (IntPtr)(ptr.ToInt64() + structSize); + } + return true; + } + + /// <summary> + /// Helper method to return source name, line numbers and IL offsets for given method token. + /// </summary> + /// <param name="assemblyPath">file path of the assembly</param> + /// <param name="methodToken">method token</param> + /// <param name="points">list of debug information for each sequence point return</param> + /// <returns>true if information is available</returns> + /// <remarks>used by the gdb JIT support (not SOS). Does not support in-memory PEs or PDBs</remarks> + private static bool GetDebugInfoForMethod(string assemblyPath, int methodToken, out List<DebugInfo> points) + { + points = null; + + OpenedReader openedReader = GetReader(assemblyPath, isFileLayout: true, peStream: null, pdbStream: null); + if (openedReader == null) + return false; + + using (openedReader) + { + try + { + Handle handle = MetadataTokens.Handle(methodToken); + if (handle.Kind != HandleKind.MethodDefinition) + return false; + + points = new List<DebugInfo>(); + MethodDebugInformationHandle methodDebugHandle = ((MethodDefinitionHandle)handle).ToDebugInformationHandle(); + MethodDebugInformation methodDebugInfo = openedReader.Reader.GetMethodDebugInformation(methodDebugHandle); + SequencePointCollection sequencePoints = methodDebugInfo.GetSequencePoints(); + + foreach (SequencePoint point in sequencePoints) + { + if (point.StartLine == 0 || point.StartLine == SequencePoint.HiddenLine) + continue; + + DebugInfo debugInfo = new DebugInfo(); + debugInfo.lineNumber = point.StartLine; + debugInfo.fileName = openedReader.Reader.GetString(openedReader.Reader.GetDocument(point.Document).Name); + debugInfo.ilOffset = point.Offset; + points.Add(debugInfo); + } + } + catch + { + return false; + } + } + return true; + } + + /// <summary> + /// Returns the portable PDB reader for the assembly path + /// </summary> + /// <param name="assemblyPath">file path of the assembly or null if the module is in-memory or dynamic</param> + /// <param name="isFileLayout">type of in-memory PE layout, if true, file based layout otherwise, loaded layout</param> + /// <param name="peStream">optional in-memory PE stream</param> + /// <param name="pdbStream">optional in-memory PDB stream</param> + /// <returns>reader/provider wrapper instance</returns> + /// <remarks> + /// Assumes that neither PE image nor PDB loaded into memory can be unloaded or moved around. + /// </remarks> + private static OpenedReader GetReader(string assemblyPath, bool isFileLayout, Stream peStream, Stream pdbStream) + { + return (pdbStream != null) ? TryOpenReaderForInMemoryPdb(pdbStream) : TryOpenReaderFromAssembly(assemblyPath, isFileLayout, peStream); + } + + private static OpenedReader TryOpenReaderForInMemoryPdb(Stream pdbStream) + { + Debug.Assert(pdbStream != null); + + byte[] buffer = new byte[sizeof(uint)]; + if (pdbStream.Read(buffer, 0, sizeof(uint)) != sizeof(uint)) + { + return null; + } + uint signature = BitConverter.ToUInt32(buffer, 0); + + // quick check to avoid throwing exceptions below in common cases: + const uint ManagedMetadataSignature = 0x424A5342; + if (signature != ManagedMetadataSignature) + { + // not a Portable PDB + return null; + } + + OpenedReader result = null; + MetadataReaderProvider provider = null; + try + { + pdbStream.Position = 0; + provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); + result = new OpenedReader(provider, provider.GetMetadataReader()); + } + catch (BadImageFormatException) + { + return null; + } + finally + { + if (result == null) + { + provider?.Dispose(); + } + } + + return result; + } + + private static OpenedReader TryOpenReaderFromAssembly(string assemblyPath, bool isFileLayout, Stream peStream) + { + if (assemblyPath == null && peStream == null) + return null; + + PEStreamOptions options = isFileLayout ? PEStreamOptions.Default : PEStreamOptions.IsLoadedImage; + if (peStream == null) + { + peStream = TryOpenFile(assemblyPath); + if (peStream == null) + return null; + + options = PEStreamOptions.Default; + } + + try + { + using (var peReader = new PEReader(peStream, options)) + { + DebugDirectoryEntry codeViewEntry, embeddedPdbEntry; + ReadPortableDebugTableEntries(peReader, out codeViewEntry, out embeddedPdbEntry); + + // First try .pdb file specified in CodeView data (we prefer .pdb file on disk over embedded PDB + // since embedded PDB needs decompression which is less efficient than memory-mapping the file). + if (codeViewEntry.DataSize != 0) + { + var result = TryOpenReaderFromCodeView(peReader, codeViewEntry, assemblyPath); + if (result != null) + { + return result; + } + } + + // if it failed try Embedded Portable PDB (if available): + if (embeddedPdbEntry.DataSize != 0) + { + return TryOpenReaderFromEmbeddedPdb(peReader, embeddedPdbEntry); + } + } + } + catch (Exception e) when (e is BadImageFormatException || e is IOException) + { + // nop + } + + return null; + } + + private static void ReadPortableDebugTableEntries(PEReader peReader, out DebugDirectoryEntry codeViewEntry, out DebugDirectoryEntry embeddedPdbEntry) + { + // See spec: https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PE-COFF.md + + codeViewEntry = default(DebugDirectoryEntry); + embeddedPdbEntry = default(DebugDirectoryEntry); + + foreach (DebugDirectoryEntry entry in peReader.ReadDebugDirectory()) + { + if (entry.Type == DebugDirectoryEntryType.CodeView) + { + const ushort PortableCodeViewVersionMagic = 0x504d; + if (entry.MinorVersion != PortableCodeViewVersionMagic) + { + continue; + } + + codeViewEntry = entry; + } + else if (entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb) + { + embeddedPdbEntry = entry; + } + } + } + + private static OpenedReader TryOpenReaderFromCodeView(PEReader peReader, DebugDirectoryEntry codeViewEntry, string assemblyPath) + { + OpenedReader result = null; + MetadataReaderProvider provider = null; + try + { + var data = peReader.ReadCodeViewDebugDirectoryData(codeViewEntry); + + string pdbPath = data.Path; + if (assemblyPath != null) + { + try + { + pdbPath = Path.Combine(Path.GetDirectoryName(assemblyPath), Path.GetFileName(pdbPath)); + } + catch + { + // invalid characters in CodeView path + return null; + } + } + + var pdbStream = TryOpenFile(pdbPath); + if (pdbStream == null) + { + return null; + } + + provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream); + var reader = provider.GetMetadataReader(); + + // Validate that the PDB matches the assembly version + if (data.Age == 1 && new BlobContentId(reader.DebugMetadataHeader.Id) == new BlobContentId(data.Guid, codeViewEntry.Stamp)) + { + result = new OpenedReader(provider, reader); + } + } + catch (Exception e) when (e is BadImageFormatException || e is IOException) + { + return null; + } + finally + { + if (result == null) + { + provider?.Dispose(); + } + } + + return result; + } + + private static OpenedReader TryOpenReaderFromEmbeddedPdb(PEReader peReader, DebugDirectoryEntry embeddedPdbEntry) + { + OpenedReader result = null; + MetadataReaderProvider provider = null; + + try + { + // TODO: We might want to cache this provider globally (across stack traces), + // since decompressing embedded PDB takes some time. + provider = peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedPdbEntry); + result = new OpenedReader(provider, provider.GetMetadataReader()); + } + catch (Exception e) when (e is BadImageFormatException || e is IOException) + { + return null; + } + finally + { + if (result == null) + { + provider?.Dispose(); + } + } + + return result; + } + + private static Stream TryOpenFile(string path) + { + if (!File.Exists(path)) + { + return null; + } + try + { + return File.OpenRead(path); + } + catch + { + return null; + } + } + } +} diff --git a/src/ToolBox/SOS/NETCore/project.json b/src/ToolBox/SOS/NETCore/project.json new file mode 100644 index 0000000000..e9e4f0999f --- /dev/null +++ b/src/ToolBox/SOS/NETCore/project.json @@ -0,0 +1,20 @@ +{ + "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1", + "System.IO.FileSystem": "4.0.1", + "System.Runtime.InteropServices": "4.1.0", + "System.Reflection.Metadata": "1.4.1-beta-24417-02" + }, + "frameworks": { + "netcoreapp1.0": {} + }, + "runtimes": { + "win7-x86": {}, + "win7-x64": {}, + "ubuntu.14.04-x64": {}, + "osx.10.10-x64": {}, + "centos.7-x64": {}, + "rhel.7-x64": {}, + "debian.8-x64": {} + } +} diff --git a/src/ToolBox/SOS/Strike/CMakeLists.txt b/src/ToolBox/SOS/Strike/CMakeLists.txt index eb3d94cf37..5d25865780 100644 --- a/src/ToolBox/SOS/Strike/CMakeLists.txt +++ b/src/ToolBox/SOS/Strike/CMakeLists.txt @@ -92,6 +92,7 @@ if(WIN32) kernel32.lib user32.lib ole32.lib + oleaut32.lib dbghelp.lib uuid.lib version.lib diff --git a/src/ToolBox/SOS/Strike/disasmARM.cpp b/src/ToolBox/SOS/Strike/disasmARM.cpp index fc51e8c8a6..82173558fd 100644 --- a/src/ToolBox/SOS/Strike/disasmARM.cpp +++ b/src/ToolBox/SOS/Strike/disasmARM.cpp @@ -365,7 +365,7 @@ void ARMMachine::Unassembly ( bool fLastWasMovW = false; INT_PTR lowbits = 0; ULONG curLine = -1; - char filename[MAX_PATH_FNAME+1]; + WCHAR filename[MAX_LONGPATH]; ULONG linenum; while (PC < PCEnd) @@ -375,13 +375,12 @@ void ARMMachine::Unassembly ( // Print out line numbers if needed if (!bSuppressLines - && SUCCEEDED(GetLineByOffset(TO_CDADDR(PC), - &linenum, filename, MAX_PATH_FNAME+1))) + && SUCCEEDED(GetLineByOffset(TO_CDADDR(PC), &linenum, filename, MAX_LONGPATH))) { if (linenum != curLine) { curLine = linenum; - ExtOut("\n%s @ %d:\n", filename, linenum); + ExtOut("\n%S @ %d:\n", filename, linenum); } } diff --git a/src/ToolBox/SOS/Strike/disasmARM64.cpp b/src/ToolBox/SOS/Strike/disasmARM64.cpp index 2629e6d2f9..6a19fc9377 100644 --- a/src/ToolBox/SOS/Strike/disasmARM64.cpp +++ b/src/ToolBox/SOS/Strike/disasmARM64.cpp @@ -163,7 +163,7 @@ void ARM64Machine::Unassembly ( char line[1024]; ULONG lineNum; ULONG curLine = -1; - char fileName[MAX_PATH_FNAME+1]; + WCHAR fileName[MAX_LONGPATH]; char *ptr; INT_PTR accumulatedConstant = 0; BOOL loBitsSet = FALSE; @@ -203,18 +203,18 @@ void ARM64Machine::Unassembly ( // This is the new instruction - if (IsInterrupt()) return; // // Print out line numbers if needed // - if (!bSuppressLines && SUCCEEDED(GetLineByOffset(TO_CDADDR(currentPC), &lineNum, fileName, MAX_PATH_FNAME+1))) + if (!bSuppressLines && + SUCCEEDED(GetLineByOffset(TO_CDADDR(currentPC), &lineNum, fileName, MAX_LONGPATH))) { if (lineNum != curLine) { curLine = lineNum; - ExtOut("\n%s @ %d:\n", fileName, lineNum); + ExtOut("\n%S @ %d:\n", fileName, lineNum); } } diff --git a/src/ToolBox/SOS/Strike/disasmX86.cpp b/src/ToolBox/SOS/Strike/disasmX86.cpp index d802ebfbfc..36a08d20a3 100644 --- a/src/ToolBox/SOS/Strike/disasmX86.cpp +++ b/src/ToolBox/SOS/Strike/disasmX86.cpp @@ -522,7 +522,7 @@ void char *ptr; ULONG curLine = -1; - char filename[MAX_PATH_FNAME+1]; + WCHAR filename[MAX_LONGPATH]; ULONG linenum; while (IP < IPEnd) @@ -532,13 +532,12 @@ void // Print out line numbers if needed if (!bSuppressLines - && SUCCEEDED(GetLineByOffset(TO_CDADDR(IP), - &linenum, filename, MAX_PATH_FNAME+1))) + && SUCCEEDED(GetLineByOffset(TO_CDADDR(IP), &linenum, filename, MAX_LONGPATH))) { if (linenum != curLine) { curLine = linenum; - ExtOut("\n%s @ %d:\n", filename, linenum); + ExtOut("\n%S @ %d:\n", filename, linenum); } } diff --git a/src/ToolBox/SOS/Strike/strike.cpp b/src/ToolBox/SOS/Strike/strike.cpp index 3164c2c0b7..731e2f505d 100644 --- a/src/ToolBox/SOS/Strike/strike.cpp +++ b/src/ToolBox/SOS/Strike/strike.cpp @@ -164,15 +164,17 @@ HMODULE g_hInstance = NULL; #pragma warning(disable:4189) // local variable is initialized but not referenced #endif - +#ifdef FEATURE_PAL +#define SOSPrefix "" +#else +#define SOSPrefix "!" +#endif #if defined _X86_ && !defined FEATURE_PAL // disable FPO for X86 builds #pragma optimize("y", off) #endif - - #undef assert #ifdef _MSC_VER @@ -297,7 +299,7 @@ DECLARE_API(IP2MD) DMLOut("MethodDesc: %s\n", DMLMethodDesc(pMD)); DumpMDInfo(TO_TADDR(pMD), cdaStart, FALSE /* fStackTraceFormat */); - char filename[MAX_PATH_FNAME+1]; + WCHAR filename[MAX_LONGPATH]; ULONG linenum; // symlines will be non-zero only if SYMOPT_LOAD_LINES was set in the symbol options ULONG symlines = 0; @@ -306,13 +308,10 @@ DECLARE_API(IP2MD) symlines &= SYMOPT_LOAD_LINES; } - if (symlines != 0 - && SUCCEEDED(GetLineByOffset(TO_CDADDR(IP), - &linenum, - filename, - MAX_PATH_FNAME+1))) + if (symlines != 0 && + SUCCEEDED(GetLineByOffset(TO_CDADDR(IP), &linenum, filename, _countof(filename)))) { - ExtOut("Source file: %s @ %d\n", filename, linenum); + ExtOut("Source file: %S @ %d\n", filename, linenum); } return Status; @@ -2305,11 +2304,12 @@ size_t FormatGeneratedException (DWORD_PTR dataPtr, // or did not update so (when ste is an explicit frames), do not update wszBuffer if (Status == S_OK) { - char filename[MAX_LONGPATH+1] = ""; + WCHAR filename[MAX_LONGPATH] = W(""); ULONG linenum = 0; - if (bLineNumbers && SUCCEEDED(GetLineByOffset(TO_CDADDR(ste.ip), &linenum, filename, _countof(filename)))) + if (bLineNumbers && + SUCCEEDED(GetLineByOffset(TO_CDADDR(ste.ip), &linenum, filename, _countof(filename)))) { - swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W(" %s [%S @ %d]\n"), so.String(), filename, linenum); + swprintf_s(wszLineBuffer, _countof(wszLineBuffer), W(" %s [%s @ %d]\n"), so.String(), filename, linenum); } else { @@ -6278,7 +6278,7 @@ public: { PendingBreakpoint *pCur = m_breakpoints; size_t iBreakpointIndex = 1; - ExtOut("!bpmd pending breakpoint list\n Breakpoint index - Location, ModuleID, Method Token\n"); + ExtOut(SOSPrefix "bpmd pending breakpoint list\n Breakpoint index - Location, ModuleID, Method Token\n"); while(pCur) { //windbg likes to format %p as always being 64 bits @@ -6360,49 +6360,14 @@ public: HRESULT LoadSymbolsForModule(TADDR mod, SymbolReader* pSymbolReader) { HRESULT Status = S_OK; - ToRelease<IXCLRDataModule> module; - IfFailRet(g_sos->GetModule(mod, &module)); + ToRelease<IXCLRDataModule> pModule; + IfFailRet(g_sos->GetModule(mod, &pModule)); ToRelease<IMetaDataImport> pMDImport = NULL; - IfFailRet(module->QueryInterface(IID_IMetaDataImport, (LPVOID *) &pMDImport)); - - WCHAR wszNameBuffer[MAX_LONGPATH]; - ULONG32 nameLen = 0; - if(FAILED(Status = module->GetFileName(MAX_LONGPATH, &nameLen, wszNameBuffer))) - { - ExtOut("SOS error: IXCLRDataModule->GetFileName failed hr=0x%x\n", wszNameBuffer); - return Status; - } - - //get a pointer to just the filename (the portion after the last backslash) - WCHAR* pModuleFilename = wszNameBuffer; - WCHAR* pSlash = _wcschr(pModuleFilename, DIRECTORY_SEPARATOR_CHAR_W); - while(pSlash != NULL) - { - pModuleFilename = pSlash+1; - pSlash = _wcschr(pModuleFilename, DIRECTORY_SEPARATOR_CHAR_W); - } -#ifndef FEATURE_PAL + IfFailRet(pModule->QueryInterface(IID_IMetaDataImport, (LPVOID *) &pMDImport)); - ImageInfo ii; - if(FAILED(Status = GetClrModuleImages(module, CLRDATA_MODULE_PE_FILE, &ii))) - { - ExtOut("SOS error: GetClrModuleImages failed hr=0x%x\n", Status); - return Status; - } + IfFailRet(pSymbolReader->LoadSymbols(pMDImport, pModule)); - if(FAILED(Status = pSymbolReader->LoadSymbols(pMDImport, ii.modBase, pModuleFilename, FALSE)) && - FAILED(pSymbolReader->LoadSymbols(pMDImport, ii.modBase, pModuleFilename, TRUE))) - { - ExtOut("SOS warning: No symbols for module %S, source line breakpoints in this module will not bind hr=0x%x\n", wszNameBuffer, Status); - return S_FALSE; // not finding symbols is a typical case - } -#else - if(FAILED(Status = pSymbolReader->LoadSymbols(pMDImport, 0, pModuleFilename, FALSE))) - { - return S_FALSE; - } -#endif // FEATURE_PAL return S_OK; } @@ -6425,15 +6390,14 @@ public: HRESULT ResolvePendingNonModuleBoundBreakpoint(__in_z WCHAR* pModuleName, __in_z WCHAR* pMethodName, TADDR mod, DWORD ilOffset) { - int numModule; + HRESULT Status = S_OK; char szName[mdNameLen]; + int numModule; ToRelease<IXCLRDataModule> module; - HRESULT Status = S_OK; IfFailRet(g_sos->GetModule(mod, &module)); - WideCharToMultiByte(CP_ACP, 0, pModuleName, (int) (_wcslen(pModuleName) + 1), - szName, mdNameLen, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, pModuleName, (int)(_wcslen(pModuleName) + 1), szName, mdNameLen, NULL, NULL); ArrayHolder<DWORD_PTR> moduleList = ModuleFromName(szName, &numModule); if (moduleList == NULL) @@ -6442,7 +6406,7 @@ public: return E_FAIL; } - for(int i=0;i<numModule;i++) + for (int i = 0; i < numModule; i++) { // If any one entry in moduleList matches, then the current PendingBreakpoint // is the right one. @@ -7026,7 +6990,7 @@ DECLARE_API(bpmd) if (IsDumpFile()) { - ExtOut("!bpmd is not supported on a dump file.\n"); + ExtOut(SOSPrefix "bpmd is not supported on a dump file.\n"); return Status; } @@ -7132,26 +7096,22 @@ DECLARE_API(bpmd) fBadParam = true; } if(nArg != 1) fBadParam = 1; -#ifdef FEATURE_PAL - if (!SymbolReader::SymbolReaderDllExists()) - { - ExtOut("Can't find dll for symbol reader."); - ExtOut("File name:Line number not supported\n"); - fBadParam = true; - } -#endif // FEATURE_PAL } } if (fBadParam || (commandsParsed != 1)) { - ExtOut("Usage: !bpmd -md <MethodDesc pointer>\n"); - ExtOut("Usage: !bpmd [-nofuturemodule] <module name> <managed function name> [<il offset>]\n"); - ExtOut("Usage: !bpmd <filename>:<line number>\n"); - ExtOut("Usage: !bpmd -list\n"); - ExtOut("Usage: !bpmd -clear <pending breakpoint number>\n"); - ExtOut("Usage: !bpmd -clearall\n"); + ExtOut("Usage: " SOSPrefix "bpmd -md <MethodDesc pointer>\n"); + ExtOut("Usage: " SOSPrefix "bpmd [-nofuturemodule] <module name> <managed function name> [<il offset>]\n"); + ExtOut("Usage: " SOSPrefix "bpmd <filename>:<line number>\n"); + ExtOut("Usage: " SOSPrefix "bpmd -list\n"); + ExtOut("Usage: " SOSPrefix "bpmd -clear <pending breakpoint number>\n"); + ExtOut("Usage: " SOSPrefix "bpmd -clearall\n"); +#ifdef FEATURE_PAL + ExtOut("See \"soshelp bpmd\" for more details.\n"); +#else ExtOut("See \"!help bpmd\" for more details.\n"); +#endif return Status; } @@ -7288,8 +7248,6 @@ DECLARE_API(bpmd) // for filename+line number only print extra info if symbols for this module are loaded (it can get quite noisy otherwise). if ((!fIsFilename) || (fIsFilename && symbolsLoaded == S_OK)) { - ExtOut("Found %d methods in module %p...\n", numMethods, moduleList[iModule]); - for (int i = 0; i < numMethods; i++) { if (pMDs[i] == MD_NOT_YET_LOADED) @@ -7319,6 +7277,11 @@ DECLARE_API(bpmd) g_bpoints.Add(Filename, lineNumber, NULL); } bNeedNotificationExceptions = TRUE; + + ULONG32 flags = 0; + g_clrData->GetOtherNotificationFlags(&flags); + flags |= (CLRDATA_NOTIFY_ON_MODULE_LOAD | CLRDATA_NOTIFY_ON_MODULE_UNLOAD); + g_clrData->SetOtherNotificationFlags(flags); } } else /* We were given a MethodDesc already */ @@ -9444,11 +9407,11 @@ DECLARE_API(Name2EE) if (nArg != 2) { - ExtOut("Usage: !Name2EE module_name item_name\n"); - ExtOut(" or !Name2EE module_name!item_name\n"); + ExtOut("Usage: " SOSPrefix "name2ee module_name item_name\n"); + ExtOut(" or " SOSPrefix "name2ee module_name!item_name\n"); ExtOut(" use * for module_name to search all loaded modules\n"); - ExtOut("Examples: !Name2EE mscorlib.dll System.String.ToString\n"); - ExtOut(" !Name2EE *!System.String\n"); + ExtOut("Examples: " SOSPrefix "name2ee mscorlib.dll System.String.ToString\n"); + ExtOut(" " SOSPrefix "name2ee *!System.String\n"); return Status; } @@ -10846,7 +10809,6 @@ DECLARE_API(GCHandleLeaks) class ClrStackImplWithICorDebug { private: - static HRESULT DereferenceAndUnboxValue(ICorDebugValue * pValue, ICorDebugValue** ppOutputValue, BOOL * pIsNull = NULL) { HRESULT Status = S_OK; @@ -10886,6 +10848,7 @@ private: (*ppOutputValue)->AddRef(); return S_OK; } + static BOOL ShouldExpandVariable(__in_z WCHAR* varToExpand, __in_z WCHAR* currentExpansion) { if(currentExpansion == NULL || varToExpand == NULL) return FALSE; @@ -10898,6 +10861,7 @@ private: return TRUE; } + static BOOL IsEnum(ICorDebugValue * pInputValue) { ToRelease<ICorDebugValue> pValue; @@ -10915,6 +10879,7 @@ private: return (_wcsncmp(baseTypeName, W("System.Enum"), 11) == 0); } + static HRESULT AddGenericArgs(ICorDebugType * pType, __inout_ecount(typeNameLen) WCHAR* typeName, ULONG typeNameLen) { bool isFirst = true; @@ -10946,6 +10911,7 @@ private: return S_OK; } + static HRESULT GetTypeOfValue(ICorDebugType * pType, __inout_ecount(typeNameLen) WCHAR* typeName, ULONG typeNameLen) { HRESULT Status = S_OK; @@ -11101,6 +11067,7 @@ private: } return S_OK; } + static HRESULT GetTypeOfValue(ICorDebugValue * pValue, __inout_ecount(typeNameLen) WCHAR* typeName, ULONG typeNameLen) { HRESULT Status = S_OK; @@ -11117,6 +11084,7 @@ private: return S_OK; } + static HRESULT PrintEnumValue(ICorDebugValue* pInputValue, BYTE* enumValue) { HRESULT Status = S_OK; @@ -11238,6 +11206,7 @@ private: return S_OK; } + static HRESULT PrintStringValue(ICorDebugValue * pValue) { HRESULT Status; @@ -11262,6 +11231,7 @@ private: return S_OK; } + static HRESULT PrintSzArrayValue(ICorDebugValue * pValue, ICorDebugILFrame * pILFrame, IMetaDataImport * pMD, int indent, __in_z WCHAR* varToExpand, __inout_ecount(currentExpansionSize) WCHAR* currentExpansion, DWORD currentExpansionSize, int currentFrame) { HRESULT Status = S_OK; @@ -11328,6 +11298,7 @@ private: return S_OK; } + static HRESULT PrintValue(ICorDebugValue * pInputValue, ICorDebugILFrame * pILFrame, IMetaDataImport * pMD, int indent, __in_z WCHAR* varToExpand, __inout_ecount(currentExpansionSize) WCHAR* currentExpansion, DWORD currentExpansionSize, int currentFrame) { HRESULT Status = S_OK; @@ -11479,6 +11450,7 @@ private: return S_OK; } + static HRESULT PrintParameters(BOOL bParams, BOOL bLocals, IMetaDataImport * pMD, mdTypeDef typeDef, mdMethodDef methodDef, ICorDebugILFrame * pILFrame, ICorDebugModule * pModule, __in_z WCHAR* varToExpand, int currentFrame) { HRESULT Status = S_OK; @@ -11726,11 +11698,6 @@ private: return S_OK; } - - - - - public: // This is the main worker function used if !clrstack is called with "-i" to indicate @@ -12204,7 +12171,7 @@ public: static void PrintNativeStackFrame(TableOutput out, PDEBUG_STACK_FRAME frame, BOOL bSuppressLines) { - char filename[MAX_PATH_FNAME + 1]; + char filename[MAX_LONGPATH + 1]; char symbol[1024]; ULONG64 displacement; @@ -14394,7 +14361,7 @@ void PrintHelp (__in_z LPCSTR pszCmdName) } // Find our line in the text file - char searchString[MAX_PATH_FNAME]; + char searchString[MAX_LONGPATH]; sprintf_s(searchString, _countof(searchString), "COMMAND: %s.", pszCmdName); LPSTR pStart = strstr(pText, searchString); diff --git a/src/ToolBox/SOS/Strike/util.cpp b/src/ToolBox/SOS/Strike/util.cpp index 45bcd213e1..9eec76e42c 100644 --- a/src/ToolBox/SOS/Strike/util.cpp +++ b/src/ToolBox/SOS/Strike/util.cpp @@ -43,20 +43,20 @@ char symBuffer[SYM_BUFFER_SIZE]; PIMAGEHLP_SYMBOL sym = (PIMAGEHLP_SYMBOL) symBuffer; #else - #include <sys/stat.h> #include <coreruncommon.h> #include <dlfcn.h> +#endif // !FEATURE_PAL + #include <coreclrhost.h> +#include <set> -void *SymbolReader::coreclrLib; -ResolveSequencePointDelegate SymbolReader::resolveSequencePointDelegate; LoadSymbolsForModuleDelegate SymbolReader::loadSymbolsForModuleDelegate; +DisposeDelegate SymbolReader::disposeDelegate; +ResolveSequencePointDelegate SymbolReader::resolveSequencePointDelegate; GetLocalVariableName SymbolReader::getLocalVariableNameDelegate; GetLineByILOffsetDelegate SymbolReader::getLineByILOffsetDelegate; -#endif // !FEATURE_PAL - const char * const CorElementTypeName[ELEMENT_TYPE_MAX]= { #define TYPEINFO(e,ns,c,s,g,ia,ip,if,im,gv) c, @@ -816,9 +816,6 @@ EEFLAVOR GetEEFlavor () BOOL IsDumpFile () { -#ifdef FEATURE_PAL - return FALSE; -#else static int g_fDumpFile = -1; if (g_fDumpFile == -1) { ULONG Class; @@ -830,7 +827,6 @@ BOOL IsDumpFile () g_fDumpFile = 0; } return g_fDumpFile != 0; -#endif //FEATURE_PAL } BOOL g_InMinidumpSafeMode = FALSE; @@ -2730,7 +2726,7 @@ DWORD_PTR *ModuleFromName(__in_opt LPSTR mName, int *numModule) return NULL; } - WCHAR StringData[MAX_PATH_FNAME]; + WCHAR StringData[MAX_LONGPATH]; char fileName[sizeof(StringData)/2]; // Search all domains to find a module @@ -2772,8 +2768,8 @@ DWORD_PTR *ModuleFromName(__in_opt LPSTR mName, int *numModule) ExtOut("Unable to get array of Assemblies for the given AppDomain..\n"); goto Failure; } - - for (int nAssem = 0;nAssem < appDomain.AssemblyCount;nAssem ++) + + for (int nAssem = 0; nAssem < appDomain.AssemblyCount; nAssem ++) { if (IsInterrupt()) { @@ -2794,8 +2790,8 @@ DWORD_PTR *ModuleFromName(__in_opt LPSTR mName, int *numModule) ExtOut("Failed to get the modules for the given assembly.\n"); goto Failure; } - - for (UINT nModule=0;nModule<assemblyData.ModuleCount;nModule++) + + for (UINT nModule = 0; nModule < assemblyData.ModuleCount; nModule++) { if (IsInterrupt()) { @@ -2813,8 +2809,10 @@ DWORD_PTR *ModuleFromName(__in_opt LPSTR mName, int *numModule) FileNameForModule ((DWORD_PTR)ModuleAddr, StringData); int m; - for (m = 0; StringData[m] != L'\0'; m ++) + for (m = 0; StringData[m] != L'\0'; m++) + { fileName[m] = (char)StringData[m]; + } fileName[m] = '\0'; if ((mName == NULL) || @@ -2822,8 +2820,7 @@ DWORD_PTR *ModuleFromName(__in_opt LPSTR mName, int *numModule) DebuggerModuleNamesMatch(ModuleData.File, mName) || IsFusionLoadedModule(fileName, mName)) { - AddToModuleList(moduleList, *numModule, maxList, - (DWORD_PTR)ModuleAddr); + AddToModuleList(moduleList, *numModule, maxList, (DWORD_PTR)ModuleAddr); } } @@ -3188,7 +3185,7 @@ void GetInfoFromModule (DWORD_PTR ModuleAddr, ULONG token, DWORD_PTR *ret) else ExtOut("Not JITTED yet. Use !bpmd -md %p to break on run.\n", SOS_PTR(md)); #else - ExtOut("Not JITTED yet. Use 'sos bpmd -md %p' to break on run.\n", SOS_PTR(md)); + ExtOut("Not JITTED yet. Use 'bpmd -md %p' to break on run.\n", SOS_PTR(md)); #endif } } @@ -4162,7 +4159,6 @@ void ResetGlobals(void) // Return Value: // HRESULT indicating success or failure // - HRESULT LoadClrDebugDll(void) { HRESULT hr = S_OK; @@ -4184,14 +4180,14 @@ HRESULT LoadClrDebugDll(void) { return CORDBG_E_MISSING_DEBUGGER_EXPORTS; } - PFN_CLRDataCreateInstance pCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance"); - if (pCLRDataCreateInstance == NULL) + PFN_CLRDataCreateInstance pfnCLRDataCreateInstance = (PFN_CLRDataCreateInstance)GetProcAddress(hdac, "CLRDataCreateInstance"); + if (pfnCLRDataCreateInstance == NULL) { FreeLibrary(hdac); return CORDBG_E_MISSING_DEBUGGER_EXPORTS; } ICLRDataTarget *target = new DataTarget(); - hr = pCLRDataCreateInstance(__uuidof(IXCLRDataProcess), target, (void**)&s_clrDataProcess); + hr = pfnCLRDataCreateInstance(__uuidof(IXCLRDataProcess), target, (void**)&s_clrDataProcess); if (FAILED(hr)) { s_clrDataProcess = NULL; @@ -5582,101 +5578,6 @@ NoOutputHolder::~NoOutputHolder() // // -// This function retrieves ImageInfo related to the module -// containing the addressed passed in "Base". -// -// NOTE: This doesn't work on xplat/PAL because the managed -// assembly PE isn't in the native debugger's module list. -// -HRESULT -GetImageFromBase( - ___in ULONG64 Base, - ___out ImageInfo* Image) -{ - ULONG modIdx = 0; - ULONG64 modBase = 0; - if (FAILED(g_ExtSymbols->GetModuleByOffset(Base, 0, &modIdx, &modBase))) - { - return E_FAIL; - } - - Image->modBase = modBase; - return S_OK; -} - -// -// Retrieve ImageInfo associated with the IXCLRDataModule instance -// passed in, and the extent type requested. -HRESULT -GetClrModuleImages( - ___in IXCLRDataModule* Module, - ___in CLRDataModuleExtentType DesiredType, - ___out ImageInfo* FirstAdd) -{ - HRESULT Status; - CLRDATA_ENUM EnumExtents; - - if (FirstAdd) - { - FirstAdd->modBase = 0; - } - - if ((Status = Module->StartEnumExtents(&EnumExtents)) != S_OK) - { - return FAILED(Status) ? Status : S_OK; - } - - CLRDATA_MODULE_EXTENT Extent; - - while (Module->EnumExtent(&EnumExtents, &Extent) == S_OK) - { - if ((DesiredType == CLRDATA_MODULE_OTHER) || (DesiredType == Extent.type)) - { - ImageInfo Image; - - if (FAILED(Status = GetImageFromBase(Extent.base, &Image))) - { - break; - } - - Status = S_OK; - if (FirstAdd) - { - *FirstAdd = Image; - break; - } - } - } - - Module->EndEnumExtents(EnumExtents); - return Status; -} - -// -// Retrieve ImageInfo associated with the IXCLRDataModule instance -// passed in. First look for NGENed module, second for IL modules. -HRESULT -FindClrModuleImage( - ___in IXCLRDataModule* Module, - ___out ImageInfo* Image) -{ - HRESULT Status; - - // Prefer the ngen image, but look for the base image if necessary. - if ((Status = GetClrModuleImages(Module, CLRDATA_MODULE_PREJIT_FILE, Image)) == S_OK && - Image->modBase != 0) - { - return S_OK; - } - if ((Status = GetClrModuleImages(Module, CLRDATA_MODULE_PE_FILE, Image)) == S_OK && - Image->modBase == 0) - { - Status = E_NOINTERFACE; - } - return Status; -} - -// // Retrieves the IXCLRDataMethodInstance* instance associated with the // passed in native offset. HRESULT @@ -5700,31 +5601,6 @@ GetClrMethodInstance( } // -// Retrieves the Token and ImageInfo associated with a managed method -// identified by the passed in IXCLRDataMethodInstance* instance. -HRESULT -GetMethodInstanceTokenAndScope( - ___in IXCLRDataMethodInstance* Method, - ___out mdMethodDef* MethodToken, - ___out ImageInfo* Image) -{ - HRESULT Status; - IXCLRDataModule* Module; - - if ((Status = Method->GetTokenAndScope(MethodToken, &Module)) != S_OK) - { - return Status; - } -#ifndef FEATURE_PAL - - Status = FindClrModuleImage(Module, Image); -#endif //FEATURE_PAL - - Module->Release(); - return Status; -} - -// // Enumerates over the IL address map associated with the passed in // managed method, and returns the highest non-epilog offset. HRESULT @@ -5797,162 +5673,76 @@ GetLastMethodIlOffset( // represent an "IL offset". HRESULT ConvertNativeToIlOffset( - ___in ULONG64 Native, - __in_opt IXCLRDataMethodInstance* MethodInst, - ___out ImageInfo* Image, - ___out mdMethodDef* MethodToken, - ___out PULONG32 MethodOffs) + ___in ULONG64 native, + ___out IXCLRDataModule** ppModule, + ___out mdMethodDef* methodToken, + ___out PULONG32 methodOffs) { + ToRelease<IXCLRDataMethodInstance> pMethodInst(NULL); HRESULT Status; - if (!MethodInst) + if ((Status = GetClrMethodInstance(native, &pMethodInst)) != S_OK) { - if ((Status = GetClrMethodInstance(Native, &MethodInst)) != S_OK) - { - return Status; - } - } - else - { - MethodInst->AddRef(); + return Status; } - if ((Status = MethodInst->GetILOffsetsByAddress(Native, 1, NULL, MethodOffs)) != S_OK) + if ((Status = pMethodInst->GetILOffsetsByAddress(native, 1, NULL, methodOffs)) != S_OK) { - *MethodOffs = 0; + *methodOffs = 0; } else { - switch((LONG)*MethodOffs) + switch((LONG)*methodOffs) { case CLRDATA_IL_OFFSET_NO_MAPPING: - MethodInst->Release(); return E_NOINTERFACE; case CLRDATA_IL_OFFSET_PROLOG: // Treat all of the prologue as part of // the first source line. - *MethodOffs = 0; + *methodOffs = 0; break; case CLRDATA_IL_OFFSET_EPILOG: // Back up until we find the last real // IL offset. - if ((Status = GetLastMethodIlOffset(MethodInst, MethodOffs)) != S_OK) + if ((Status = GetLastMethodIlOffset(pMethodInst, methodOffs)) != S_OK) { - MethodInst->Release(); return Status; } break; } } - Status = GetMethodInstanceTokenAndScope(MethodInst, MethodToken, Image); - - MethodInst->Release(); - - return Status; + return pMethodInst->GetTokenAndScope(methodToken, ppModule); } // Based on a native offset, passed in the first argument this function // identifies the corresponding source file name and line number. HRESULT GetLineByOffset( - ___in ULONG64 Offset, + ___in ULONG64 offset, ___out ULONG *pLinenum, - __out_ecount(cbFileName) LPSTR lpszFileName, - ___in ULONG cbFileName) + __out_ecount(cchFileName) WCHAR* pwszFileName, + ___in ULONG cchFileName) { - HRESULT hr = S_OK; - ULONG64 displacement = 0; - - // first let's try it the hard way, this will work with the public debuggers - { - ImageInfo Image = {0}; - ULONG64 modBase = 0; - ULONG32 MethodToken; - ULONG32 MethodOffs; - ULONG64 IlOffset; - -#ifndef FEATURE_PAL - ToRelease<IDebugSymbols3> spSym3(NULL); - if (FAILED(g_ExtSymbols->QueryInterface(__uuidof(IDebugSymbols3), (void**)&spSym3))) - { - hr = E_FAIL; - goto fallback; - } -#endif //!FEATURE_PAL + HRESULT Status = S_OK; + ULONG32 methodToken; + ULONG32 methodOffs; - // find the image, method token and IL offset that correspond - // to "Offset" - if ((hr = ConvertNativeToIlOffset(Offset, NULL, &Image, - &MethodToken, &MethodOffs)) != S_OK) - { - goto fallback; - } + // Find the image, method token and IL offset that correspond to "offset" + ToRelease<IXCLRDataModule> pModule(NULL); + IfFailRet(ConvertNativeToIlOffset(offset, &pModule, &methodToken, &methodOffs)); -#ifndef FEATURE_PAL - modBase = Image.modBase; - DEBUG_MODULE_AND_ID id; - DEBUG_SYMBOL_ENTRY symInfo; - if (FAILED(spSym3->GetSymbolEntryByToken(modBase, MethodToken, &id)) - || FAILED(spSym3->GetSymbolEntryInformation(&id, &symInfo))) - { - hr = E_FAIL; - goto fallback; - } + ToRelease<IMetaDataImport> pMDImport(NULL); + IfFailRet(pModule->QueryInterface(IID_IMetaDataImport, (LPVOID *) &pMDImport)); - IlOffset = symInfo.Offset + MethodOffs; -#else - // Source lines with 0xFEEFEE markers are filtered out on the managed side. - const String &moduleName = ModuleNameFromIP(TO_CDADDR(Offset)); - return SymbolReader::GetLineByILOffset(moduleName.c_str(), MethodToken, MethodOffs, pLinenum, lpszFileName, cbFileName); -#endif //!FEATURE_PAL - // - // Source maps for managed code can end - // up with special 0xFEEFEE markers that - // indicate don't-stop points. Try and - // filter those out. - // - for (ULONG SkipCount = 64; SkipCount > 0; SkipCount--) - { - if (FAILED(g_ExtSymbols->GetLineByOffset( - IlOffset, - pLinenum, - lpszFileName, - cbFileName, - NULL, - &displacement))) - { - hr = E_FAIL; - goto fallback; - } + SymbolReader symbolReader; + IfFailRet(symbolReader.LoadSymbols(pMDImport, pModule)); - if (*pLinenum == 0xfeefee) - { - ++IlOffset; - } - else - { - return S_OK; - } - } - - // Fall into the regular translation as a last-ditch effort. - Offset = IlOffset; - } - -fallback: - return g_ExtSymbols->GetLineByOffset( - Offset, - pLinenum, - lpszFileName, - cbFileName, - NULL, - &displacement); + return symbolReader.GetLineByILOffset(methodToken, methodOffs, pLinenum, pwszFileName, cchFileName); } - void TableOutput::ReInit(int numColumns, int defaultColumnWidth, Alignment alignmentDefault, int indent, int padding) { Clear(); @@ -6185,184 +5975,94 @@ HRESULT __stdcall PERvaMemoryReader::ReadExecutableAtRVA(DWORD relativeVirtualAd #endif // FEATURE_PAL -HRESULT SymbolReader::LoadSymbols(IMetaDataImport * pMD, ICorDebugModule * pModule) +HRESULT SymbolReader::LoadSymbols(___in IMetaDataImport* pMD, ___in ICorDebugModule* pModule) { HRESULT Status = S_OK; - if(m_pSymReader != NULL) return S_OK; - BOOL isDynamic = FALSE; BOOL isInMemory = FALSE; IfFailRet(pModule->IsDynamic(&isDynamic)); IfFailRet(pModule->IsInMemory(&isInMemory)); - if(isDynamic) + if (isDynamic) { - // Dynamic and in memory assemblies are a special case - // which we will ignore for now - // now - ExtOut("SOS Warning: Loading symbols for dynamic assemblies is not yet supported\n"); + // Dynamic and in memory assemblies are a special case which we will ignore for now + ExtWarn("SOS Warning: Loading symbols for dynamic assemblies is not yet supported\n"); return E_FAIL; } - ULONG64 baseAddress = 0; - IfFailRet(pModule->GetBaseAddress(&baseAddress)); + ULONG64 peAddress = 0; + ULONG32 peSize = 0; + IfFailRet(pModule->GetBaseAddress(&peAddress)); + IfFailRet(pModule->GetSize(&peSize)); ULONG32 len = 0; WCHAR moduleName[MAX_LONGPATH]; IfFailRet(pModule->GetName(_countof(moduleName), &len, moduleName)); - return LoadSymbols(pMD, baseAddress, moduleName, isInMemory); -} - -#ifdef FEATURE_PAL -bool SymbolReader::SymbolReaderDllExists() -{ - struct stat sb; - std::string SymbolReaderDll(SymbolReaderDllName); - SymbolReaderDll += ".dll"; - - return stat(SymbolReaderDll.c_str(), &sb) == 0; -} - -HRESULT SymbolReader::PrepareSymbolReader() -{ - static bool attemptedSymbolReaderPreparation = false; - if (attemptedSymbolReaderPreparation) +#ifndef FEATURE_PAL + if (SUCCEEDED(LoadSymbolsForWindowsPDB(pMD, peAddress, moduleName, isInMemory))) { - // If we already tried to set up the symbol reader, we won't try again. - return E_FAIL; + return S_OK; } +#endif // FEATURE_PAL + return LoadSymbolsForPortablePDB(moduleName, isInMemory, isInMemory, peAddress, peSize, 0, 0); +} - attemptedSymbolReaderPreparation = true; - - std::string absolutePath; - std::string coreClrPath = g_ExtServices->GetCoreClrDirectory(); - if (!GetAbsolutePath(coreClrPath.c_str(), absolutePath)) +HRESULT SymbolReader::LoadSymbols(___in IMetaDataImport* pMD, ___in IXCLRDataModule* pModule) +{ + DacpGetModuleData moduleData; + HRESULT hr = moduleData.Request(pModule); + if (FAILED(hr)) { - ExtErr("Error: fail to convert CLR files path to absolute path \n"); - return E_FAIL; + ExtOut("LoadSymbols moduleData.Request FAILED 0x%08x\n", hr); + return hr; } - coreClrPath.append("/"); - coreClrPath.append(coreClrDll); - coreclrLib = dlopen(coreClrPath.c_str(), RTLD_NOW | RTLD_LOCAL); - if (coreclrLib == nullptr) + if (moduleData.IsDynamic) { - ExtErr("Error: Fail to load %s\n", coreClrPath.c_str()); + ExtWarn("SOS Warning: Loading symbols for dynamic assemblies is not yet supported\n"); return E_FAIL; } - void *hostHandle; - unsigned int domainId; - coreclr_initialize_ptr initializeCoreCLR = - (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize"); - - // FIXME: We should shutdown coreclr when it is not needed - coreclr_shutdown_ptr shutdownCoreCLR = - (coreclr_shutdown_ptr)dlsym(coreclrLib, "coreclr_shutdown"); - - std::string tpaList; - AddFilesFromDirectoryToTpaList(absolutePath.c_str(), tpaList); - - const char *propertyKeys[] = { - "TRUSTED_PLATFORM_ASSEMBLIES", "APP_PATHS", "APP_NI_PATHS", - "NATIVE_DLL_SEARCH_DIRECTORIES", "AppDomainCompatSwitch"}; - - const char *propertyValues[] = {// TRUSTED_PLATFORM_ASSEMBLIES - tpaList.c_str(), - // APP_PATHS - absolutePath.c_str(), - // APP_NI_PATHS - absolutePath.c_str(), - // NATIVE_DLL_SEARCH_DIRECTORIES - absolutePath.c_str(), - // AppDomainCompatSwitch - "UseLatestBehaviorWhenTFMNotSpecified"}; - - std::string entryPointExecutablePath; - if (!GetEntrypointExecutableAbsolutePath(entryPointExecutablePath)) + ArrayHolder<WCHAR> pModuleName = new WCHAR[MAX_LONGPATH + 1]; + ULONG32 nameLen = 0; + hr = pModule->GetFileName(MAX_LONGPATH, &nameLen, pModuleName); + if (FAILED(hr)) { - ExtErr("Could not get full path to current executable"); - return E_FAIL; + ExtOut("LoadSymbols: IXCLRDataModule->GetFileName FAILED 0x%08x\n", hr); + return hr; } - HRESULT Status = initializeCoreCLR(entryPointExecutablePath.c_str(), "soscorerun", - sizeof(propertyKeys) / sizeof(propertyKeys[0]), - propertyKeys, propertyValues, &hostHandle, &domainId); - if (Status != S_OK) +#ifndef FEATURE_PAL + // TODO: in-memory windows PDB not supported + hr = LoadSymbolsForWindowsPDB(pMD, moduleData.LoadedPEAddress, pModuleName, moduleData.IsFileLayout); + if (SUCCEEDED(hr)) { - ExtErr("Error: Fail to initialize CoreCLR\n"); - return Status; + return hr; } +#endif // FEATURE_PAL - coreclr_create_delegate_ptr CreateDelegate = - (coreclr_create_delegate_ptr)dlsym(coreclrLib, "coreclr_create_delegate"); - - IfFailRet(CreateDelegate(hostHandle, domainId, SymbolReaderDllName, - SymbolReaderClassName, "ResolveSequencePoint", - (void **)&resolveSequencePointDelegate)); - IfFailRet(CreateDelegate(hostHandle, domainId, SymbolReaderDllName, - SymbolReaderClassName, "LoadSymbolsForModule", - (void **)&loadSymbolsForModuleDelegate)); - IfFailRet(CreateDelegate(hostHandle, domainId, SymbolReaderDllName, - SymbolReaderClassName, "GetLocalVariableName", - (void **)&getLocalVariableNameDelegate)); - IfFailRet(CreateDelegate(hostHandle, domainId, SymbolReaderDllName, - SymbolReaderClassName, "GetLineByILOffset", - (void **)&getLineByILOffsetDelegate)); - return Status; + return LoadSymbolsForPortablePDB( + pModuleName, + moduleData.IsInMemory, + moduleData.IsFileLayout, + moduleData.LoadedPEAddress, + moduleData.LoadedPESize, + moduleData.InMemoryPdbAddress, + moduleData.InMemoryPdbSize); } -HRESULT SymbolReader::GetLineByILOffset(__in_z const char* szModuleName, mdMethodDef MethodToken, - ULONG64 IlOffset, ___out ULONG *pLinenum, - __out_ecount(cbFileName) LPSTR lpszFileName, - ___in ULONG cbFileName) -{ - HRESULT Status = S_OK; - - if (getLineByILOffsetDelegate == nullptr) - { - IfFailRet(SymbolReader::PrepareSymbolReader()); - } - - BSTR wszFileName = SysAllocStringLen(0, cbFileName); - if (wszFileName == nullptr) - { - return E_OUTOFMEMORY; - } - - if (getLineByILOffsetDelegate(szModuleName, MethodToken, IlOffset, pLinenum, &wszFileName) == TRUE) - { - WideCharToMultiByte(CP_ACP, 0, wszFileName, (int) (_wcslen(wszFileName) + 1), - lpszFileName, cbFileName, NULL, NULL); - if (*pLinenum == 0) - { - *pLinenum = -1; - Status = E_FAIL; - } - } - else - { - Status = E_FAIL; - } - - SysFreeString(wszFileName); - - return Status; -} -#endif //FEATURE_PAL +#ifndef FEATURE_PAL -HRESULT SymbolReader::LoadSymbols(IMetaDataImport * pMD, ULONG64 baseAddress, __in_z WCHAR* pModuleName, BOOL isInMemory) +HRESULT SymbolReader::LoadSymbolsForWindowsPDB(___in IMetaDataImport* pMD, ___in ULONG64 peAddress, __in_z WCHAR* pModuleName, ___in BOOL isFileLayout) { - HRESULT Status = S_OK; - -#ifndef FEATURE_PAL + HRESULT Status = S_OK; - if (m_pSymReader != NULL) return S_OK; + if (m_pSymReader != NULL) + return S_OK; IfFailRet(CoInitialize(NULL)); - // We now need a binder object that will take the module and return a // reader object ToRelease<ISymUnmanagedBinder3> pSymBinder; @@ -6401,79 +6101,377 @@ HRESULT SymbolReader::LoadSymbols(IMetaDataImport * pMD, ULONG64 baseAddress, __ return Status; } - // This should be about the right code to handle in-memory assemblies but after writing it all up I lost my repro case - // This path is blocked up above but it would probably be pretty easy to get this working if someone wanted it ToRelease<IUnknown> pCallback = NULL; - if (isInMemory) + if (isFileLayout) { - pCallback = (IUnknown*) new PEOffsetMemoryReader(TO_TADDR(baseAddress)); + pCallback = (IUnknown*) new PEOffsetMemoryReader(TO_TADDR(peAddress)); } else { - pCallback = (IUnknown*) new PERvaMemoryReader(TO_TADDR(baseAddress)); + pCallback = (IUnknown*) new PERvaMemoryReader(TO_TADDR(peAddress)); } // TODO: this should be better integrated with windbg's symbol lookup - Status = pSymBinder->GetReaderFromCallback(pMD, pModuleName, symbolPath, AllowRegistryAccess | AllowSymbolServerAccess | AllowOriginalPathAccess | AllowReferencePathAccess, pCallback, &m_pSymReader); + Status = pSymBinder->GetReaderFromCallback(pMD, pModuleName, symbolPath, + AllowRegistryAccess | AllowSymbolServerAccess | AllowOriginalPathAccess | AllowReferencePathAccess, pCallback, &m_pSymReader); + if (FAILED(Status) && m_pSymReader != NULL) { m_pSymReader->Release(); m_pSymReader = NULL; } return Status; -#else +} + +#endif // FEATURE_PAL + +// +// Pass to managed helper code to read in-memory PEs/PDBs +// Returns the number of bytes read. +// +int ReadMemoryForSymbols(ULONG64 address, char *buffer, int cb) +{ + ULONG read; + if (SafeReadMemory(address, (PVOID)buffer, cb, &read)) + { + return read; + } + return 0; +} + +HRESULT SymbolReader::LoadSymbolsForPortablePDB(__in_z WCHAR* pModuleName, ___in BOOL isInMemory, ___in BOOL isFileLayout, + ___in ULONG64 peAddress, ___in ULONG64 peSize, ___in ULONG64 inMemoryPdbAddress, ___in ULONG64 inMemoryPdbSize) +{ + HRESULT Status = S_OK; + if (loadSymbolsForModuleDelegate == nullptr) { IfFailRet(PrepareSymbolReader()); } - WideCharToMultiByte(CP_ACP, 0, pModuleName, (int) (_wcslen(pModuleName) + 1), m_szModuleName, mdNameLen, NULL, NULL); - if (loadSymbolsForModuleDelegate(m_szModuleName) == FALSE) + // The module name needs to be null for in-memory PE's. + ArrayHolder<char> szModuleName = nullptr; + if (!isInMemory && pModuleName != nullptr) + { + szModuleName = new char[MAX_LONGPATH]; + if (WideCharToMultiByte(CP_ACP, 0, pModuleName, (int)(_wcslen(pModuleName) + 1), szModuleName, MAX_LONGPATH, NULL, NULL) == 0) + { + return E_FAIL; + } + } + + m_symbolReaderHandle = loadSymbolsForModuleDelegate(szModuleName, isFileLayout, peAddress, + (int)peSize, inMemoryPdbAddress, (int)inMemoryPdbSize, ReadMemoryForSymbols); + + if (m_symbolReaderHandle == 0) { return E_FAIL; } return Status; -#endif // FEATURE_PAL } -HRESULT SymbolReader::GetNamedLocalVariable(ISymUnmanagedScope * pScope, ICorDebugILFrame * pILFrame, mdMethodDef methodToken, ULONG localIndex, __inout_ecount(paramNameLen) WCHAR* paramName, ULONG paramNameLen, ICorDebugValue** ppValue) +#ifndef FEATURE_PAL + +void AddFilesFromDirectoryToTpaList(const char* directory, std::string& tpaList) { - HRESULT Status = S_OK; + const char * const tpaExtensions[] = { + "*.ni.dll", // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir + "*.dll", + "*.ni.exe", + "*.exe", + }; + + std::set<std::string> addedAssemblies; + + // Walk the directory for each extension separately so that we first get files with .ni.dll extension, + // then files with .dll extension, etc. + for (int extIndex = 0; extIndex < sizeof(tpaExtensions) / sizeof(tpaExtensions[0]); extIndex++) + { + const char* ext = tpaExtensions[extIndex]; + size_t extLength = strlen(ext); + + std::string assemblyPath(directory); + assemblyPath.append(DIRECTORY_SEPARATOR_STR_A); + assemblyPath.append(tpaExtensions[extIndex]); + + WIN32_FIND_DATAA data; + HANDLE findHandle = FindFirstFileA(assemblyPath.c_str(), &data); + + if (findHandle != INVALID_HANDLE_VALUE) + { + do + { + if (!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + + std::string filename(data.cFileName); + size_t extPos = filename.length() - extLength; + std::string filenameWithoutExt(filename.substr(0, extPos)); + + // Make sure if we have an assembly with multiple extensions present, + // we insert only one version of it. + if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end()) + { + addedAssemblies.insert(filenameWithoutExt); + + tpaList.append(directory); + tpaList.append(DIRECTORY_SEPARATOR_STR_A); + tpaList.append(filename); + tpaList.append(";"); + } + } + } + while (0 != FindNextFileA(findHandle, &data)); + + FindClose(findHandle); + } + } +} + +bool GetEntrypointExecutableAbsolutePath(std::string& entrypointExecutable) +{ + ArrayHolder<char> hostPath = new char[MAX_LONGPATH+1]; + if (::GetModuleFileName(NULL, hostPath, MAX_LONGPATH) == 0) + { + return false; + } + + entrypointExecutable.clear(); + entrypointExecutable.append(hostPath); + + return true; +} + +#endif // FEATURE_PAL + +HRESULT SymbolReader::PrepareSymbolReader() +{ + static bool attemptedSymbolReaderPreparation = false; + if (attemptedSymbolReaderPreparation) + { + // If we already tried to set up the symbol reader, we won't try again. + return E_FAIL; + } + + attemptedSymbolReaderPreparation = true; + + std::string absolutePath; + std::string coreClrPath; + HRESULT Status; + #ifdef FEATURE_PAL - if (getLocalVariableNameDelegate == nullptr) + coreClrPath = g_ExtServices->GetCoreClrDirectory(); + if (!GetAbsolutePath(coreClrPath.c_str(), absolutePath)) { - IfFailRet(PrepareSymbolReader()); + ExtErr("Error: Failed to get coreclr absolute path\n"); + return E_FAIL; + } + coreClrPath.append(DIRECTORY_SEPARATOR_STR_A); + coreClrPath.append(MAIN_CLR_DLL_NAME_A); +#else + ULONG index; + Status = g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, &index, NULL); + if (FAILED(Status)) + { + ExtErr("Error: Can't find coreclr module\n"); + return Status; } + ArrayHolder<char> szModuleName = new char[MAX_LONGPATH + 1]; + Status = g_ExtSymbols->GetModuleNames(index, 0, szModuleName, MAX_LONGPATH, NULL, NULL, 0, NULL, NULL, 0, NULL); + if (FAILED(Status)) + { + ExtErr("Error: Failed to get coreclr module name\n"); + return Status; + } + coreClrPath = szModuleName; - BSTR wszParamName = SysAllocStringLen(0, mdNameLen); - if (wszParamName == NULL) + // Parse off the module name to get just the path + size_t pos = coreClrPath.rfind(DIRECTORY_SEPARATOR_CHAR_A); + if (pos == std::string::npos) { - return E_OUTOFMEMORY; + ExtErr("Error: Failed to parse coreclr module name\n"); + return E_FAIL; } + absolutePath.assign(coreClrPath, 0, pos); +#endif // FEATURE_PAL - if (getLocalVariableNameDelegate(m_szModuleName, methodToken, localIndex, &wszParamName) == FALSE) + HMODULE coreclrLib = LoadLibraryA(coreClrPath.c_str()); + if (coreclrLib == nullptr) { - SysFreeString(wszParamName); + ExtErr("Error: Failed to load %s\n", coreClrPath.c_str()); return E_FAIL; } - wcscpy_s(paramName, _wcslen(wszParamName) + 1, wszParamName); - paramNameLen = _wcslen(paramName); + void *hostHandle; + unsigned int domainId; + coreclr_initialize_ptr initializeCoreCLR = (coreclr_initialize_ptr)GetProcAddress(coreclrLib, "coreclr_initialize"); + if (initializeCoreCLR == nullptr) + { + ExtErr("Error: coreclr_initialize not found\n"); + return E_FAIL; + } + + std::string tpaList; + AddFilesFromDirectoryToTpaList(absolutePath.c_str(), tpaList); - SysFreeString(wszParamName); + const char *propertyKeys[] = { + "TRUSTED_PLATFORM_ASSEMBLIES", "APP_PATHS", "APP_NI_PATHS", + "NATIVE_DLL_SEARCH_DIRECTORIES", "AppDomainCompatSwitch"}; - if (SUCCEEDED(pILFrame->GetLocalVariable(localIndex, ppValue)) && (*ppValue != NULL)) + const char *propertyValues[] = {// TRUSTED_PLATFORM_ASSEMBLIES + tpaList.c_str(), + // APP_PATHS + absolutePath.c_str(), + // APP_NI_PATHS + absolutePath.c_str(), + // NATIVE_DLL_SEARCH_DIRECTORIES + absolutePath.c_str(), + // AppDomainCompatSwitch + "UseLatestBehaviorWhenTFMNotSpecified"}; + + std::string entryPointExecutablePath; + if (!GetEntrypointExecutableAbsolutePath(entryPointExecutablePath)) { - return S_OK; + ExtErr("Could not get full path to current executable"); + return E_FAIL; } - else + + Status = initializeCoreCLR(entryPointExecutablePath.c_str(), "sos", + sizeof(propertyKeys) / sizeof(propertyKeys[0]), propertyKeys, propertyValues, &hostHandle, &domainId); + + if (FAILED(Status)) + { + ExtErr("Error: Fail to initialize CoreCLR %08x\n", Status); + return Status; + } + + coreclr_create_delegate_ptr createDelegate = (coreclr_create_delegate_ptr)GetProcAddress(coreclrLib, "coreclr_create_delegate"); + if (createDelegate == nullptr) { - *ppValue = NULL; + ExtErr("Error: coreclr_create_delegate not found\n"); return E_FAIL; } -#else + IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "LoadSymbolsForModule", (void **)&loadSymbolsForModuleDelegate)); + IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "Dispose", (void **)&disposeDelegate)); + IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "ResolveSequencePoint", (void **)&resolveSequencePointDelegate)); + IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "GetLocalVariableName", (void **)&getLocalVariableNameDelegate)); + IfFailRet(createDelegate(hostHandle, domainId, SymbolReaderDllName, SymbolReaderClassName, "GetLineByILOffset", (void **)&getLineByILOffsetDelegate)); + + return Status; +} + +HRESULT SymbolReader::GetLineByILOffset(___in mdMethodDef methodToken, ___in ULONG64 ilOffset, + ___out ULONG *pLinenum, __out_ecount(cchFileName) WCHAR* pwszFileName, ___in ULONG cchFileName) +{ + HRESULT Status = S_OK; + + if (m_symbolReaderHandle != 0) + { + _ASSERTE(getLineByILOffsetDelegate != nullptr); + + BSTR bstrFileName = SysAllocStringLen(0, MAX_LONGPATH); + if (bstrFileName == nullptr) + { + return E_OUTOFMEMORY; + } + // Source lines with 0xFEEFEE markers are filtered out on the managed side. + if ((getLineByILOffsetDelegate(m_symbolReaderHandle, methodToken, ilOffset, pLinenum, &bstrFileName) == FALSE) || (*pLinenum == 0)) + { + SysFreeString(bstrFileName); + return E_FAIL; + } + wcscpy_s(pwszFileName, cchFileName, bstrFileName); + SysFreeString(bstrFileName); + return S_OK; + } + +#ifndef FEATURE_PAL + if (m_pSymReader == NULL) + return E_FAIL; + + ToRelease<ISymUnmanagedMethod> pSymMethod(NULL); + IfFailRet(m_pSymReader->GetMethod(methodToken, &pSymMethod)); + + ULONG32 seqPointCount = 0; + IfFailRet(pSymMethod->GetSequencePointCount(&seqPointCount)); + + if (seqPointCount == 0) + return E_FAIL; + + // allocate memory for the objects to be fetched + ArrayHolder<ULONG32> offsets(new ULONG32[seqPointCount]); + ArrayHolder<ULONG32> lines(new ULONG32[seqPointCount]); + ArrayHolder<ULONG32> columns(new ULONG32[seqPointCount]); + ArrayHolder<ULONG32> endlines(new ULONG32[seqPointCount]); + ArrayHolder<ULONG32> endcolumns(new ULONG32[seqPointCount]); + ArrayHolder<ToRelease<ISymUnmanagedDocument>> documents(new ToRelease<ISymUnmanagedDocument>[seqPointCount]); + + ULONG32 realSeqPointCount = 0; + IfFailRet(pSymMethod->GetSequencePoints(seqPointCount, &realSeqPointCount, offsets, &(documents[0]), lines, columns, endlines, endcolumns)); + + const ULONG32 HiddenLine = 0x00feefee; + int bestSoFar = -1; + + for (int i = 0; i < (int)realSeqPointCount; i++) + { + if (offsets[i] > ilOffset) + break; + + if (lines[i] != HiddenLine) + bestSoFar = i; + } + + if (bestSoFar != -1) + { + ULONG32 cchNeeded = 0; + IfFailRet(documents[bestSoFar]->GetURL(cchFileName, &cchNeeded, pwszFileName)); + + *pLinenum = lines[bestSoFar]; + return S_OK; + } +#endif // FEATURE_PAL + + return E_FAIL; +} + +HRESULT SymbolReader::GetNamedLocalVariable(___in ISymUnmanagedScope * pScope, ___in ICorDebugILFrame * pILFrame, ___in mdMethodDef methodToken, + ___in ULONG localIndex, __out_ecount(paramNameLen) WCHAR* paramName, ___in ULONG paramNameLen, ICorDebugValue** ppValue) +{ + HRESULT Status = S_OK; + + if (m_symbolReaderHandle != 0) + { + _ASSERTE(getLocalVariableNameDelegate != nullptr); + + BSTR wszParamName = SysAllocStringLen(0, mdNameLen); + if (wszParamName == NULL) + { + return E_OUTOFMEMORY; + } + + if (getLocalVariableNameDelegate(m_symbolReaderHandle, methodToken, localIndex, &wszParamName) == FALSE) + { + SysFreeString(wszParamName); + return E_FAIL; + } + + wcscpy_s(paramName, paramNameLen, wszParamName); + SysFreeString(wszParamName); + + if (FAILED(pILFrame->GetLocalVariable(localIndex, ppValue)) || (*ppValue == NULL)) + { + *ppValue = NULL; + return E_FAIL; + } + return S_OK; + } + +#ifndef FEATURE_PAL + if (m_pSymReader == NULL) + return E_FAIL; + if (pScope == NULL) { ToRelease<ISymUnmanagedMethod> pSymMethod; @@ -6534,14 +6532,14 @@ HRESULT SymbolReader::GetNamedLocalVariable(ISymUnmanagedScope * pScope, ICorDeb } for (ULONG j = 0; j < numChildren; j++) pChildren[j]->Release(); - } +#endif // FEATURE_PAL return E_FAIL; -#endif // FEATURE_PAL } -HRESULT SymbolReader::GetNamedLocalVariable(ICorDebugFrame * pFrame, ULONG localIndex, __inout_ecount(paramNameLen) WCHAR* paramName, ULONG paramNameLen, ICorDebugValue** ppValue) +HRESULT SymbolReader::GetNamedLocalVariable(___in ICorDebugFrame * pFrame, ___in ULONG localIndex, __out_ecount(paramNameLen) WCHAR* paramName, + ___in ULONG paramNameLen, ___out ICorDebugValue** ppValue) { HRESULT Status = S_OK; @@ -6564,11 +6562,30 @@ HRESULT SymbolReader::GetNamedLocalVariable(ICorDebugFrame * pFrame, ULONG local return GetNamedLocalVariable(NULL, pILFrame, methodDef, localIndex, paramName, paramNameLen, ppValue); } -HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 lineNumber, TADDR mod, mdMethodDef* pToken, ULONG32* pIlOffset) +HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ___in ULONG32 lineNumber, ___in TADDR mod, ___out mdMethodDef* pToken, ___out ULONG32* pIlOffset) { HRESULT Status = S_OK; + if (m_symbolReaderHandle != 0) + { + _ASSERTE(resolveSequencePointDelegate != nullptr); + + char szName[mdNameLen]; + if (WideCharToMultiByte(CP_ACP, 0, pFilename, (int)(_wcslen(pFilename) + 1), szName, mdNameLen, NULL, NULL) == 0) + { + return E_FAIL; + } + if (resolveSequencePointDelegate(m_symbolReaderHandle, szName, lineNumber, pToken, pIlOffset) == FALSE) + { + return E_FAIL; + } + return S_OK; + } + #ifndef FEATURE_PAL + if (m_pSymReader == NULL) + return E_FAIL; + ULONG32 cDocs = 0; ULONG32 cDocsNeeded = 0; ArrayHolder<ToRelease<ISymUnmanagedDocument>> pDocs = NULL; @@ -6580,7 +6597,7 @@ HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 line ULONG32 filenameLen = (ULONG32) _wcslen(pFilename); - for(ULONG32 i = 0; i < cDocs; i++) + for (ULONG32 i = 0; i < cDocs; i++) { ULONG32 cchUrl = 0; ULONG32 cchUrlNeeded = 0; @@ -6591,18 +6608,18 @@ HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 line IfFailRet(pDocs[i]->GetURL(cchUrl, &cchUrlNeeded, pUrl)); // If the URL is exactly as long as the filename then compare the two names directly - if(cchUrl-1 == filenameLen) + if (cchUrl-1 == filenameLen) { - if(0!=_wcsicmp(pUrl, pFilename)) + if (0!=_wcsicmp(pUrl, pFilename)) continue; } // does the URL suffix match [back]slash + filename? - else if(cchUrl-1 > filenameLen) + else if (cchUrl-1 > filenameLen) { WCHAR* slashLocation = pUrl + (cchUrl - filenameLen - 2); - if(*slashLocation != L'\\' && *slashLocation != L'/') + if (*slashLocation != L'\\' && *slashLocation != L'/') continue; - if(0 != _wcsicmp(slashLocation+1, pFilename)) + if (0 != _wcsicmp(slashLocation+1, pFilename)) continue; } // URL is too short to match @@ -6610,7 +6627,7 @@ HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 line continue; ULONG32 closestLine = 0; - if(FAILED(pDocs[i]->FindClosestLine(lineNumber, &closestLine))) + if (FAILED(pDocs[i]->FindClosestLine(lineNumber, &closestLine))) continue; ToRelease<ISymUnmanagedMethod> pSymUnmanagedMethod; @@ -6625,29 +6642,9 @@ HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 line } return S_OK; } - return E_FAIL; - -#else - if (loadSymbolsForModuleDelegate == nullptr) - { - IfFailRet(PrepareSymbolReader()); - } - - char szName[mdNameLen]; - WideCharToMultiByte(CP_ACP, 0, pFilename, (int) (_wcslen(pFilename) + 1), szName, mdNameLen, NULL, NULL); - - WCHAR FileNameW[MAX_LONGPATH]; - char FileName[MAX_LONGPATH]; - FileNameForModule(mod, FileNameW); - - WideCharToMultiByte(CP_ACP, 0, FileNameW, (int) (_wcslen(FileNameW) + 1), FileName, MAX_LONGPATH, NULL, NULL); - if (resolveSequencePointDelegate(FileName, szName, lineNumber, pToken, pIlOffset) == FALSE) - { - return E_FAIL; - } - - return S_OK; #endif // FEATURE_PAL + + return E_FAIL; } static void AddAssemblyName(WString& methodOutput, CLRDATA_ADDRESS mdesc) @@ -6658,17 +6655,21 @@ static void AddAssemblyName(WString& methodOutput, CLRDATA_ADDRESS mdesc) DacpModuleData dmd; if (SUCCEEDED(dmd.Request(g_sos, mdescData.ModulePtr))) { - ArrayHolder<WCHAR> wszFileName = new WCHAR[MAX_LONGPATH+1]; - if (SUCCEEDED(g_sos->GetPEFileName(dmd.File, MAX_LONGPATH, wszFileName, NULL))) + ToRelease<IXCLRDataModule> pModule; + if (SUCCEEDED(g_sos->GetModule(mdescData.ModulePtr, &pModule))) { - if (wszFileName[0] != W('\0')) + ArrayHolder<WCHAR> wszFileName = new WCHAR[MAX_LONGPATH + 1]; + ULONG32 nameLen = 0; + if (SUCCEEDED(pModule->GetFileName(MAX_LONGPATH, &nameLen, wszFileName))) { - WCHAR *pJustName = _wcsrchr(wszFileName, DIRECTORY_SEPARATOR_CHAR_W); - if (pJustName == NULL) - pJustName = wszFileName - 1; - - methodOutput += (pJustName + 1); - methodOutput += W("!"); + if (wszFileName[0] != W('\0')) + { + WCHAR *pJustName = _wcsrchr(wszFileName, DIRECTORY_SEPARATOR_CHAR_W); + if (pJustName == NULL) + pJustName = wszFileName - 1; + methodOutput += (pJustName + 1); + methodOutput += W("!"); + } } } } @@ -6730,30 +6731,6 @@ WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackWalk, BOO return frameOutput; } -String ModuleNameFromIP(CLRDATA_ADDRESS ip) -{ - CLRDATA_ADDRESS mdesc = 0; - if (SUCCEEDED(g_sos->GetMethodDescPtrFromIP(ip, &mdesc))) - { - DacpMethodDescData mdescData; - DacpModuleData moduleData; - if (SUCCEEDED(mdescData.Request(g_sos, mdesc))) - { - if (SUCCEEDED(moduleData.Request(g_sos, mdescData.ModulePtr))) - { - ArrayHolder<WCHAR> wszModuleName = new WCHAR[MAX_LONGPATH+1]; - if (SUCCEEDED(g_sos->GetPEFileName(moduleData.File, MAX_LONGPATH, wszModuleName, NULL))) - { - ArrayHolder<char> szModuleName = new char[MAX_LONGPATH+1]; - WideCharToMultiByte(CP_ACP, 0, wszModuleName, (int) (_wcslen(wszModuleName) + 1), szModuleName, mdNameLen, NULL, NULL); - return szModuleName.GetPtr(); - } - } - } - } - return ""; -} - WString MethodNameFromIP(CLRDATA_ADDRESS ip, BOOL bSuppressLines, BOOL bAssemblyName, BOOL bDisplacement) { ULONG linenum; @@ -6825,15 +6802,10 @@ WString MethodNameFromIP(CLRDATA_ADDRESS ip, BOOL bSuppressLines, BOOL bAssembly methodOutput = W("<unknown>"); } - ArrayHolder<char> szFileName = new char[MAX_LONGPATH+1]; - + ArrayHolder<WCHAR> wszFileName = new WCHAR[MAX_LONGPATH]; if (!bSuppressLines && - SUCCEEDED(GetLineByOffset(TO_CDADDR(ip), &linenum, szFileName, MAX_LONGPATH))) + SUCCEEDED(GetLineByOffset(TO_CDADDR(ip), &linenum, wszFileName, MAX_LONGPATH))) { - int len = MultiByteToWideChar(CP_ACP, 0, szFileName, MAX_LONGPATH, NULL, 0); - ArrayHolder<WCHAR> wszFileName = new WCHAR[len]; - MultiByteToWideChar(CP_ACP, 0, szFileName, MAX_LONGPATH, wszFileName, len); - methodOutput += WString(W(" [")) + wszFileName + W(" @ ") + Decimal(linenum) + W("]"); } } diff --git a/src/ToolBox/SOS/Strike/util.h b/src/ToolBox/SOS/Strike/util.h index ee49f8cd01..f444c9fcb2 100644 --- a/src/ToolBox/SOS/Strike/util.h +++ b/src/ToolBox/SOS/Strike/util.h @@ -2355,63 +2355,75 @@ private: #endif // !FEATURE_PAL -#ifdef FEATURE_PAL -typedef BOOL (*ResolveSequencePointDelegate)(const char*, const char*, unsigned int, unsigned int*, unsigned int*); -typedef BOOL (*LoadSymbolsForModuleDelegate)(const char*); -typedef BOOL (*GetLocalVariableName)(const char*, int, int, BSTR*); -typedef BOOL (*GetLineByILOffsetDelegate)(const char*, mdMethodDef, ULONG64, ULONG *, BSTR*); -static const char *SymbolReaderDllName = "System.Diagnostics.Debug.SymbolReader"; -static const char *SymbolReaderClassName = "System.Diagnostics.Debug.SymbolReader.SymbolReader"; -#endif //FEATURE_PAL +static const char *SymbolReaderDllName = "SOS.NETCore"; +static const char *SymbolReaderClassName = "SOS.SymbolReader"; + +typedef int (*ReadMemoryDelegate)(ULONG64, char *, int); +typedef ULONG64 (*LoadSymbolsForModuleDelegate)(const char*, BOOL, ULONG64, int, ULONG64, int, ReadMemoryDelegate); +typedef void (*DisposeDelegate)(ULONG64); +typedef BOOL (*ResolveSequencePointDelegate)(ULONG64, const char*, unsigned int, unsigned int*, unsigned int*); +typedef BOOL (*GetLocalVariableName)(ULONG64, int, int, BSTR*); +typedef BOOL (*GetLineByILOffsetDelegate)(ULONG64, mdMethodDef, ULONG64, ULONG *, BSTR*); class SymbolReader { private: +#ifndef FEATURE_PAL ISymUnmanagedReader* m_pSymReader; -#ifdef FEATURE_PAL - static void *coreclrLib; - char m_szModuleName[mdNameLen]; - static ResolveSequencePointDelegate resolveSequencePointDelegate; +#endif + ULONG64 m_symbolReaderHandle; + static LoadSymbolsForModuleDelegate loadSymbolsForModuleDelegate; + static DisposeDelegate disposeDelegate; + static ResolveSequencePointDelegate resolveSequencePointDelegate; static GetLocalVariableName getLocalVariableNameDelegate; static GetLineByILOffsetDelegate getLineByILOffsetDelegate; + static HRESULT PrepareSymbolReader(); -#endif - -private: - HRESULT GetNamedLocalVariable(ISymUnmanagedScope * pScope, ICorDebugILFrame * pILFrame, mdMethodDef methodToken, ULONG localIndex, __inout_ecount(paramNameLen) WCHAR* paramName, ULONG paramNameLen, ICorDebugValue** ppValue); + HRESULT GetNamedLocalVariable(___in ISymUnmanagedScope* pScope, ___in ICorDebugILFrame* pILFrame, ___in mdMethodDef methodToken, ___in ULONG localIndex, + __out_ecount(paramNameLen) WCHAR* paramName, ___in ULONG paramNameLen, ___out ICorDebugValue** ppValue); + HRESULT LoadSymbolsForWindowsPDB(___in IMetaDataImport* pMD, ___in ULONG64 peAddress, __in_z WCHAR* pModuleName, ___in BOOL isFileLayout); + HRESULT LoadSymbolsForPortablePDB(__in_z WCHAR* pModuleName, ___in BOOL isInMemory, ___in BOOL isFileLayout, ___in ULONG64 peAddress, ___in ULONG64 peSize, + ___in ULONG64 inMemoryPdbAddress, ___in ULONG64 inMemoryPdbSize); public: - SymbolReader() : m_pSymReader (NULL) { + SymbolReader() + { +#ifndef FEATURE_PAL + m_pSymReader = NULL; +#endif + m_symbolReaderHandle = 0; } + ~SymbolReader() { +#ifndef FEATURE_PAL if(m_pSymReader != NULL) { m_pSymReader->Release(); m_pSymReader = NULL; } +#endif + if (m_symbolReaderHandle != 0) + { + disposeDelegate(m_symbolReaderHandle); + m_symbolReaderHandle = 0; + } } -#ifdef FEATURE_PAL - static HRESULT PrepareSymbolReader(); - static bool SymbolReaderDllExists(); - static HRESULT GetLineByILOffset(__in_z const char* szModuleName, mdMethodDef MethodToken, ULONG64 IlOffset, ___out ULONG *pLinenum, - __out_ecount(cbFileName) LPSTR lpszFileName, ___in ULONG cbFileName); -#endif //FEATURE_PAL - HRESULT LoadSymbols(IMetaDataImport * pMD, ICorDebugModule * pModule); - HRESULT LoadSymbols(IMetaDataImport * pMD, ULONG64 baseAddress, __in_z WCHAR* pModuleName, BOOL isInMemory); - HRESULT GetNamedLocalVariable(ICorDebugFrame * pFrame, ULONG localIndex, __inout_ecount(paramNameLen) WCHAR* paramName, ULONG paramNameLen, ICorDebugValue** ppValue); - HRESULT SymbolReader::ResolveSequencePoint(__in_z WCHAR* pFilename, ULONG32 lineNumber, TADDR mod, mdMethodDef* pToken, ULONG32* pIlOffset); + HRESULT LoadSymbols(___in IMetaDataImport* pMD, ___in ICorDebugModule* pModule); + HRESULT LoadSymbols(___in IMetaDataImport* pMD, ___in IXCLRDataModule* pModule); + HRESULT GetLineByILOffset(___in mdMethodDef MethodToken, ___in ULONG64 IlOffset, ___out ULONG *pLinenum, __out_ecount(cchFileName) WCHAR* pwszFileName, ___in ULONG cchFileName); + HRESULT GetNamedLocalVariable(___in ICorDebugFrame * pFrame, ___in ULONG localIndex, __out_ecount(paramNameLen) WCHAR* paramName, ___in ULONG paramNameLen, ___out ICorDebugValue** ppValue); + HRESULT ResolveSequencePoint(__in_z WCHAR* pFilename, ___in ULONG32 lineNumber, ___in TADDR mod, ___out mdMethodDef* ___out pToken, ___out ULONG32* pIlOffset); }; - HRESULT GetLineByOffset( ___in ULONG64 IP, ___out ULONG *pLinenum, - __out_ecount(cbFileName) LPSTR lpszFileName, - ___in ULONG cbFileName); + __out_ecount(cchFileName) WCHAR* pwszFileName, + ___in ULONG cchFileName); /// X86 Context #define X86_SIZE_OF_80387_REGISTERS 80 @@ -2708,7 +2720,6 @@ typedef struct _CROSS_PLATFORM_CONTEXT { WString BuildRegisterOutput(const SOSStackRefData &ref, bool printObj = true); WString MethodNameFromIP(CLRDATA_ADDRESS methodDesc, BOOL bSuppressLines = FALSE, BOOL bAssemblyName = FALSE, BOOL bDisplacement = FALSE); -String ModuleNameFromIP(CLRDATA_ADDRESS ip); HRESULT GetGCRefs(ULONG osID, SOSStackRefData **ppRefs, unsigned int *pRefCnt, SOSStackRefError **ppErrors, unsigned int *pErrCount); WString GetFrameFromAddress(TADDR frameAddr, IXCLRDataStackWalk *pStackwalk = NULL, BOOL bAssemblyName = FALSE); @@ -3254,12 +3265,6 @@ struct ImageInfo ULONG64 modBase; }; -HRESULT -GetClrModuleImages( - ___in IXCLRDataModule* Module, - ___in CLRDataModuleExtentType DesiredType, - ___out ImageInfo* FirstAdd); - // Helper class used in ClrStackFromPublicInterface() to keep track of explicit EE Frames // (i.e., "internal frames") on the stack. Call Init() with the appropriate // ICorDebugThread3, and this class will initialize itself with the set of internal diff --git a/src/ToolBox/SOS/lldbplugin/inc/lldbservices.h b/src/ToolBox/SOS/lldbplugin/inc/lldbservices.h index 6c713141f3..16702b116d 100644 --- a/src/ToolBox/SOS/lldbplugin/inc/lldbservices.h +++ b/src/ToolBox/SOS/lldbplugin/inc/lldbservices.h @@ -67,6 +67,17 @@ extern "C" { #define DEBUG_CLASS_USER_WINDOWS 2 #define DEBUG_CLASS_IMAGE_FILE 3 +// Generic dump types. These can be used +// with either user or kernel sessions. +// Session-type-specific aliases are also +// provided. +#define DEBUG_DUMP_SMALL 1024 +#define DEBUG_DUMP_DEFAULT 1025 +#define DEBUG_DUMP_FULL 1026 +#define DEBUG_DUMP_IMAGE_FILE 1027 +#define DEBUG_DUMP_TRACE_LOG 1028 +#define DEBUG_DUMP_WINDOWS_CE 1029 + #define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386. #define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian #define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) diff --git a/src/build.proj b/src/build.proj index c12e859e31..8b9e3922b8 100644 --- a/src/build.proj +++ b/src/build.proj @@ -3,6 +3,7 @@ <!-- List the projects that need to be built --> <ItemGroup> + <Project Include="ToolBox\SOS\NETCore\SOS.NETCore.csproj" /> <Project Include="mscorlib\System.Private.CoreLib.csproj" /> <Project Include="mscorlib\facade\mscorlib.csproj" /> <Project Include="mscorlib\ref\mscorlib.csproj" /> @@ -36,4 +37,4 @@ DestinationFolder="$(BinDir)PDB" /> </Target> -</Project>
\ No newline at end of file +</Project> diff --git a/src/debug/daccess/dacimpl.h b/src/debug/daccess/dacimpl.h index a755391ff6..635be80232 100644 --- a/src/debug/daccess/dacimpl.h +++ b/src/debug/daccess/dacimpl.h @@ -2570,9 +2570,14 @@ public: /* [size_is][out] */ BYTE *outBuffer); HRESULT RequestGetModulePtr(IN ULONG32 inBufferSize, - IN BYTE* inBuffer, - IN ULONG32 outBufferSize, - OUT BYTE* outBuffer); + IN BYTE* inBuffer, + IN ULONG32 outBufferSize, + OUT BYTE* outBuffer); + + HRESULT RequestGetModuleData(IN ULONG32 inBufferSize, + IN BYTE* inBuffer, + IN ULONG32 outBufferSize, + OUT BYTE* outBuffer); Module* GetModule(void) { diff --git a/src/debug/daccess/task.cpp b/src/debug/daccess/task.cpp index fe60eae04b..601ad401af 100644 --- a/src/debug/daccess/task.cpp +++ b/src/debug/daccess/task.cpp @@ -2710,6 +2710,56 @@ ClrDataModule::RequestGetModulePtr( outGMA->ModulePtr = TO_CDADDR(PTR_HOST_TO_TADDR(m_module)); return S_OK; } + +HRESULT +ClrDataModule::RequestGetModuleData( + /* [in] */ ULONG32 inBufferSize, + /* [size_is][in] */ BYTE *inBuffer, + /* [in] */ ULONG32 outBufferSize, + /* [size_is][out] */ BYTE *outBuffer) +{ + // Validate params. + // Input: Nothing. + // Output: a DacpGetModuleData structure. + if ((inBufferSize != 0) || + (inBuffer != NULL) || + (outBufferSize != sizeof(DacpGetModuleData)) || + (outBuffer == NULL)) + { + return E_INVALIDARG; + } + + DacpGetModuleData * outGMD = reinterpret_cast<DacpGetModuleData *>(outBuffer); + ZeroMemory(outGMD, sizeof(DacpGetModuleData)); + + Module* pModule = GetModule(); + PEFile *pPEFile = pModule->GetFile(); + + outGMD->PEFile = TO_CDADDR(PTR_HOST_TO_TADDR(pPEFile)); + outGMD->IsDynamic = pModule->IsReflection(); + + if (pPEFile != NULL) + { + outGMD->IsInMemory = pPEFile->GetPath().IsEmpty(); + + COUNT_T peSize; + outGMD->LoadedPEAddress = TO_CDADDR(PTR_TO_TADDR(pPEFile->GetLoadedImageContents(&peSize))); + outGMD->LoadedPESize = (ULONG64)peSize; + outGMD->IsFileLayout = pPEFile->GetLoaded()->IsFlat(); + } + + // If there is a in memory symbol stream + CGrowableStream* stream = pModule->GetInMemorySymbolStream(); + if (stream != NULL) + { + // Save the in-memory PDB address and size + MemoryRange range = stream->GetRawBuffer(); + outGMD->InMemoryPdbAddress = TO_CDADDR(PTR_TO_TADDR(range.StartAddress())); + outGMD->InMemoryPdbSize = range.Size(); + } + + return S_OK; +} HRESULT STDMETHODCALLTYPE ClrDataModule::Request( @@ -2742,9 +2792,11 @@ ClrDataModule::Request( break; case DACDATAMODULEPRIV_REQUEST_GET_MODULEPTR: - status = RequestGetModulePtr(inBufferSize, inBuffer, - outBufferSize, outBuffer); + status = RequestGetModulePtr(inBufferSize, inBuffer, outBufferSize, outBuffer); + break; + case DACDATAMODULEPRIV_REQUEST_GET_MODULEDATA: + status = RequestGetModuleData(inBufferSize, inBuffer, outBufferSize, outBuffer); break; default: diff --git a/src/dlls/mscoree/unixinterface.cpp b/src/dlls/mscoree/unixinterface.cpp index 897924c90c..8d75ff2721 100644 --- a/src/dlls/mscoree/unixinterface.cpp +++ b/src/dlls/mscoree/unixinterface.cpp @@ -250,8 +250,8 @@ int coreclr_initialize( hr = coreclr_create_delegate(*hostHandle, *domainId, - "System.Diagnostics.Debug.SymbolReader", - "System.Diagnostics.Debug.SymbolReader.SymbolReader", + "SOS.NETCore", + "SOS.SymbolReader", "GetInfoForMethod", (void**)&getInfoForMethodDelegate); diff --git a/src/inc/dacprivate.h b/src/inc/dacprivate.h index cf786eec61..5a09abe113 100644 --- a/src/inc/dacprivate.h +++ b/src/inc/dacprivate.h @@ -46,7 +46,8 @@ struct ZeroInit // Private requests for DataModules enum { - DACDATAMODULEPRIV_REQUEST_GET_MODULEPTR = 0xf0000000 + DACDATAMODULEPRIV_REQUEST_GET_MODULEPTR = 0xf0000000, + DACDATAMODULEPRIV_REQUEST_GET_MODULEDATA = 0xf0000001 }; @@ -902,9 +903,24 @@ struct DacpGetModuleAddress : ZeroInit<DacpGetModuleAddress> CLRDATA_ADDRESS ModulePtr; HRESULT Request(IXCLRDataModule* pDataModule) { - return pDataModule->Request(DACDATAMODULEPRIV_REQUEST_GET_MODULEPTR, - 0, NULL, - sizeof(*this), (PBYTE) this); + return pDataModule->Request(DACDATAMODULEPRIV_REQUEST_GET_MODULEPTR, 0, NULL, sizeof(*this), (PBYTE) this); + } +}; + +struct DacpGetModuleData : ZeroInit<DacpGetModuleData> +{ + BOOL IsDynamic; + BOOL IsInMemory; + BOOL IsFileLayout; + CLRDATA_ADDRESS PEFile; + CLRDATA_ADDRESS LoadedPEAddress; + ULONG64 LoadedPESize; + CLRDATA_ADDRESS InMemoryPdbAddress; + ULONG64 InMemoryPdbSize; + + HRESULT Request(IXCLRDataModule* pDataModule) + { + return pDataModule->Request(DACDATAMODULEPRIV_REQUEST_GET_MODULEDATA, 0, NULL, sizeof(*this), (PBYTE) this); } }; diff --git a/src/inc/palclr.h b/src/inc/palclr.h index 4bac965962..85c802f65b 100644 --- a/src/inc/palclr.h +++ b/src/inc/palclr.h @@ -86,6 +86,7 @@ #endif #define DIRECTORY_SEPARATOR_CHAR_A '\\' +#define DIRECTORY_SEPARATOR_STR_A "\\" #define DIRECTORY_SEPARATOR_CHAR_W W('\\') #define DIRECTORY_SEPARATOR_STR_W W("\\") diff --git a/src/mscorlib/src/System/Diagnostics/Stacktrace.cs b/src/mscorlib/src/System/Diagnostics/Stacktrace.cs index d93412e855..c06a1c0d11 100644 --- a/src/mscorlib/src/System/Diagnostics/Stacktrace.cs +++ b/src/mscorlib/src/System/Diagnostics/Stacktrace.cs @@ -125,13 +125,13 @@ namespace System.Diagnostics { if (s_symbolsMethodInfo == null) { s_symbolsType = Type.GetType( - "System.Diagnostics.StackTraceSymbols, System.Diagnostics.StackTrace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "System.Diagnostics.StackTraceSymbols, System.Diagnostics.StackTrace, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false); if (s_symbolsType == null) return; - s_symbolsMethodInfo = s_symbolsType.GetMethod("GetSourceLineInfo"); + s_symbolsMethodInfo = s_symbolsType.GetMethod("GetSourceLineInfo", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); if (s_symbolsMethodInfo == null) return; } @@ -147,7 +147,7 @@ namespace System.Diagnostics { for (int index = 0; index < iFrameCount; index++) { - // If there was some reason not to try get get the symbols from the portable PDB reader like the module was + // If there was some reason not to try get the symbols from the portable PDB reader like the module was // ENC or the source/line info was already retrieved, the method token is 0. if (rgiMethodToken[index] != 0) { diff --git a/src/vm/gdbjit.cpp b/src/vm/gdbjit.cpp index 4d7640afed..2742946cd5 100644 --- a/src/vm/gdbjit.cpp +++ b/src/vm/gdbjit.cpp @@ -99,15 +99,20 @@ GetDebugInfoFromPDB(MethodDesc* MethodDescPtr, SymbolsInfo** symInfo, unsigned i const Module* mod = MethodDescPtr->GetMethodTable()->GetModule(); SString modName = mod->GetFile()->GetPath(); + if (modName.IsEmpty()) + return E_FAIL; + StackScratchBuffer scratch; const char* szModName = modName.GetUTF8(scratch); MethodDebugInfo* methodDebugInfo = new (nothrow) MethodDebugInfo(); if (methodDebugInfo == nullptr) return E_OUTOFMEMORY; + methodDebugInfo->points = (SequencePointInfo*) CoTaskMemAlloc(sizeof(SequencePointInfo) * numMap); if (methodDebugInfo->points == nullptr) return E_OUTOFMEMORY; + methodDebugInfo->size = numMap; if (getInfoForMethodDelegate(szModName, MethodDescPtr->GetMemberDef(), *methodDebugInfo) == FALSE) |