<!-- Other libs -->
<MicrosoftSymbolStoreVersion>1.0.41901</MicrosoftSymbolStoreVersion>
- <MicrosoftDiagnosticsRuntimeVersion>1.1.37504</MicrosoftDiagnosticsRuntimeVersion>
+ <MicrosoftDiagnosticsRuntimeVersion>1.1.46104</MicrosoftDiagnosticsRuntimeVersion>
<MicrosoftDiaSymReaderNativePackageVersion>1.7.0</MicrosoftDiaSymReaderNativePackageVersion>
<MicrosoftDiagnosticsTracingTraceEventVersion>2.0.44</MicrosoftDiagnosticsTracingTraceEventVersion>
<SystemCommandLineExperimentalVersion>0.2.0-alpha.19254.1</SystemCommandLineExperimentalVersion>
inputs:
pathtoPublish: '$(Build.SourcesDirectory)/artifacts/$(_PublishArtifacts)'
artifactName: $(_PhaseName)_$(_BuildArch)_$(_BuildConfig)
- condition: and(succeeded(), ne(variables['_PublishArtifacts'], ''))
+ condition: ne(variables['_PublishArtifacts'], '')
- task: CopyFiles@2
displayName: Gather Build Logs
/// <summary>
/// The major portion of the runtime framework version
/// </summary>
+ /// <exception cref="SkipTestException">the RuntimeFrameworkVersion property doesn't exist</exception>
public int RuntimeFrameworkVersionMajor
{
get {
using System;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
builder = AddInterface(IID_ILLDBServices2, validate: false);
builder.AddMethod(new LoadNativeSymbolsDelegate2(LoadNativeSymbols2));
builder.AddMethod(new AddModuleSymbolDelegate(AddModuleSymbol));
+ builder.AddMethod(new GetModuleInfoDelegate(GetModuleInfo));
+ builder.AddMethod(new GetModuleVersionInformationDelegate(soshost.GetModuleVersionInformation));
builder.Complete();
AddRef();
return S_OK;
}
+ unsafe int GetModuleInfo(
+ IntPtr self,
+ uint index,
+ ulong *moduleBase,
+ ulong *moduleSize)
+ {
+ try
+ {
+ ModuleInfo module = _soshost.DataReader.EnumerateModules().ElementAt((int)index);
+ if (module == null) {
+ return E_FAIL;
+ }
+ SOSHost.Write(moduleBase, module.ImageBase);
+ SOSHost.Write(moduleSize, module.FileSize);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ return E_FAIL;
+ }
+ return S_OK;
+ }
+
#endregion
#region ILLDBServices delegates
/// </summary>
public delegate void ModuleLoadCallback(
IntPtr parameter,
- [MarshalAs(UnmanagedType.LPStr)] string moduleFilePath,
- ulong moduleAddress,
- int moduleSize);
+ [In, MarshalAs(UnmanagedType.LPStr)] string moduleFilePath,
+ [In] ulong moduleAddress,
+ [In] int moduleSize);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int LoadNativeSymbolsDelegate2(
IntPtr self,
- bool runtimeOnly,
- ModuleLoadCallback callback);
+ [In] bool runtimeOnly,
+ [In] ModuleLoadCallback callback);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int AddModuleSymbolDelegate(
IntPtr self,
- IntPtr parameter,
- [MarshalAs(UnmanagedType.LPStr)] string symbolFilename);
+ [In] IntPtr parameter,
+ [In, MarshalAs(UnmanagedType.LPStr)] string symbolFilename);
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+ private unsafe delegate int GetModuleInfoDelegate(
+ IntPtr self,
+ [In] uint index,
+ [Out] ulong *moduleBase,
+ [Out] ulong *moduleSize);
+
+ [UnmanagedFunctionPointer(CallingConvention.StdCall)]
+ private delegate int GetModuleVersionInformationDelegate(
+ IntPtr self,
+ [In] uint Index,
+ [In] ulong Base,
+ [In][MarshalAs(UnmanagedType.LPStr)] string Item,
+ [Out] byte* Buffer,
+ [In] uint BufferSize,
+ [Out] uint* VerInfoSize);
#endregion
}
private readonly IConsoleService _console;
private readonly COMCallableIUnknown _ccw;
private readonly IntPtr _interface;
+ private readonly ReadVirtualCache _versionCache;
private IntPtr _sosLibrary = IntPtr.Zero;
private Dictionary<string, PEReader> _pathToPeReader = new Dictionary<string, PEReader>();
_console = serviceProvider.GetService<IConsoleService>();
_analyzeContext = serviceProvider.GetService<AnalyzeContext>();
_registerService = serviceProvider.GetService<RegisterService>();
+ _versionCache = new ReadVirtualCache(this);
string rid = InstallHelper.GetRid();
SOSPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), rid);
uint* nameSize,
ulong* displacement)
{
- nameBuffer.Clear();
+ nameBuffer?.Clear();
Write(nameSize);
Write(displacement);
return E_NOTIMPL;
uint i = 0;
foreach (ModuleInfo module in DataReader.EnumerateModules())
{
- if (index != uint.MaxValue && i == index || index == uint.MaxValue && baseAddress == module.ImageBase)
+ if ((index != uint.MaxValue && i == index) || (index == uint.MaxValue && baseAddress == module.ImageBase))
{
- if (imageNameBuffer != null) {
- imageNameBuffer.Append(module.FileName);
- }
+ imageNameBuffer?.Append(module.FileName);
Write(imageNameSize, (uint)module.FileName.Length + 1);
string moduleName = GetModuleName(module);
- if (moduleNameBuffer != null) {
- moduleNameBuffer.Append(moduleName);
- }
+ moduleNameBuffer?.Append(moduleName);
Write(moduleNameSize, (uint)moduleName.Length + 1);
return S_OK;
}
return S_OK;
}
+ internal unsafe int GetModuleVersionInformation(
+ IntPtr self,
+ uint index,
+ ulong baseAddress,
+ [MarshalAs(UnmanagedType.LPStr)] string item,
+ byte* buffer,
+ uint bufferSize,
+ uint* verInfoSize)
+ {
+ Debug.Assert(buffer != null);
+ Debug.Assert(verInfoSize == null);
+
+ uint i = 0;
+ foreach (ModuleInfo module in DataReader.EnumerateModules())
+ {
+ if ((index != uint.MaxValue && i == index) || (index == uint.MaxValue && baseAddress == module.ImageBase))
+ {
+ if (item == "\\")
+ {
+ uint versionSize = (uint)Marshal.SizeOf(typeof(VS_FIXEDFILEINFO));
+ Write(verInfoSize, versionSize);
+ if (bufferSize < versionSize)
+ {
+ return E_INVALIDARG;
+ }
+ VS_FIXEDFILEINFO* fileInfo = (VS_FIXEDFILEINFO*)buffer;
+ fileInfo->dwSignature = 0;
+ fileInfo->dwStrucVersion = 0;
+ fileInfo->dwFileFlagsMask = 0;
+ fileInfo->dwFileFlags = 0;
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ VersionInfo versionInfo = module.Version;
+ fileInfo->dwFileVersionMS = (uint)versionInfo.Minor | (uint)versionInfo.Major << 16;
+ fileInfo->dwFileVersionLS = (uint)versionInfo.Patch | (uint)versionInfo.Revision << 16;
+ return S_OK;
+ }
+ else
+ {
+ if (SearchVersionString(module, out string versionString))
+ {
+ int spaceIndex = versionString.IndexOf(' ');
+ if (spaceIndex > 0)
+ {
+ if (versionString[spaceIndex - 1] == '.')
+ {
+ spaceIndex--;
+ }
+ string versionToParse = versionString.Substring(0, spaceIndex);
+ try
+ {
+ Version versionInfo = Version.Parse(versionToParse);
+ fileInfo->dwFileVersionMS = (uint)versionInfo.Minor | (uint)versionInfo.Major << 16;
+ fileInfo->dwFileVersionLS = (uint)versionInfo.Revision | (uint)versionInfo.Build << 16;
+ return S_OK;
+ }
+ catch (ArgumentException ex)
+ {
+ Trace.TraceError($"GetModuleVersion FAILURE: '{versionToParse}' '{versionString}' {ex.ToString()}");
+ }
+ }
+ }
+ break;
+ }
+ }
+ else if (item == "\\StringFileInfo\\040904B0\\FileVersion")
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return E_INVALIDARG;
+ }
+ else
+ {
+ if (SearchVersionString(module, out string versionString))
+ {
+ byte[] source = Encoding.ASCII.GetBytes(versionString + '\0');
+ Marshal.Copy(source, 0, new IntPtr(buffer), Math.Min(source.Length, (int)bufferSize));
+ return S_OK;
+ }
+ break;
+ }
+ }
+ else
+ {
+ return E_INVALIDARG;
+ }
+ }
+ i++;
+ }
+
+ return E_FAIL;
+ }
+
+ private static readonly byte[] s_versionString = Encoding.ASCII.GetBytes("@(#)Version ");
+ private static readonly uint s_versionLength = (uint)s_versionString.Length;
+
+ private bool SearchVersionString(ModuleInfo moduleInfo, out string fileVersion)
+ {
+ byte[] buffer = new byte[s_versionString.Length];
+ ulong address = moduleInfo.ImageBase;
+ uint size = moduleInfo.FileSize;
+
+ _versionCache.Clear();
+
+ while (size > 0) {
+ bool result = _versionCache.Read(address, buffer, s_versionString.Length, out int cbBytesRead);
+ if (result && cbBytesRead >= s_versionLength)
+ {
+ if (s_versionString.SequenceEqual(buffer))
+ {
+ address += s_versionLength;
+ size -= s_versionLength;
+
+ var sb = new StringBuilder();
+ byte[] ch = new byte[1];
+ while (true)
+ {
+ // Now read the version string a char/byte at a time
+ result = _versionCache.Read(address, ch, ch.Length, out cbBytesRead);
+
+ // Return not found if there are any failures or problems while reading the version string.
+ if (!result || cbBytesRead < ch.Length || size <= 0) {
+ break;
+ }
+
+ // Found the end of the string
+ if (ch[0] == '\0') {
+ fileVersion = sb.ToString();
+ return true;
+ }
+ sb.Append(Encoding.ASCII.GetChars(ch));
+ address++;
+ size--;
+ }
+ // Return not found if overflowed the fileVersionBuffer (not finding a null).
+ break;
+ }
+ address++;
+ size--;
+ }
+ else
+ {
+ address += s_versionLength;
+ size -= s_versionLength;
+ }
+ }
+
+ fileVersion = null;
+ return false;
+ }
+
internal unsafe int GetLineByOffset(
IntPtr self,
ulong offset,
#endregion
}
+
+ class ReadVirtualCache
+ {
+ private const int CACHE_SIZE = 4096;
+
+ private readonly SOSHost _soshost;
+ private readonly byte[] _cache = new byte[CACHE_SIZE];
+ private ulong _startCache;
+ private bool _cacheValid;
+ private int _cacheSize;
+
+ internal ReadVirtualCache(SOSHost soshost)
+ {
+ _soshost = soshost;
+ Clear();
+ }
+
+ internal bool Read(ulong address, byte[] buffer, int bufferSize, out int bytesRead)
+ {
+ bytesRead = 0;
+
+ if (bufferSize == 0) {
+ return true;
+ }
+
+ if (bufferSize > CACHE_SIZE)
+ {
+ // Don't even try with the cache
+ return _soshost.DataReader.ReadMemory(address, buffer, bufferSize, out bytesRead);
+ }
+
+ if (!_cacheValid || (address < _startCache) || (address > (_startCache + (ulong)(_cacheSize - bufferSize))))
+ {
+ _cacheValid = false;
+ _startCache = address;
+ if (!_soshost.DataReader.ReadMemory(_startCache, _cache, CACHE_SIZE, out int cbBytesRead)) {
+ return false;
+ }
+ _cacheSize = cbBytesRead;
+ _cacheValid = true;
+ }
+
+ Array.Copy(_cache, (int)(address - _startCache), buffer, 0, bufferSize);
+ bytesRead = bufferSize;
+ return true;
+ }
+
+ internal void Clear()
+ {
+ _cacheValid = false;
+ _cacheSize = CACHE_SIZE;
+ }
+ }
}
private static void AddDebugSymbols2(VTableBuilder builder, SOSHost soshost)
{
AddDebugSymbols(builder, soshost);
- builder.AddMethod(new GetModuleVersionInformationDelegate((self, index, baseAddress, item, buffer, bufferSize, verInfoSize) => DebugClient.NotImplemented));
+ builder.AddMethod(new GetModuleVersionInformationDelegate(soshost.GetModuleVersionInformation));
builder.AddMethod(new GetModuleNameStringDelegate((self, which, index, baseAddress, buffer, bufferSize, nameSize) => DebugClient.NotImplemented));
builder.AddMethod(new GetConstantNameDelegate((self, module, typeId, value, buffer, bufferSize, nameSize) => DebugClient.NotImplemented));
builder.AddMethod(new GetFieldNameDelegate((self, module, typeId, fieldIndex, buffer, bufferSize, nameSize) => DebugClient.NotImplemented));
Debugger.Break(); // GCWhere should temp in Gen2
PrintIt(temp);
GC.KeepAlive(temp);
- return 100;
+ return 0;
}
// This is here because without calling something with the object as an argument it'll get optimized away
using System.Threading;
using System.Threading.Tasks;
using Xunit.Abstractions;
+using Xunit.Extensions;
public class SOSRunner : IDisposable
{
WithEnvironmentVariable("COMPlus_DbgEnableMiniDump", "1").
WithEnvironmentVariable("COMPlus_DbgMiniDumpName", ReplaceVariables(variables,"%DUMP_NAME%"));
+ // Exit codes on Windows should always be 0, but not on Linux/OSX for the faulting test apps.
+ if (OS.Kind == OSKind.Windows)
+ {
+ processRunner.WithExpectedExitCode(0);
+ }
+
processRunner.Start();
// Wait for the debuggee to finish
WithLog(scriptLogger).
WithTimeout(TimeSpan.FromMinutes(10));
+ // Exit codes on Windows should always be 0, but not on Linux/OSX for the faulting test apps.
+ if (OS.Kind == OSKind.Windows)
+ {
+ processRunner.WithExpectedExitCode(0);
+ }
+
// Create the sos runner instance
sosRunner = new SOSRunner(debugger, config, outputHelper, variables, scriptLogger, processRunner, options == Options.LoadDump || options == Options.LoadDumpWithDotNetDump);
public async Task RunScript(string scriptRelativePath)
{
- string scriptFile = Path.Combine(_config.ScriptRootDir, scriptRelativePath);
- if (!File.Exists(scriptFile))
- {
- throw new FileNotFoundException("Script file does not exist: " + scriptFile);
- }
- HashSet<string> enabledDefines = GetEnabledDefines();
- LogProcessingReproInfo(scriptFile, enabledDefines);
- string[] scriptLines = File.ReadAllLines(scriptFile);
- Dictionary<string, bool> activeDefines = new Dictionary<string, bool>();
- bool isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines);
- int i = 0;
try
{
- for (; i < scriptLines.Length; i++)
+ string scriptFile = Path.Combine(_config.ScriptRootDir, scriptRelativePath);
+ if (!File.Exists(scriptFile))
{
- string line = scriptLines[i].TrimStart();
- if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#"))
- {
- continue;
- }
- else if (line.StartsWith("IFDEF:"))
- {
- string define = line.Substring("IFDEF:".Length);
- activeDefines.Add(define, true);
- isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines);
- }
- else if (line.StartsWith("!IFDEF:"))
- {
- string define = line.Substring("!IFDEF:".Length);
- activeDefines.Add(define, false);
- isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines);
- }
- else if (line.StartsWith("ENDIF:"))
+ throw new FileNotFoundException("Script file does not exist: " + scriptFile);
+ }
+ HashSet<string> enabledDefines = GetEnabledDefines();
+ LogProcessingReproInfo(scriptFile, enabledDefines);
+ string[] scriptLines = File.ReadAllLines(scriptFile);
+ Dictionary<string, bool> activeDefines = new Dictionary<string, bool>();
+ bool isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines);
+ int i = 0;
+ try
+ {
+ for (; i < scriptLines.Length; i++)
{
- string define = line.Substring("ENDIF:".Length);
- if (!activeDefines.Last().Key.Equals(define))
+ string line = scriptLines[i].TrimStart();
+ if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#"))
{
- throw new Exception("Mismatched IFDEF/ENDIF. IFDEF: " + activeDefines.Last().Key + " ENDIF: " + define);
+ continue;
}
- activeDefines.Remove(define);
- isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines);
- }
- else if (!isActiveDefineRegionEnabled)
- {
- WriteLine(" SKIPPING: {0}", line);
- continue;
- }
- else if (line.StartsWith("LOADSOS"))
- {
- await LoadSosExtension();
- }
- else if (line.StartsWith("CONTINUE"))
- {
- await ContinueExecution();
- }
- else if (line.StartsWith("SOSCOMMAND:"))
- {
- string input = line.Substring("SOSCOMMAND:".Length).TrimStart();
- if (!await RunSosCommand(input))
+ else if (line.StartsWith("IFDEF:"))
{
- throw new Exception($"SOS command FAILED: {input}");
+ string define = line.Substring("IFDEF:".Length);
+ activeDefines.Add(define, true);
+ isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines);
}
- }
- else if (line.StartsWith("COMMAND:"))
- {
- string input = line.Substring("COMMAND:".Length).TrimStart();
- if (!await RunCommand(input))
+ else if (line.StartsWith("!IFDEF:"))
{
- throw new Exception($"Debugger command FAILED: {input}");
+ string define = line.Substring("!IFDEF:".Length);
+ activeDefines.Add(define, false);
+ isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines);
+ }
+ else if (line.StartsWith("ENDIF:"))
+ {
+ string define = line.Substring("ENDIF:".Length);
+ if (!activeDefines.Last().Key.Equals(define))
+ {
+ throw new Exception("Mismatched IFDEF/ENDIF. IFDEF: " + activeDefines.Last().Key + " ENDIF: " + define);
+ }
+ activeDefines.Remove(define);
+ isActiveDefineRegionEnabled = IsActiveDefineRegionEnabled(activeDefines, enabledDefines);
+ }
+ else if (!isActiveDefineRegionEnabled)
+ {
+ WriteLine(" SKIPPING: {0}", line);
+ continue;
+ }
+ else if (line.StartsWith("LOADSOS"))
+ {
+ await LoadSosExtension();
+ }
+ else if (line.StartsWith("CONTINUE"))
+ {
+ await ContinueExecution();
+ }
+ else if (line.StartsWith("SOSCOMMAND:"))
+ {
+ string input = line.Substring("SOSCOMMAND:".Length).TrimStart();
+ if (!await RunSosCommand(input))
+ {
+ throw new Exception($"SOS command FAILED: {input}");
+ }
+ }
+ else if (line.StartsWith("COMMAND:"))
+ {
+ string input = line.Substring("COMMAND:".Length).TrimStart();
+ if (!await RunCommand(input))
+ {
+ throw new Exception($"Debugger command FAILED: {input}");
+ }
+ }
+ else if (line.StartsWith("VERIFY:"))
+ {
+ string verifyLine = line.Substring("VERIFY:".Length);
+ VerifyOutput(verifyLine);
+ }
+ else
+ {
+ continue;
}
}
- else if (line.StartsWith("VERIFY:"))
- {
- string verifyLine = line.Substring("VERIFY:".Length);
- VerifyOutput(verifyLine);
- }
- else
+
+ if (activeDefines.Count != 0)
{
- continue;
+ throw new Exception("Error unbalanced IFDEFs. " + activeDefines.First().Key + " has no ENDIF.");
}
- }
- if (activeDefines.Count != 0)
+ await QuitDebugger();
+ }
+ catch (Exception)
{
- throw new Exception("Error unbalanced IFDEFs. " + activeDefines.First().Key + " has no ENDIF.");
+ WriteLine("SOSRunner error at " + scriptFile + ":" + (i + 1));
+ WriteLine("Excerpt from " + scriptFile + ":");
+ for (int j = Math.Max(0, i - 2); j < Math.Min(i + 3, scriptLines.Length); j++)
+ {
+ WriteLine((j + 1).ToString().PadLeft(5) + " " + scriptLines[j]);
+ }
+ throw;
}
-
- await QuitDebugger();
}
- catch (Exception e)
+ catch (Exception ex)
{
- WriteLine("SOSRunner error at " + scriptFile + ":" + (i + 1));
- WriteLine("Excerpt from " + scriptFile + ":");
- for (int j = Math.Max(0, i - 2); j < Math.Min(i + 3, scriptLines.Length); j++)
- {
- WriteLine((j + 1).ToString().PadLeft(5) + " " + scriptLines[j]);
- }
- WriteLine(e.ToString());
+ WriteLine(ex.ToString());
throw;
}
}
OS.Kind.ToString().ToUpperInvariant(),
_config.TestProduct.ToUpperInvariant(),
_config.TargetArchitecture.ToUpperInvariant(),
- "MAJOR_RUNTIME_VERSION_" + _config.RuntimeFrameworkVersionMajor.ToString()
};
+ try
+ {
+ defines.Add("MAJOR_RUNTIME_VERSION_" + _config.RuntimeFrameworkVersionMajor.ToString());
+ }
+ catch (SkipTestException)
+ {
+ }
if (_isDump)
{
defines.Add("DUMP");
VERIFY:\s+<HEXVAL>\s+<HEXVAL>\s+SymbolTestApp\.Program\.Main\(.*\)\s+\[(?i:.*[\\|/]SymbolTestApp\.cs) @ 19\]\s*
SOSCOMMAND:SetSymbolServer -disable
+# Test eeversion command
+SOSCOMMAND:EEVersion
+VERIFY:\s+<DECVAL>.<DECVAL>.<DECVAL>.<DECVAL>.*
+
# Verify that ClrStack with managed/native mixed works
IFDEF:PROJECTK
SOSCOMMAND:ClrStack -f
CONTINUE
ENDIF:LIVE
+# Test eeversion command
+SOSCOMMAND:EEVersion
+VERIFY:\s+<DECVAL>.<DECVAL>.<DECVAL>.<DECVAL>.*
+
# 1) Verifying that ClrStack with no options works
SOSCOMMAND:ClrStack
VERIFY:.*OS Thread Id:\s+0x<HEXVAL>\s+.*
PDEBUG_CLIENT g_ExtClient;
PDEBUG_DATA_SPACES2 g_ExtData2;
-PDEBUG_SYMBOLS2 g_ExtSymbols2;
PDEBUG_ADVANCED g_ExtAdvanced;
PDEBUG_CLIENT g_pCallbacksClient;
DebugClient* g_DebugClient;
ILLDBServices* g_ExtServices;
+ILLDBServices2* g_ExtServices2;
bool g_palInitialized = false;
#endif // FEATURE_PAL
PDEBUG_DATA_SPACES g_ExtData;
PDEBUG_REGISTERS g_ExtRegisters;
PDEBUG_SYMBOLS g_ExtSymbols;
+PDEBUG_SYMBOLS2 g_ExtSymbols2;
PDEBUG_SYSTEM_OBJECTS g_ExtSystem;
#define SOS_ExtQueryFailGo(var, riid) \
g_palInitialized = true;
}
g_ExtServices = services;
- DebugClient* client = new DebugClient(services);
+ services->QueryInterface(__uuidof(ILLDBServices2), (void**)&g_ExtServices2);
+
+ DebugClient* client = new DebugClient(services, g_ExtServices2);
g_DebugClient = client;
#endif
HRESULT Status;
SOS_ExtQueryFailGo(g_ExtData, IDebugDataSpaces);
SOS_ExtQueryFailGo(g_ExtRegisters, IDebugRegisters);
SOS_ExtQueryFailGo(g_ExtSymbols, IDebugSymbols);
+ SOS_ExtQueryFailGo(g_ExtSymbols2, IDebugSymbols2);
SOS_ExtQueryFailGo(g_ExtSystem, IDebugSystemObjects);
#ifndef FEATURE_PAL
SOS_ExtQueryFailGo(g_ExtData2, IDebugDataSpaces2);
- SOS_ExtQueryFailGo(g_ExtSymbols2, IDebugSymbols2);
SOS_ExtQueryFailGo(g_ExtAdvanced, IDebugAdvanced);
#endif // FEATURE_PAL
return S_OK;
EXT_RELEASE(g_ExtData);
EXT_RELEASE(g_ExtRegisters);
EXT_RELEASE(g_ExtSymbols);
+ EXT_RELEASE(g_ExtSymbols2);
EXT_RELEASE(g_ExtSystem);
#ifndef FEATURE_PAL
EXT_RELEASE(g_ExtData2);
- EXT_RELEASE(g_ExtSymbols2);
EXT_RELEASE(g_ExtAdvanced);
g_ExtClient = NULL;
#else
EXT_RELEASE(g_DebugClient);
+ EXT_RELEASE(g_ExtServices2);
g_ExtServices = NULL;
#endif // FEATURE_PAL
}
InterfaceId == __uuidof(IDebugControl4) ||
InterfaceId == __uuidof(IDebugDataSpaces) ||
InterfaceId == __uuidof(IDebugSymbols) ||
+ InterfaceId == __uuidof(IDebugSymbols2) ||
InterfaceId == __uuidof(IDebugSystemObjects) ||
InterfaceId == __uuidof(IDebugRegisters))
{
if (ref == 0)
{
m_lldbservices->Release();
+ if (m_lldbservices2 != nullptr) {
+ m_lldbservices2->Release();
+ }
delete this;
}
return ref;
extern PDEBUG_CONTROL2 g_ExtControl;
extern PDEBUG_DATA_SPACES g_ExtData;
extern PDEBUG_SYMBOLS g_ExtSymbols;
+extern PDEBUG_SYMBOLS2 g_ExtSymbols2;
extern PDEBUG_SYSTEM_OBJECTS g_ExtSystem;
extern PDEBUG_REGISTERS g_ExtRegisters;
// Global variables initialized by query.
extern PDEBUG_CLIENT g_ExtClient;
extern PDEBUG_DATA_SPACES2 g_ExtData2;
-extern PDEBUG_SYMBOLS2 g_ExtSymbols2;
extern PDEBUG_ADVANCED g_ExtAdvanced;
bool
#else // FEATURE_PAL
extern ILLDBServices* g_ExtServices;
+extern ILLDBServices2* g_ExtServices2;
#define IsInitializedByDbgEng() false
}
#else
ULONG index;
- HRESULT Status = g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, &index, NULL);
+ HRESULT Status = GetRuntimeModuleInfo(&index, NULL);
if (FAILED(Status))
{
ExtErr("Error: Runtime module (%s) not loaded yet\n", MAKEDLLNAME_A("coreclr"));
dacModulePath.append(DIRECTORY_SEPARATOR_STR_A);
dacModulePath.append(MAKEDLLNAME_A("mscordaccore"));
#ifdef FEATURE_PAL
- // if DAC file exists
+ // If DAC file exists in the runtime directory
if (access(dacModulePath.c_str(), F_OK) == 0)
#endif
{
dbiModulePath.append(DIRECTORY_SEPARATOR_STR_A);
dbiModulePath.append(MAKEDLLNAME_A("mscordbi"));
#ifdef FEATURE_PAL
- // if DBI file exists
+ // If DBI file exists in the runtime directory
if (access(dbiModulePath.c_str(), F_OK) == 0)
#endif
{
return;
}
#ifdef FEATURE_PAL
- ToRelease<ILLDBServices2> services2(NULL);
- HRESULT Status = g_ExtServices->QueryInterface(__uuidof(ILLDBServices2), (void**)&services2);
- if (SUCCEEDED(Status))
+ if (g_ExtServices2 != nullptr)
{
- services2->AddModuleSymbol(param, symbolFilePath);
+ g_ExtServices2->AddModuleSymbol(param, symbolFilePath);
}
#endif
}
if (g_symbolStoreInitialized)
{
#ifdef FEATURE_PAL
- ToRelease<ILLDBServices2> services2(NULL);
- hr = g_ExtServices->QueryInterface(__uuidof(ILLDBServices2), (void**)&services2);
- if (SUCCEEDED(hr))
- {
- hr = services2->LoadNativeSymbols(runtimeOnly, LoadNativeSymbolsCallback);
- }
+ hr = g_ExtServices2 ? g_ExtServices2->LoadNativeSymbols(runtimeOnly, LoadNativeSymbolsCallback) : E_NOINTERFACE;
#else
if (runtimeOnly)
{
ULONG index;
ULONG64 moduleAddress;
- HRESULT hr = g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, &index, &moduleAddress);
+ HRESULT hr = GetRuntimeModuleInfo(&index, &moduleAddress);
if (SUCCEEDED(hr))
{
ArrayHolder<char> moduleFilePath = new char[MAX_LONGPATH + 1];
DumpStackObjects
DumpVC
EEHeap
+EEVersion
GCWhere
EEStack
EHInfo
DumpStackWorker(*pDSFlag);
}
+
DECLARE_API(DumpStack)
{
INIT_API_NO_RET_ON_FAILURE();
ExtOut("NumThreadStaticFields: %x\n", vMethodTableFields.wNumThreadStaticFields);
}
+
+ if (vMethodTableFields.wContextStaticsSize)
+ {
+ ExtOut("ContextStaticOffset: %x\n", vMethodTableFields.wContextStaticOffset);
+ ExtOut("ContextStaticsSize: %x\n", vMethodTableFields.wContextStaticsSize);
+ }
+
+
if (vMethodTableFields.wNumInstanceFields + vMethodTableFields.wNumStaticFields > 0)
{
DisplayFields(methodTable, &mtdata, &vMethodTableFields, NULL, TRUE, FALSE);
// did we get dll and type name or file:line#? Search for a colon in the first arg
// to see if it is in fact a file:line#
CHAR* pColon = strchr(DllName.data, ':');
-#ifndef FEATURE_PAL
- if (FAILED(g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, NULL, NULL))) {
-#else
- if (FAILED(g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_DLL_NAME_A, 0, NULL, NULL))) {
-#endif
+ if (FAILED(GetRuntimeModuleInfo(NULL, NULL))) {
ExtOut("%s not loaded yet\n", MAIN_CLR_DLL_NAME_A);
return Status;
}
#endif //GC_CONFIG_DRIVEN
}
-#ifndef FEATURE_PAL
/**********************************************************************\
* Routine Description: *
* *
ExtOut("CLR not loaded\n");
return Status;
}
-
- if (g_ExtSymbols2) {
- VS_FIXEDFILEINFO version;
-
- BOOL ret = GetEEVersion(&version);
-
- if (ret)
- {
- if (version.dwFileVersionMS != (DWORD)-1)
- {
- ExtOut("%u.%u.%u.%u",
- HIWORD(version.dwFileVersionMS),
- LOWORD(version.dwFileVersionMS),
- HIWORD(version.dwFileVersionLS),
- LOWORD(version.dwFileVersionLS));
- if (version.dwFileFlags & VS_FF_DEBUG)
- {
- ExtOut(" Checked or debug build");
- }
- else
- {
- BOOL fRet = IsRetailBuild ((size_t)g_moduleInfo[eef].baseAddr);
+ static const int fileVersionBufferSize = 1024;
+ ArrayHolder<char> fileVersionBuffer = new char[fileVersionBufferSize];
+ VS_FIXEDFILEINFO version;
- if (fRet)
- ExtOut(" retail");
- else
- ExtOut(" free");
- }
+ BOOL ret = GetEEVersion(&version, fileVersionBuffer.GetPtr(), fileVersionBufferSize);
+ if (ret)
+ {
+ if (version.dwFileVersionMS != (DWORD)-1)
+ {
+ ExtOut("%u.%u.%u.%u",
+ HIWORD(version.dwFileVersionMS),
+ LOWORD(version.dwFileVersionMS),
+ HIWORD(version.dwFileVersionLS),
+ LOWORD(version.dwFileVersionLS));
+#ifndef FEATURE_PAL
+ if (version.dwFileFlags & VS_FF_DEBUG)
+ {
+ ExtOut(" Checked or debug build");
+ }
+ else
+ {
+ BOOL fRet = IsRetailBuild ((size_t)g_moduleInfo[eef].baseAddr);
+ if (fRet)
+ ExtOut(" retail");
+ else
+ ExtOut(" free");
+ }
+#endif
+ ExtOut("\n");
- ExtOut("\n");
+ if (fileVersionBuffer[0] != '\0')
+ {
+ ExtOut("%s\n", fileVersionBuffer.GetPtr());
}
}
- }
+ }
if (!InitializeHeapData ())
ExtOut("GC Heap not initialized, so GC mode is not determined yet.\n");
ExtOut("In plan phase of garbage collection\n");
}
+#ifndef FEATURE_PAL
// Print SOS version
VS_FIXEDFILEINFO sosVersion;
if (GetSOSVersion(&sosVersion))
LOWORD(sosVersion.dwFileVersionMS),
HIWORD(sosVersion.dwFileVersionLS),
LOWORD(sosVersion.dwFileVersionLS));
+
if (sosVersion.dwFileFlags & VS_FF_DEBUG)
{
ExtOut(" Checked or debug build");
{
ExtOut(" retail build");
}
-
ExtOut("\n");
}
}
+#endif // FEATURE_PAL
return Status;
}
-#endif // FEATURE_PAL
#ifndef FEATURE_PAL
/**********************************************************************\
{
if(g_clrBaseAddr == 0)
{
- g_ExtSymbols->GetModuleByModuleName (MAIN_CLR_MODULE_NAME_A,0,NULL,
- &g_clrBaseAddr);
+ GetRuntimeModuleInfo(NULL, &g_clrBaseAddr);
}
if(g_clrBaseAddr == base)
{
else if(g_ExtSymbols->GetModuleByOffset (ip, 0, NULL, &base) == S_OK)
{
ULONG64 clrBaseAddr = 0;
- if(SUCCEEDED(g_ExtSymbols->GetModuleByModuleName (MAIN_CLR_MODULE_NAME_A,0,NULL, &clrBaseAddr)) && base==clrBaseAddr)
+ if(SUCCEEDED(GetRuntimeModuleInfo(NULL, &clrBaseAddr)) && base==clrBaseAddr)
{
ExtOut("Compiled code in CLR");
codeType = 4;
#endif // FEATURE_PAL
-ModuleInfo g_moduleInfo[MSCOREND] = {{0, FALSE, 0}, {0, FALSE, 0}, {0, FALSE, 0}};
+ModuleInfo g_moduleInfo[MSCOREND] = {{0, 0, DEBUG_ANY_ID, FALSE}, {0, 0, DEBUG_ANY_ID, FALSE}, {0, 0, DEBUG_ANY_ID, FALSE}};
void ReportOOM()
{
ExtOut("SOS Error: Out of memory\n");
}
+HRESULT GetRuntimeModuleInfo(PULONG moduleIndex, PULONG64 moduleBase)
+{
+#ifdef FEATURE_PAL
+ return g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_DLL_NAME_A, 0, moduleIndex, moduleBase);
+#else
+ return g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, moduleIndex, moduleBase);
+#endif
+}
+
HRESULT CheckEEDll()
{
-#ifndef FEATURE_PAL
- // Do we have coreclr.dll
+ HRESULT hr = S_OK;
+
+ // Do we have runtime module info?
if (g_moduleInfo[MSCORWKS].baseAddr == 0)
{
- DEBUG_MODULE_PARAMETERS Params;
-
- g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A, 0, NULL, &g_moduleInfo[MSCORWKS].baseAddr);
- if (g_moduleInfo[MSCORWKS].baseAddr != 0 && g_moduleInfo[MSCORWKS].hasPdb == FALSE)
+ hr = GetRuntimeModuleInfo(&g_moduleInfo[MSCORWKS].index, &g_moduleInfo[MSCORWKS].baseAddr);
+#ifdef FEATURE_PAL
+ if (SUCCEEDED(hr))
{
- g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, &Params);
- if (Params.SymbolType == SymDeferred)
+ if (g_ExtServices2 != nullptr)
{
- g_ExtSymbols->Reload("/f " MAIN_CLR_DLL_NAME_A);
- g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, &Params);
+ g_ExtServices2->GetModuleInfo(g_moduleInfo[MSCORWKS].index, nullptr, &g_moduleInfo[MSCORWKS].size);
}
- if (Params.SymbolType == SymPdb || Params.SymbolType == SymDia)
+ }
+#else
+ if (g_moduleInfo[MSCORWKS].baseAddr != 0 && g_moduleInfo[MSCORWKS].hasPdb == FALSE)
+ {
+ DEBUG_MODULE_PARAMETERS params;
+ if (SUCCEEDED(g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, ¶ms)))
{
- g_moduleInfo[MSCORWKS].hasPdb = TRUE;
+ if (params.SymbolType == SymDeferred)
+ {
+ g_ExtSymbols->Reload("/f " MAIN_CLR_DLL_NAME_A);
+ g_ExtSymbols->GetModuleParameters(1, &g_moduleInfo[MSCORWKS].baseAddr, 0, ¶ms);
+ }
+ if (params.SymbolType == SymPdb || params.SymbolType == SymDia)
+ {
+ g_moduleInfo[MSCORWKS].hasPdb = TRUE;
+ }
+ g_moduleInfo[MSCORWKS].size = params.Size;
}
- g_moduleInfo[MSCORWKS].size = Params.Size;
}
if (g_moduleInfo[MSCORWKS].baseAddr != 0 && g_moduleInfo[MSCORWKS].hasPdb == FALSE)
{
ExtOut("PDB symbol for coreclr.dll not loaded\n");
}
- }
- return (g_moduleInfo[MSCORWKS].baseAddr != 0) ? S_OK : E_FAIL;
-#else
- return S_OK;
#endif // FEATURE_PAL
+ }
+ return hr;
}
EEFLAVOR GetEEFlavor()
return MSCORWKS;
#else // FEATUER_PAL
EEFLAVOR flavor = UNKNOWNEE;
-
- if (SUCCEEDED(g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_MODULE_NAME_A,0,NULL,NULL))) {
+ if (SUCCEEDED(GetRuntimeModuleInfo(NULL, NULL))) {
flavor = MSCORWKS;
}
return flavor;
return "UNKNOWN";
}
-void DumpTieredNativeCodeAddressInfo(struct DacpTieredVersionData * pTieredVersionData,
- const UINT cTieredVersionData, ULONG rejitID, CLRDATA_ADDRESS ilAddr, CLRDATA_ADDRESS ilNodeAddr)
+// 2.x version
+void DumpTieredNativeCodeAddressInfo_2x(struct DacpTieredVersionData_2x * pTieredVersionData, const UINT cTieredVersionData)
{
for(int i = cTieredVersionData - 1; i >= 0; --i)
{
- ExtOut(" NativeCodeVersion: %p\n", SOS_PTR(pTieredVersionData[i].NativeCodeVersionNodePtr));
-
const char *descriptor = NULL;
- switch(pTieredVersionData[i].OptimizationTier)
+ switch(pTieredVersionData[i].TieredInfo)
{
- case DacpTieredVersionData::OptimizationTier_Unknown:
+ case DacpTieredVersionData_2x::TIERED_UNKNOWN:
default:
descriptor = "Unknown Tier";
break;
- case DacpTieredVersionData::OptimizationTier_MinOptJitted:
- descriptor = "MinOptJitted";
- break;
- case DacpTieredVersionData::OptimizationTier_Optimized:
- descriptor = "Optimized";
+ case DacpTieredVersionData_2x::NON_TIERED:
+ descriptor = "Non-Tiered";
break;
- case DacpTieredVersionData::OptimizationTier_QuickJitted:
- descriptor = "QuickJitted";
+ case DacpTieredVersionData_2x::TIERED_0:
+ descriptor = "Tier 0";
break;
- case DacpTieredVersionData::OptimizationTier_OptimizedTier1:
- descriptor = "OptimizedTier1";
- break;
- case DacpTieredVersionData::OptimizationTier_ReadyToRun:
- descriptor = "ReadyToRun";
+ case DacpTieredVersionData_2x::TIERED_1:
+ descriptor = "Tier 1";
break;
}
+ DMLOut(" CodeAddr: %s (%s)\n", DMLIP(pTieredVersionData[i].NativeCodeAddr), descriptor);
+ ExtOut(" NativeCodeVersion: %p\n", SOS_PTR(pTieredVersionData[i].NativeCodeVersionNodePtr));
+ }
+}
- ExtOut(" ReJIT ID: %d\n", rejitID);
- DMLOut(" CodeAddr: %s (%s)\n", DMLIP(pTieredVersionData[i].NativeCodeAddr), descriptor);
- DMLOut(" IL Addr: %s\n", DMLIL(ilAddr));
- ExtOut(" ILCodeVersion: %p\n", SOS_PTR(ilNodeAddr));
+void DumpTieredNativeCodeAddressInfo(struct DacpTieredVersionData * pTieredVersionData, const UINT cTieredVersionData,
+ ULONG rejitID, CLRDATA_ADDRESS ilAddr, CLRDATA_ADDRESS ilNodeAddr)
+{
+ ExtOut(" ILCodeVersion: %p\n", SOS_PTR(ilNodeAddr));
+ ExtOut(" ReJIT ID: %d\n", rejitID);
+ DMLOut(" IL Addr: %s\n", DMLIL(ilAddr));
+ if (IsRuntimeVersion(3)) {
+ for(int i = cTieredVersionData - 1; i >= 0; --i)
+ {
+ const char *descriptor = NULL;
+ switch(pTieredVersionData[i].OptimizationTier)
+ {
+ case DacpTieredVersionData::OptimizationTier_Unknown:
+ default:
+ descriptor = "Unknown Tier";
+ break;
+ case DacpTieredVersionData::OptimizationTier_MinOptJitted:
+ descriptor = "MinOptJitted";
+ break;
+ case DacpTieredVersionData::OptimizationTier_Optimized:
+ descriptor = "Optimized";
+ break;
+ case DacpTieredVersionData::OptimizationTier_QuickJitted:
+ descriptor = "QuickJitted";
+ break;
+ case DacpTieredVersionData::OptimizationTier_OptimizedTier1:
+ descriptor = "OptimizedTier1";
+ break;
+ case DacpTieredVersionData::OptimizationTier_ReadyToRun:
+ descriptor = "ReadyToRun";
+ break;
+ }
+ DMLOut(" CodeAddr: %s (%s)\n", DMLIP(pTieredVersionData[i].NativeCodeAddr), descriptor);
+ ExtOut(" NativeCodeVersion: %p\n", SOS_PTR(pTieredVersionData[i].NativeCodeVersionNodePtr));
+ }
+ }
+ else {
+ DumpTieredNativeCodeAddressInfo_2x((DacpTieredVersionData_2x*)pTieredVersionData, cTieredVersionData);
}
}
{
// Special case, there is no jitted code yet but still need to output the IL information
ExtOut(" ILCodeVersion: %p (pending)\n", SOS_PTR(pendingRejitData.ilCodeVersionNodePtr));
- ExtOut(" ReJIT ID: %d\n", pendingRejitID);
- DMLOut(" IL Addr: %s\n", DMLIL(pendingRejitData.il));
+ ExtOut(" ReJIT ID: %d\n", pendingRejitID);
+ DMLOut(" IL Addr: %s\n", DMLIL(pendingRejitData.il));
}
}
return (size_t) pMD;
}
-#ifndef FEATURE_PAL
-
//
// Gets version info for the CLR in the debuggee process.
//
-BOOL GetEEVersion(VS_FIXEDFILEINFO *pFileInfo)
+BOOL GetEEVersion(VS_FIXEDFILEINFO* pFileInfo, char* fileVersionBuffer, int fileVersionBufferSizeInBytes)
{
- _ASSERTE(g_ExtSymbols2);
_ASSERTE(pFileInfo);
+ if (g_ExtSymbols2 == nullptr) {
+ return FALSE;
+ }
+ ModuleInfo moduleInfo = g_moduleInfo[GetEEFlavor()];
+ _ASSERTE(moduleInfo.index != DEBUG_ANY_ID);
+
+#ifdef FEATURE_PAL
+ // Load the symbols for runtime. On Linux we are looking for the "sccsid"
+ // global so "libcoreclr.so/.dylib" symbols need to be loaded.
+ LoadNativeSymbols(true);
+#endif
+
+ HRESULT hr = g_ExtSymbols2->GetModuleVersionInformation(moduleInfo.index, 0, "\\", pFileInfo, sizeof(VS_FIXEDFILEINFO), NULL);
+
+ // Attempt to get the the FileVersion string that contains version and the "built by" and commit id info
+ if (fileVersionBuffer != nullptr)
+ {
+ if (fileVersionBufferSizeInBytes > 0) {
+ fileVersionBuffer[0] = '\0';
+ }
+ // We can assume the English/CP_UNICODE lang/code page for the runtime modules
+ g_ExtSymbols2->GetModuleVersionInformation(
+ moduleInfo.index, 0, "\\StringFileInfo\\040904B0\\FileVersion", fileVersionBuffer, fileVersionBufferSizeInBytes, NULL);
+ }
- // Grab the version info directly from the module.
- return g_ExtSymbols2->GetModuleVersionInformation(
- DEBUG_ANY_ID, g_moduleInfo[GetEEFlavor()].baseAddr, "\\", pFileInfo, sizeof(VS_FIXEDFILEINFO), NULL) == S_OK;
+ return SUCCEEDED(hr);
+}
+
+//
+// Return true if major runtime version (logical product version like 2.1,
+// 3.0 or 5.x). Currently only major versions of 3 or 5 are supported.
+//
+bool IsRuntimeVersion(DWORD major)
+{
+ VS_FIXEDFILEINFO fileInfo;
+ if (GetEEVersion(&fileInfo, nullptr, 0))
+ {
+ switch (major)
+ {
+ case 5:
+ return HIWORD(fileInfo.dwFileVersionMS) == 5;
+ case 3:
+ return HIWORD(fileInfo.dwFileVersionMS) == 4 && LOWORD(fileInfo.dwFileVersionMS) == 700;
+ default:
+ _ASSERTE(FALSE);
+ break;
+ }
+ }
+ return false;
}
+#ifndef FEATURE_PAL
+
BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo)
{
_ASSERTE(pFileInfo);
return E_FAIL;
#else
ULONG64 ulBase;
- hr = g_ExtSymbols->GetModuleByModuleName(MAIN_CLR_DLL_NAME_A, 0, NULL, &ulBase);
+ hr = GetRuntimeModuleInfo(NULL, &ulBase);
if (SUCCEEDED(hr))
{
hr = InitCorDebugInterfaceFromModule(ulBase, pClrDebugging);
return E_ACCESSDENIED;
}
-#endif // FEATURE_PAL
\ No newline at end of file
+#endif // FEATURE_PAL
{
ULONG64 baseAddr;
ULONG64 size;
+ ULONG index;
BOOL hasPdb;
};
extern ModuleInfo g_moduleInfo[];
void DecodeIL(IMetaDataImport *pImport, BYTE *buffer, ULONG bufSize);
void DecodeDynamicIL(BYTE *data, ULONG Size, DacpObjectData& tokenArray);
-BOOL IsRetailBuild (size_t base);
+HRESULT GetRuntimeModuleInfo(PULONG moduleIndex, PULONG64 moduleBase);
EEFLAVOR GetEEFlavor ();
HRESULT InitCorDebugInterface();
VOID UninitCorDebugInterface();
+BOOL GetEEVersion(VS_FIXEDFILEINFO* pFileInfo, char* fileVersionBuffer, int fileVersionBufferSizeInBytes);
+bool IsRuntimeVersion(DWORD major);
#ifndef FEATURE_PAL
-BOOL GetEEVersion(VS_FIXEDFILEINFO *pFileInfo);
+BOOL IsRetailBuild (size_t base);
BOOL GetSOSVersion(VS_FIXEDFILEINFO *pFileInfo);
#endif
{
private:
LONG m_ref;
- ILLDBServices *m_lldbservices;
+ ILLDBServices* m_lldbservices;
+ ILLDBServices2* m_lldbservices2;
public:
- DebugClient(ILLDBServices *lldbservices) :
+ DebugClient(ILLDBServices* lldbservices, ILLDBServices2* lldbservices2) :
m_ref(1),
- m_lldbservices(lldbservices)
+ m_lldbservices(lldbservices),
+ m_lldbservices2(lldbservices2)
{
m_lldbservices->AddRef();
+ if (m_lldbservices2 != nullptr) {
+ m_lldbservices2->AddRef();
+ }
}
//----------------------------------------------------------------------------
moduleNameBufferSize, moduleNameSize, loadedImageNameBuffer, loadedImageNameBufferSize, loadedImageNameSize);
}
+ HRESULT
+ GetModuleVersionInformation(
+ ULONG index,
+ ULONG64 base,
+ PCSTR item,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG versionInfoSize)
+ {
+ if (m_lldbservices2 == nullptr) {
+ return E_NOINTERFACE;
+ }
+ return m_lldbservices2->GetModuleVersionInformation(index, base, item, buffer, bufferSize, versionInfoSize);
+ }
+
HRESULT
GetLineByOffset(
ULONG64 offset,
{
};
+MIDL_INTERFACE("3a707211-afdd-4495-ad4f-56fecdf8163f")
+IDebugSymbols2 : DebugClient
+{
+};
+
MIDL_INTERFACE("6b86fe2c-2c4f-4f0c-9da2-174311acc327")
IDebugSystemObjects : DebugClient
{
typedef interface IDebugControl4* PDEBUG_CONTROL4;
typedef interface IDebugDataSpaces* PDEBUG_DATA_SPACES;
typedef interface IDebugSymbols* PDEBUG_SYMBOLS;
+typedef interface IDebugSymbols2* PDEBUG_SYMBOLS2;
typedef interface IDebugSystemObjects* PDEBUG_SYSTEM_OBJECTS;
typedef interface IDebugRegisters* PDEBUG_REGISTERS;
virtual HRESULT AddModuleSymbol(
void* param,
const char* symbolFilePath) = 0;
+
+ virtual HRESULT GetModuleInfo(
+ ULONG index,
+ PULONG64 base,
+ PULONG64 size) = 0;
+
+ virtual HRESULT GetModuleVersionInformation(
+ ULONG index,
+ ULONG64 base,
+ PCSTR item,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG versionInfoSize) = 0;
};
#ifdef __cplusplus
#include <string>
#include <dlfcn.h>
#include <pthread.h>
+#include <arrayholder.h>
#define CONVERT_FROM_SIGN_EXTENDED(offset) ((ULONG_PTR)(offset))
m_currentProcess(process),
m_currentThread(thread)
{
+ ClearCache();
returnObject.SetStatus(lldb::eReturnStatusSuccessFinishResult);
}
ULONG index,
PULONG64 base)
{
- ULONG64 moduleBase = UINT64_MAX;
-
lldb::SBTarget target;
lldb::SBModule module;
target = m_debugger.GetSelectedTarget();
if (!target.IsValid())
{
- goto exit;
+ return E_INVALIDARG;
}
module = target.GetModuleAtIndex(index);
if (!module.IsValid())
{
- goto exit;
+ return E_INVALIDARG;
}
- moduleBase = GetModuleBase(target, module);
-
-exit:
if (base)
{
+ ULONG64 moduleBase = GetModuleBase(target, module);
+ if (moduleBase == UINT64_MAX)
+ {
+ return E_INVALIDARG;
+ }
*base = moduleBase;
}
- return moduleBase == UINT64_MAX ? E_FAIL : S_OK;
+ return S_OK;
}
HRESULT
PULONG index,
PULONG64 base)
{
- ULONG64 moduleBase = UINT64_MAX;
- ULONG moduleIndex = UINT32_MAX;
-
lldb::SBTarget target;
lldb::SBModule module;
lldb::SBFileSpec fileSpec;
target = m_debugger.GetSelectedTarget();
if (!target.IsValid())
{
- goto exit;
+ return E_INVALIDARG;
}
module = target.FindModule(fileSpec);
if (!module.IsValid())
{
- goto exit;
+ return E_INVALIDARG;
}
- moduleBase = GetModuleBase(target, module);
+ if (base)
+ {
+ ULONG64 moduleBase = GetModuleBase(target, module);
+ if (moduleBase == UINT64_MAX)
+ {
+ return E_INVALIDARG;
+ }
+ *base = moduleBase;
+ }
if (index)
{
lldb::SBModule mod = target.GetModuleAtIndex(mi);
if (module == mod)
{
- moduleIndex = mi;
+ *index = mi;
break;
}
}
}
-exit:
- if (index)
- {
- *index = moduleIndex;
- }
- if (base)
- {
- *base = moduleBase;
- }
- return moduleBase == UINT64_MAX ? E_FAIL : S_OK;
+ return S_OK;
}
HRESULT
PULONG index,
PULONG64 base)
{
- ULONG64 moduleBase = UINT64_MAX;
- ULONG moduleIndex = UINT32_MAX;
-
lldb::SBTarget target;
int numModules;
target = m_debugger.GetSelectedTarget();
if (!target.IsValid())
{
- goto exit;
+ return E_INVALIDARG;
}
numModules = target.GetNumModules();
lldb::addr_t baseAddress = section.GetLoadAddress(target);
if (baseAddress != LLDB_INVALID_ADDRESS)
{
- if (offset > baseAddress)
+ if (offset >= baseAddress)
{
if ((offset - baseAddress) < section.GetByteSize())
{
- moduleIndex = mi;
- moduleBase = baseAddress - section.GetFileOffset();
- goto exit;
+ if (index)
+ {
+ *index = mi;
+ }
+ if (base)
+ {
+ *base = baseAddress - section.GetFileOffset();
+ }
+ return S_OK;
}
}
}
}
}
-exit:
- if (index)
- {
- *index = moduleIndex;
- }
- if (base)
- {
- *base = moduleBase;
- }
- return moduleBase == UINT64_MAX ? E_FAIL : S_OK;
+ return E_FAIL;
}
HRESULT
{
lldb::SBTarget target;
lldb::SBFileSpec fileSpec;
- HRESULT hr = S_OK;
// lldb doesn't expect sign-extended address
base = CONVERT_FROM_SIGN_EXTENDED(base);
target = m_debugger.GetSelectedTarget();
if (!target.IsValid())
{
- hr = E_FAIL;
- goto exit;
+ return E_INVALIDARG;
}
-
if (index != DEBUG_ANY_ID)
{
lldb::SBModule module = target.GetModuleAtIndex(index);
}
}
}
-
if (!fileSpec.IsValid())
{
- hr = E_FAIL;
- goto exit;
+ return E_INVALIDARG;
}
-
-exit:
if (imageNameBuffer)
{
int size = fileSpec.GetPath(imageNameBuffer, imageNameBufferSize);
*loadedImageNameSize = size;
}
}
- return hr;
+ return S_OK;
}
HRESULT
return UINT64_MAX;
}
+ULONG64
+LLDBServices::GetModuleSize(
+ /* const */ lldb::SBModule& module)
+{
+ ULONG64 size = 0;
+
+ // Find the first section with an valid base address
+ int numSections = module.GetNumSections();
+ for (int si = 0; si < numSections; si++)
+ {
+ lldb::SBSection section = module.GetSectionAtIndex(si);
+ if (section.IsValid())
+ {
+ size += section.GetByteSize();
+ }
+ }
+
+ return size;
+}
+
//----------------------------------------------------------------------------
// IDebugSystemObjects
//----------------------------------------------------------------------------
if (directory != nullptr && filename != nullptr)
{
ULONG64 moduleAddress = GetModuleBase(target, module);
- int moduleSize = INT32_MAX;
if (moduleAddress != UINT64_MAX)
{
std::string path(directory);
path.append("/");
path.append(filename);
+ int moduleSize = GetModuleSize(module);
+
callback(&module, path.c_str(), moduleAddress, moduleSize);
}
}
return Execute(DEBUG_EXECUTE_NOT_LOGGED, command.c_str(), 0);
}
+HRESULT LLDBServices::GetModuleInfo(
+ ULONG index,
+ PULONG64 pBase,
+ PULONG64 pSize)
+{
+ lldb::SBTarget target;
+ lldb::SBModule module;
+
+ target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ return E_INVALIDARG;
+ }
+
+ module = target.GetModuleAtIndex(index);
+ if (!module.IsValid())
+ {
+ return E_INVALIDARG;
+ }
+
+ if (pBase)
+ {
+ ULONG64 moduleBase = GetModuleBase(target, module);
+ if (moduleBase == UINT64_MAX)
+ {
+ return E_INVALIDARG;
+ }
+ *pBase = moduleBase;
+ }
+
+ if (pSize)
+ {
+ *pSize = GetModuleSize(module);
+ }
+
+ return S_OK;
+}
+
+#define VersionBufferSize 1024
+
+HRESULT
+LLDBServices::GetModuleVersionInformation(
+ ULONG index,
+ ULONG64 base,
+ PCSTR item,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG versionInfoSize)
+{
+ // Only support a narrow set of argument values
+ if (index == DEBUG_ANY_ID || buffer == nullptr || versionInfoSize != nullptr)
+ {
+ return E_INVALIDARG;
+ }
+ lldb::SBTarget target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ return E_INVALIDARG;
+ }
+ lldb::SBModule module = target.GetModuleAtIndex(index);
+ if (!module.IsValid())
+ {
+ return E_INVALIDARG;
+ }
+ const char* versionString = nullptr;
+ lldb::SBValue value;
+ lldb::SBData data;
+
+ value = module.FindFirstGlobalVariable(target, "sccsid");
+ if (value.IsValid())
+ {
+ data = value.GetData();
+ if (data.IsValid())
+ {
+ lldb::SBError error;
+ versionString = data.GetString(error, 0);
+ if (error.Fail())
+ {
+ versionString = nullptr;
+ }
+ }
+ }
+
+ ArrayHolder<char> versionBuffer = nullptr;
+ if (versionString == nullptr)
+ {
+ versionBuffer = new char[VersionBufferSize];
+
+ int numSections = module.GetNumSections();
+ for (int si = 0; si < numSections; si++)
+ {
+ lldb::SBSection section = module.GetSectionAtIndex(si);
+ if (GetVersionStringFromSection(target, section, versionBuffer.GetPtr()))
+ {
+ versionString = versionBuffer;
+ break;
+ }
+ }
+ }
+
+ if (versionString == nullptr)
+ {
+ return E_FAIL;
+ }
+
+ if (strcmp(item, "\\") == 0)
+ {
+ if (bufferSize < sizeof(VS_FIXEDFILEINFO))
+ {
+ return E_INVALIDARG;
+ }
+ DWORD major, minor, build, revision;
+ if (sscanf(versionString, "@(#)Version %u.%u.%u.%u", &major, &minor, &build, &revision) != 4)
+ {
+ return E_FAIL;
+ }
+ memset(buffer, 0, sizeof(VS_FIXEDFILEINFO));
+ ((VS_FIXEDFILEINFO*)buffer)->dwFileVersionMS = MAKELONG(minor, major);
+ ((VS_FIXEDFILEINFO*)buffer)->dwFileVersionLS = MAKELONG(revision, build);
+ }
+ else if (strcmp(item, "\\StringFileInfo\\040904B0\\FileVersion") == 0)
+ {
+ if (bufferSize < (strlen(versionString) - sizeof("@(#)Version")))
+ {
+ return E_INVALIDARG;
+ }
+ stpncpy((char*)buffer, versionString + sizeof("@(#)Version"), bufferSize);
+ }
+ else
+ {
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
//----------------------------------------------------------------------------
// Helper functions
//----------------------------------------------------------------------------
}
return g_pluginModuleDirectory;
}
+
+bool
+LLDBServices::GetVersionStringFromSection(lldb::SBTarget& target, lldb::SBSection& section, char* versionBuffer)
+{
+ if (section.IsValid())
+ {
+ lldb::SectionType sectionType = section.GetSectionType();
+
+ if (sectionType == lldb::eSectionTypeContainer)
+ {
+ int numSubSections = section.GetNumSubSections();
+ for (int subsi = 0; subsi < numSubSections; subsi++)
+ {
+ lldb::SBSection subSection = section.GetSubSectionAtIndex(subsi);
+ if (GetVersionStringFromSection(target, subSection, versionBuffer)) {
+ return true;
+ }
+ }
+ }
+ else if (sectionType == lldb::eSectionTypeData)
+ {
+ lldb::addr_t address = section.GetLoadAddress(target);
+ uint32_t size = section.GetByteSize();
+ if (SearchVersionString(address, size, versionBuffer, VersionBufferSize)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+#define VersionLength 12
+static const char* g_versionString = "@(#)Version ";
+
+bool
+LLDBServices::SearchVersionString(
+ ULONG64 address,
+ ULONG64 size,
+ char* versionBuffer,
+ int versionBufferSize)
+{
+ BYTE buffer[VersionLength];
+ ULONG cbBytesRead;
+ bool result;
+
+ ClearCache();
+
+ while (size > 0)
+ {
+ result = ReadVirtualCache(address, buffer, VersionLength, &cbBytesRead);
+ if (result && cbBytesRead >= VersionLength)
+ {
+ if (memcmp(buffer, g_versionString, VersionLength) == 0)
+ {
+ for (int i = 0; i < versionBufferSize; i++)
+ {
+ // Now read the version string a char/byte at a time
+ result = ReadVirtualCache(address, &versionBuffer[i], 1, &cbBytesRead);
+
+ // Return not found if there are any failures or problems while reading the version string.
+ if (!result || cbBytesRead < 1 || size <= 0) {
+ break;
+ }
+ // Found the end of the string
+ if (versionBuffer[i] == '\0') {
+ return true;
+ }
+ address++;
+ size--;
+ }
+ // Return not found if overflowed the versionBuffer (not finding a null).
+ break;
+ }
+ address++;
+ size--;
+ }
+ else
+ {
+ address += VersionLength;
+ size -= VersionLength;
+ }
+ }
+
+ return false;
+}
+
+bool
+LLDBServices::ReadVirtualCache(ULONG64 address, PVOID buffer, ULONG bufferSize, PULONG pcbBytesRead)
+{
+ if (bufferSize == 0)
+ {
+ return true;
+ }
+
+ if (bufferSize > CACHE_SIZE)
+ {
+ // Don't even try with the cache
+ return ReadVirtual(address, buffer, bufferSize, pcbBytesRead) == S_OK;
+ }
+
+ if (!m_cacheValid || (address < m_startCache) || (address > (m_startCache + m_cacheSize - bufferSize)))
+ {
+ m_cacheValid = false;
+ m_startCache = address;
+
+ ULONG cbBytesRead = 0;
+ HRESULT hr = ReadVirtual(m_startCache, m_cache, CACHE_SIZE, &cbBytesRead);
+ if (hr != S_OK)
+ {
+ return false;
+ }
+
+ m_cacheSize = cbBytesRead;
+ m_cacheValid = true;
+ }
+
+ memcpy(buffer, (LPVOID)((ULONG64)m_cache + (address - m_startCache)), bufferSize);
+
+ if (pcbBytesRead != NULL)
+ {
+ *pcbBytesRead = bufferSize;
+ }
+
+ return true;
+}
#include <cstdarg>
+#define CACHE_SIZE 4096
+
class LLDBServices : public ILLDBServices, public ILLDBServices2
{
private:
lldb::SBProcess *m_currentProcess;
lldb::SBThread *m_currentThread;
+ BYTE m_cache[CACHE_SIZE];
+ ULONG64 m_startCache;
+ bool m_cacheValid;
+ ULONG m_cacheSize;
+
void OutputString(ULONG mask, PCSTR str);
ULONG64 GetModuleBase(lldb::SBTarget& target, lldb::SBModule& module);
+ ULONG64 GetModuleSize(lldb::SBModule& module);
DWORD_PTR GetExpression(lldb::SBFrame& frame, lldb::SBError& error, PCSTR exp);
void GetContextFromFrame(lldb::SBFrame& frame, DT_CONTEXT *dtcontext);
DWORD_PTR GetRegister(lldb::SBFrame& frame, const char *name);
+ bool GetVersionStringFromSection(lldb::SBTarget& target, lldb::SBSection& section, char* versionBuffer);
+ bool SearchVersionString(ULONG64 address, ULONG64 size, char* versionBuffer, int versionBufferSize);
+ bool ReadVirtualCache(ULONG64 address, PVOID buffer, ULONG bufferSize, PULONG pcbBytesRead);
+
+ void ClearCache()
+ {
+ m_cacheValid = false;
+ m_cacheSize = CACHE_SIZE;
+ }
+
lldb::SBProcess GetCurrentProcess();
lldb::SBThread GetCurrentThread();
lldb::SBFrame GetCurrentFrame();
void* param,
const char* symbolFileName);
+ HRESULT GetModuleInfo(
+ ULONG index,
+ PULONG64 base,
+ PULONG64 size);
+
+ HRESULT GetModuleVersionInformation(
+ ULONG index,
+ ULONG64 base,
+ PCSTR item,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG versionInfoSize);
+
//----------------------------------------------------------------------------
// LLDBServices (internal)
//----------------------------------------------------------------------------
interpreter.AddCommand("clrstack", new sosCommand("ClrStack"), "Provides a stack trace of managed code only.");
interpreter.AddCommand("clrthreads", new sosCommand("Threads"), "List the managed threads running.");
interpreter.AddCommand("clru", new sosCommand("u"), "Displays an annotated disassembly of a managed method.");
+ interpreter.AddCommand("dumparray", new sosCommand("DumpArray"), "Displays details about a managed array.");
interpreter.AddCommand("dumpasync", new sosCommand("DumpAsync"), "Displays info about async state machines on the garbage-collected heap.");
interpreter.AddCommand("dumpassembly", new sosCommand("DumpAssembly"), "Displays details about an assembly.");
interpreter.AddCommand("dumpclass", new sosCommand("DumpClass"), "Displays information about a EE class structure at the specified address.");
interpreter.AddCommand("dso", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack.");
interpreter.AddCommand("eeheap", new sosCommand("EEHeap"), "Displays info about process memory consumed by internal runtime data structures.");
interpreter.AddCommand("eestack", new sosCommand("EEStack"), "Runs dumpstack on all threads in the process.");
+ interpreter.AddCommand("eeversion", new sosCommand("EEVersion"), "Displays information about the runtime version.");
interpreter.AddCommand("finalizequeue", new sosCommand("FinalizeQueue"), "Displays all objects registered for finalization.");
interpreter.AddCommand("gcroot", new sosCommand("GCRoot"), "Displays info about references (or roots) to an object at the specified address.");
interpreter.AddCommand("gcwhere", new sosCommand("GCWhere"), "Displays the location in the GC heap of the argument passed in.");
[Command(Name = "dumpstackobjects", AliasExpansion = "DumpStackObjects", Help = "Displays all managed objects found within the bounds of the current stack.")]
[CommandAlias(Name = "dso")]
[Command(Name = "eeheap", AliasExpansion = "EEHeap", Help = "Displays info about process memory consumed by internal runtime data structures.")]
+ [Command(Name = "eeversion", AliasExpansion = "EEVersion", Help = "Displays information about the runtime version.")]
[Command(Name = "finalizequeue", AliasExpansion = "FinalizeQueue", Help = "Displays all objects registered for finalization.")]
[Command(Name = "gcroot", AliasExpansion = "GCRoot", Help = "Displays info about references (or roots) to an object at the specified address.")]
[Command(Name = "gcwhere", AliasExpansion = "GCWhere", Help = "Displays the location in the GC heap of the argument passed in.")]
[Command(Name = "watsonbuckets", AliasExpansion = "WatsonBuckets", Help = "Displays the Watson buckets.")]
[Command(Name = "threadpool", AliasExpansion = "ThreadPool", Help = "Lists basic information about the thread pool.")]
[Command(Name = "comstate", AliasExpansion = "COMState", Help = "Lists the COM apartment model for each thread.")]
- [Command(Name = "eeversion", AliasExpansion = "EEVersion", Help = "This prints the runtiem and SOS versions.")]
[Command(Name = "gchandles", AliasExpansion = "GCHandles", Help = "Provides statistics about GCHandles in the process.")]
[Command(Name = "objsize", AliasExpansion = "ObjSize", Help = "Lists the sizes of the all the objects found on managed threads.")]
[Command(Name = "gchandleleaks", AliasExpansion = "GCHandleLeaks", Help = "Helps in tracking down GCHandle leaks")]
CLRDATA_ADDRESS NativeCodeVersionNodePtr;
};
-// 2.1 version
-struct MSLAYOUT DacpTieredVersionData_21
+// 2.x version
+struct MSLAYOUT DacpTieredVersionData_2x
{
enum TieredState
{