Create SOS SymbolReader managed project and change SOS to use it. (dotnet/coreclr...
authorMike McLaughlin <mikem@microsoft.com>
Fri, 19 Aug 2016 23:06:56 +0000 (16:06 -0700)
committerGitHub <noreply@github.com>
Fri, 19 Aug 2016 23:06:56 +0000 (16:06 -0700)
* Change SOS to use wrapper class that is now in System.Diagnostics.StackTrace.

The portable PDB helper code for SOS source/line support has been moved from
System.Diagnostics.Debug.SymbolReader to a new managed SOS project in the coreclr
repo called SOS.NETCore.

The public APIs have now been made internal.

Plumb through the loaded PE address to the managed SymbolReader functions so it can be used as a key.

Fixed a stack trashing/overflow when a unresolved managed breakpoint is resolved because one of the
module name buffers was too small (MAX_PATH_FNAME). Changed it (and others) to MAXLONGPATH.

SOS now works with Portable PDBs on Windows.

New dac private get module data request. Used to get the necessary info for portable PDBs.

SOS now supports in-memory PE's on xplat and Windows. Needed to get and plumb though the in-memory
PE layout where it is file based or loaded.

Better Windows GetLineByILOffset support. Uses the SymbolReader and now works with in-memory PEs.

Misc code formatting and general cleanup.

* Code review feedback.

Commit migrated from https://github.com/dotnet/coreclr/commit/75890669d59ea8e1a28ade8222ebec2706082674

30 files changed:
src/coreclr/build.proj
src/coreclr/dir.props
src/coreclr/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/debian/Microsoft.NETCore.Runtime.CoreCLR.pkgproj
src/coreclr/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/fedora/23/Microsoft.NETCore.Runtime.CoreCLR.pkgproj
src/coreclr/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/opensuse/13.2/Microsoft.NETCore.Runtime.CoreCLR.pkgproj
src/coreclr/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/osx/Microsoft.NETCore.Runtime.CoreCLR.pkgproj
src/coreclr/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/rhel/Microsoft.NETCore.Runtime.CoreCLR.pkgproj
src/coreclr/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/14.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj
src/coreclr/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/ubuntu/16.04/Microsoft.NETCore.Runtime.CoreCLR.pkgproj
src/coreclr/src/.nuget/Microsoft.NETCore.Runtime.CoreCLR/win/Microsoft.NETCore.Runtime.CoreCLR.pkgproj
src/coreclr/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj [new file with mode: 0644]
src/coreclr/src/ToolBox/SOS/NETCore/SOS.NETCore.sln [new file with mode: 0644]
src/coreclr/src/ToolBox/SOS/NETCore/SymbolReader.cs [new file with mode: 0644]
src/coreclr/src/ToolBox/SOS/NETCore/project.json [new file with mode: 0644]
src/coreclr/src/ToolBox/SOS/Strike/CMakeLists.txt
src/coreclr/src/ToolBox/SOS/Strike/disasmARM.cpp
src/coreclr/src/ToolBox/SOS/Strike/disasmARM64.cpp
src/coreclr/src/ToolBox/SOS/Strike/disasmX86.cpp
src/coreclr/src/ToolBox/SOS/Strike/strike.cpp
src/coreclr/src/ToolBox/SOS/Strike/util.cpp
src/coreclr/src/ToolBox/SOS/Strike/util.h
src/coreclr/src/ToolBox/SOS/lldbplugin/inc/lldbservices.h
src/coreclr/src/build.proj
src/coreclr/src/debug/daccess/dacimpl.h
src/coreclr/src/debug/daccess/task.cpp
src/coreclr/src/dlls/mscoree/unixinterface.cpp
src/coreclr/src/inc/dacprivate.h
src/coreclr/src/inc/palclr.h
src/coreclr/src/mscorlib/src/System/Diagnostics/Stacktrace.cs
src/coreclr/src/vm/gdbjit.cpp

index f3a9d40..7df2904 100644 (file)
@@ -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) &quot;$(SourceDir).nuget/init/project.json&quot; --source https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
   </Target>
   
-</Project>
\ No newline at end of file
+</Project>
index f8823b7..7f164fd 100644 (file)
@@ -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>
index 0a7e5cb..2709e18 100644 (file)
@@ -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>
index 657ccca..3e3533d 100644 (file)
@@ -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>
index 1c50503..cc8c206 100644 (file)
@@ -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>
index a244b88..f076019 100644 (file)
@@ -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>
index eaa6e34..200abce 100644 (file)
@@ -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>
index a0110d5..8996273 100644 (file)
@@ -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>
index 14e86cd..f12132d 100644 (file)
@@ -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>
index 930d277..41a3887 100644 (file)
@@ -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/coreclr/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj b/src/coreclr/src/ToolBox/SOS/NETCore/SOS.NETCore.csproj
new file mode 100644 (file)
index 0000000..e8e2b7e
--- /dev/null
@@ -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/coreclr/src/ToolBox/SOS/NETCore/SOS.NETCore.sln b/src/coreclr/src/ToolBox/SOS/NETCore/SOS.NETCore.sln
new file mode 100644 (file)
index 0000000..0106883
--- /dev/null
@@ -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/coreclr/src/ToolBox/SOS/NETCore/SymbolReader.cs b/src/coreclr/src/ToolBox/SOS/NETCore/SymbolReader.cs
new file mode 100644 (file)
index 0000000..c4c1dc8
--- /dev/null
@@ -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/coreclr/src/ToolBox/SOS/NETCore/project.json b/src/coreclr/src/ToolBox/SOS/NETCore/project.json
new file mode 100644 (file)
index 0000000..e9e4f09
--- /dev/null
@@ -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": {}
+  }
+}
index eb3d94c..5d25865 100644 (file)
@@ -92,6 +92,7 @@ if(WIN32)
     kernel32.lib
     user32.lib
     ole32.lib
+    oleaut32.lib
     dbghelp.lib
     uuid.lib
     version.lib
index fc51e8c..8217355 100644 (file)
@@ -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);
             }
         }
 
index 2629e6d..6a19fc9 100644 (file)
@@ -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);
             }
         }
 
index d802ebf..36a08d2 100644 (file)
@@ -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);
             }
         }
 
index 3164c2c..731e2f5 100644 (file)
@@ -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);
index 45bcd21..9eec76e 100644 (file)
 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("]");
         }
     }
index ee49f8c..f444c9f 100644 (file)
@@ -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
index 6c71314..16702b1 100644 (file)
@@ -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)
index c12e859..8b9e392 100644 (file)
@@ -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>
index a755391..635be80 100644 (file)
@@ -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)
     {
index fe60eae..601ad40 100644 (file)
@@ -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:
index 897924c..8d75ff2 100644 (file)
@@ -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);
 
index cf786ee..5a09abe 100644 (file)
@@ -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);
     }
 };
 
index 4bac965..85c802f 100644 (file)
@@ -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("\\")
 
index d93412e..c06a1c0 100644 (file)
@@ -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)
                     {
index 4d7640a..2742946 100644 (file)
@@ -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)