зеркало из https://github.com/dotnet/diagnostics.git
Misc service and implementation cleanup (#5129)
Clean up and add useful functions to IModuleService, IThreadService, IHost, ITarget
This commit is contained in:
Родитель
a83544eeba
Коммит
4d0d682cfd
|
@ -30,7 +30,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
|
||||
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
|
||||
{
|
||||
// apply any existing policy
|
||||
// Apply any existing policy
|
||||
AssemblyName referenceName = new(AppDomain.CurrentDomain.ApplyPolicy(args.Name));
|
||||
string fileName = referenceName.Name + ".dll";
|
||||
string assemblyPath;
|
||||
|
@ -39,10 +39,10 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
|
||||
// Look next to the executing assembly
|
||||
probingPath = Path.Combine(_defaultAssembliesPath, fileName);
|
||||
Debug.WriteLine($"Considering {probingPath} based on ExecutingAssembly");
|
||||
Trace.TraceInformation($"Considering {probingPath} based on ExecutingAssembly");
|
||||
if (Probe(probingPath, referenceName.Version, out assembly))
|
||||
{
|
||||
Debug.WriteLine($"Matched {probingPath} based on ExecutingAssembly");
|
||||
Trace.TraceInformation($"Matched {probingPath} based on ExecutingAssembly");
|
||||
return assembly;
|
||||
}
|
||||
|
||||
|
@ -51,10 +51,10 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
if (!string.IsNullOrEmpty(assemblyPath))
|
||||
{
|
||||
probingPath = Path.Combine(Path.GetDirectoryName(assemblyPath), fileName);
|
||||
Debug.WriteLine($"Considering {probingPath} based on RequestingAssembly");
|
||||
Trace.TraceInformation($"Considering {probingPath} based on RequestingAssembly");
|
||||
if (Probe(probingPath, referenceName.Version, out assembly))
|
||||
{
|
||||
Debug.WriteLine($"Matched {probingPath} based on RequestingAssembly");
|
||||
Trace.TraceInformation($"Matched {probingPath} based on RequestingAssembly");
|
||||
return assembly;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using Microsoft.Diagnostics.DebugServices;
|
||||
|
||||
|
@ -14,6 +15,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
private readonly ServiceManager _serviceManager;
|
||||
private ServiceContainer _serviceContainer;
|
||||
private readonly List<ITarget> _targets = new();
|
||||
private string _tempDirectory;
|
||||
private int _targetIdFactory;
|
||||
|
||||
public Host(HostType type)
|
||||
|
@ -61,6 +63,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
target.Destroy();
|
||||
}
|
||||
_targets.Clear();
|
||||
CleanupTempDirectory();
|
||||
}
|
||||
|
||||
#region IHost
|
||||
|
@ -84,6 +87,35 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
return _targetIdFactory++;
|
||||
}
|
||||
|
||||
public string GetTempDirectory()
|
||||
{
|
||||
if (_tempDirectory == null)
|
||||
{
|
||||
// Use the SOS process's id if can't get the target's
|
||||
uint processId = (uint)Process.GetCurrentProcess().Id;
|
||||
|
||||
// SOS depends on that the temp directory ends with "/".
|
||||
_tempDirectory = Path.Combine(Path.GetTempPath(), "sos" + processId.ToString()) + Path.DirectorySeparatorChar;
|
||||
Directory.CreateDirectory(_tempDirectory);
|
||||
}
|
||||
return _tempDirectory;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void CleanupTempDirectory()
|
||||
{
|
||||
if (_tempDirectory != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(_tempDirectory, recursive: true);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
}
|
||||
_tempDirectory = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||
using System.Collections.Immutable;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Diagnostics.Runtime;
|
||||
using Microsoft.FileFormats;
|
||||
|
@ -73,7 +74,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
|
||||
public virtual uint? IndexTimeStamp { get; protected set; }
|
||||
|
||||
public bool IsPEImage
|
||||
public virtual bool IsPEImage
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -184,6 +185,31 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
|
||||
public abstract string LoadSymbols();
|
||||
|
||||
/// <summary>
|
||||
/// Downloads and returns the metadata for the assembly.
|
||||
/// </summary>
|
||||
/// <returns>metadata bytes</returns>
|
||||
public ImmutableArray<byte> GetMetadata()
|
||||
{
|
||||
try
|
||||
{
|
||||
PEReader reader = Services.GetService<PEReader>();
|
||||
if (reader is not null && reader.HasMetadata)
|
||||
{
|
||||
PEMemoryBlock metadataInfo = reader.GetMetadata();
|
||||
return metadataInfo.GetContent();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when
|
||||
(ex is InvalidOperationException ||
|
||||
ex is BadImageFormatException ||
|
||||
ex is IOException)
|
||||
{
|
||||
Trace.TraceError($"GetMetaData: {ex.Message}");
|
||||
}
|
||||
return ImmutableArray<byte>.Empty;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IExportSymbols
|
||||
|
|
|
@ -69,6 +69,8 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
|
||||
#endregion
|
||||
|
||||
internal void AddService<T>(T service) => _serviceContainer.AddService(service);
|
||||
|
||||
protected override ModuleService ModuleService { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,6 +172,19 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a module instance
|
||||
/// </summary>
|
||||
/// <param name="moduleIndex">artificial index</param>
|
||||
/// <param name="imageBase">module base address</param>
|
||||
/// <param name="imageSize">module size</param>
|
||||
/// <param name="imageName">module name</param>
|
||||
/// <returns>IModule</returns>
|
||||
IModule IModuleService.CreateModule(int moduleIndex, ulong imageBase, ulong imageSize, string imageName)
|
||||
{
|
||||
return new ModuleFromAddress(this, moduleIndex, imageBase, imageSize, imageName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
|
@ -220,7 +233,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
// First try getting the PE info as loaded layout (native Windows DLLs and most managed PEs).
|
||||
peFile = GetPEInfo(isVirtual: true, address, size, out List<PdbFileInfo> pdbs, out Module.Flags flags);
|
||||
|
||||
// Continue only if marked as a PE. This bit regardless of the layout if the module has a PE header/signature.
|
||||
// Continue only if marked as a PE. This bit is set regardless of the layout if the module has a PE header/signature.
|
||||
if ((flags & Module.Flags.IsPEImage) != 0)
|
||||
{
|
||||
if (peFile is null || pdbs.Count == 0)
|
||||
|
@ -288,9 +301,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
/// <returns>build id or null</returns>
|
||||
internal byte[] GetBuildId(ulong address)
|
||||
{
|
||||
// This code is called by the image mapping memory service so it needs to use the
|
||||
// original or raw memory service to prevent recursion so it can't use the ELFFile
|
||||
// or MachOFile instance that is available from the IModule.Services provider.
|
||||
Stream stream = MemoryService.CreateMemoryStream();
|
||||
byte[] buildId = null;
|
||||
try
|
||||
|
|
|
@ -47,6 +47,8 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
|
||||
public override uint? IndexTimeStamp => _moduleInfo.IndexTimeStamp == InvalidTimeStamp ? null : unchecked((uint)_moduleInfo.IndexTimeStamp);
|
||||
|
||||
public override bool IsPEImage => _moduleInfo.Kind == ModuleKind.PortableExecutable;
|
||||
|
||||
public override ImmutableArray<byte> BuildId
|
||||
{
|
||||
get
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
public IDisposable RegisterOneShot(Action callback) => Register(oneshot: true, callback);
|
||||
|
||||
#pragma warning disable CA1859
|
||||
// Use concrete types when possible for improved performance. Explicitly obscure any functionality other than a duspose token.
|
||||
// Use concrete types when possible for improved performance. Explicitly obscure any functionality other than a dispose token.
|
||||
private IDisposable Register(bool oneshot, Action callback)
|
||||
#pragma warning restore CA1859
|
||||
{
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
/// <summary>
|
||||
/// The default symbol cache path:
|
||||
/// * dbgeng on Windows uses the dbgeng symbol cache path: %PROGRAMDATA%\dbg\sym
|
||||
/// * dotnet-dump on Windows uses the VS symbol cache path: %TEMPDIR%\SymbolCache
|
||||
/// * VS or dotnet-dump on Windows use the VS symbol cache path: %TEMPDIR%\SymbolCache
|
||||
/// * dotnet-dump/lldb on Linux/MacOS uses: $HOME/.dotnet/symbolcache
|
||||
/// </summary>
|
||||
public string DefaultSymbolCache
|
||||
|
@ -86,8 +86,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
_defaultSymbolCache = _host.HostType switch
|
||||
{
|
||||
HostType.DbgEng => Path.Combine(Environment.GetEnvironmentVariable("PROGRAMDATA"), "dbg", "sym"),
|
||||
HostType.DotnetDump => Path.Combine(Path.GetTempPath(), "SymbolCache"),
|
||||
_ => throw new NotSupportedException($"Host type not supported {_host.HostType}"),
|
||||
_ => Path.Combine(Path.GetTempPath(), "SymbolCache"),
|
||||
};
|
||||
}
|
||||
else
|
||||
|
|
|
@ -17,7 +17,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
public abstract class Target : ITarget
|
||||
{
|
||||
private readonly string _dumpPath;
|
||||
private string _tempDirectory;
|
||||
private ServiceContainer _serviceContainer;
|
||||
|
||||
protected readonly ServiceContainerFactory _serviceContainerFactory;
|
||||
|
@ -82,23 +81,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
/// </summary>
|
||||
public uint? ProcessId { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unique temporary directory for this instance of SOS
|
||||
/// </summary>
|
||||
public string GetTempDirectory()
|
||||
{
|
||||
if (_tempDirectory == null)
|
||||
{
|
||||
// Use the SOS process's id if can't get the target's
|
||||
uint processId = ProcessId.GetValueOrDefault((uint)Process.GetCurrentProcess().Id);
|
||||
|
||||
// SOS depends on that the temp directory ends with "/".
|
||||
_tempDirectory = Path.Combine(Path.GetTempPath(), "sos" + processId.ToString()) + Path.DirectorySeparatorChar;
|
||||
Directory.CreateDirectory(_tempDirectory);
|
||||
}
|
||||
return _tempDirectory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The per target services.
|
||||
/// </summary>
|
||||
|
@ -132,7 +114,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
OnDestroyEvent.Fire();
|
||||
_serviceContainer.RemoveService(typeof(ITarget));
|
||||
_serviceContainer.DisposeServices();
|
||||
CleanupTempDirectory();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -154,25 +135,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
return new Reader(new StreamAddressSpace(stream), layoutManager);
|
||||
}
|
||||
|
||||
private void CleanupTempDirectory()
|
||||
{
|
||||
if (_tempDirectory != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (string file in Directory.EnumerateFiles(_tempDirectory))
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
Directory.Delete(_tempDirectory);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
}
|
||||
_tempDirectory = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Id == ((ITarget)obj).Id;
|
||||
|
@ -192,10 +154,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
{
|
||||
sb.Append($" {_dumpPath}");
|
||||
}
|
||||
if (_tempDirectory != null)
|
||||
{
|
||||
sb.Append($" {_tempDirectory}");
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Diagnostics.DebugServices.Implementation
|
||||
{
|
||||
|
@ -23,7 +24,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
_serviceContainer.AddService<IThread>(this);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
_serviceContainer.RemoveService(typeof(IThread));
|
||||
_serviceContainer.DisposeServices();
|
||||
|
@ -58,22 +59,47 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
{
|
||||
if (_threadContext.IsEmpty)
|
||||
{
|
||||
_threadContext = _threadService.GetThreadContext(this);
|
||||
byte[] threadContext = new byte[_threadService.ContextSize];
|
||||
if (!GetThreadContextInner(_threadService.ContextFlags, threadContext))
|
||||
{
|
||||
throw new DiagnosticsException($"Unable to get the context for thread {ThreadId:X8} with flags {_threadService.ContextFlags:X8}");
|
||||
}
|
||||
_threadContext = threadContext;
|
||||
}
|
||||
return _threadContext.Span;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the thread context
|
||||
/// </summary>
|
||||
/// <param name="contextFlags">Windows context flags</param>
|
||||
/// <param name="context">Context buffer</param>
|
||||
/// <returns>true succeeded, false failed</returns>
|
||||
protected virtual bool GetThreadContextInner(uint contextFlags, byte[] context) => _threadService.GetThreadContext(ThreadId, contextFlags, context);
|
||||
|
||||
public ulong GetThreadTeb()
|
||||
{
|
||||
if (!_teb.HasValue)
|
||||
{
|
||||
_teb = _threadService.GetThreadTeb(this);
|
||||
_teb = GetThreadTebInner();
|
||||
}
|
||||
return _teb.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Windows TEB pointer for the thread
|
||||
/// </summary>
|
||||
/// <returns>TEB pointer or 0 if not implemented or thread id not found</returns>
|
||||
protected virtual ulong GetThreadTebInner() => _threadService.GetThreadTeb(ThreadId);
|
||||
|
||||
#endregion
|
||||
|
||||
protected void SetContextFlags(uint contextFlags, Span<byte> context)
|
||||
{
|
||||
Span<byte> threadSpan = context.Slice(_threadService.ContextFlagsOffset, sizeof(uint));
|
||||
MemoryMarshal.Write<uint>(threadSpan, ref contextFlags);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
IThread thread = (IThread)obj;
|
||||
|
|
|
@ -16,12 +16,13 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation {
|
|||
/// </summary>
|
||||
public abstract class ThreadService : IThreadService, IDisposable
|
||||
{
|
||||
private readonly int _contextSize;
|
||||
private readonly uint _contextFlags;
|
||||
private readonly Dictionary<string, RegisterInfo> _lookupByName;
|
||||
private readonly Dictionary<int, RegisterInfo> _lookupByIndex;
|
||||
private Dictionary<uint, IThread> _threads;
|
||||
|
||||
protected internal readonly int ContextSize;
|
||||
protected internal readonly uint ContextFlags;
|
||||
protected internal readonly int ContextFlagsOffset;
|
||||
protected internal readonly IServiceProvider Services;
|
||||
protected internal readonly ITarget Target;
|
||||
|
||||
|
@ -36,38 +37,38 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation {
|
|||
{
|
||||
case Architecture.X64:
|
||||
// Dumps generated with newer dbgeng have bigger context buffers and clrmd requires the context size to at least be that size.
|
||||
_contextSize = Target.OperatingSystem == OSPlatform.Windows ? 0x700 : AMD64Context.Size;
|
||||
_contextFlags = AMD64Context.ContextControl | AMD64Context.ContextInteger | AMD64Context.ContextSegments | AMD64Context.ContextFloatingPoint;
|
||||
ContextSize = Target.Host.HostType != HostType.Vs && Target.OperatingSystem == OSPlatform.Windows ? 0x700 : AMD64Context.Size;
|
||||
ContextFlags = AMD64Context.ContextControl | AMD64Context.ContextInteger | AMD64Context.ContextSegments | AMD64Context.ContextFloatingPoint;
|
||||
contextType = typeof(AMD64Context);
|
||||
break;
|
||||
|
||||
case Architecture.X86:
|
||||
_contextSize = X86Context.Size;
|
||||
_contextFlags = X86Context.ContextControl | X86Context.ContextInteger | X86Context.ContextSegments | X86Context.ContextFloatingPoint;
|
||||
ContextSize = X86Context.Size;
|
||||
ContextFlags = X86Context.ContextControl | X86Context.ContextInteger | X86Context.ContextSegments | X86Context.ContextFloatingPoint;
|
||||
contextType = typeof(X86Context);
|
||||
break;
|
||||
|
||||
case Architecture.Arm64:
|
||||
_contextSize = Arm64Context.Size;
|
||||
_contextFlags = Arm64Context.ContextControl | Arm64Context.ContextInteger | Arm64Context.ContextFloatingPoint;
|
||||
ContextSize = Arm64Context.Size;
|
||||
ContextFlags = Arm64Context.ContextControl | Arm64Context.ContextInteger | Arm64Context.ContextFloatingPoint;
|
||||
contextType = typeof(Arm64Context);
|
||||
break;
|
||||
|
||||
case Architecture.Arm:
|
||||
_contextSize = ArmContext.Size;
|
||||
_contextFlags = ArmContext.ContextControl | ArmContext.ContextInteger | ArmContext.ContextFloatingPoint;
|
||||
ContextSize = ArmContext.Size;
|
||||
ContextFlags = ArmContext.ContextControl | ArmContext.ContextInteger | ArmContext.ContextFloatingPoint;
|
||||
contextType = typeof(ArmContext);
|
||||
break;
|
||||
|
||||
case (Architecture)6 /* Architecture.LoongArch64 */:
|
||||
_contextSize = LoongArch64Context.Size;
|
||||
_contextFlags = LoongArch64Context.ContextControl | LoongArch64Context.ContextInteger | LoongArch64Context.ContextFloatingPoint;
|
||||
ContextSize = LoongArch64Context.Size;
|
||||
ContextFlags = LoongArch64Context.ContextControl | LoongArch64Context.ContextInteger | LoongArch64Context.ContextFloatingPoint;
|
||||
contextType = typeof(LoongArch64Context);
|
||||
break;
|
||||
|
||||
case (Architecture)9 /* Architecture.RiscV64 */:
|
||||
_contextSize = RiscV64Context.Size;
|
||||
_contextFlags = RiscV64Context.ContextControl | RiscV64Context.ContextInteger | RiscV64Context.ContextFloatingPoint;
|
||||
ContextSize = RiscV64Context.Size;
|
||||
ContextFlags = RiscV64Context.ContextControl | RiscV64Context.ContextInteger | RiscV64Context.ContextFloatingPoint;
|
||||
contextType = typeof(RiscV64Context);
|
||||
break;
|
||||
|
||||
|
@ -81,6 +82,11 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation {
|
|||
FieldInfo[] fields = contextType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
FieldOffsetAttribute offsetAttribute = field.GetCustomAttributes<FieldOffsetAttribute>(inherit: false).Single();
|
||||
if (field.Name.Equals("contextflags", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
ContextFlagsOffset = offsetAttribute.Value;
|
||||
}
|
||||
RegisterAttribute registerAttribute = field.GetCustomAttributes<RegisterAttribute>(inherit: false).SingleOrDefault();
|
||||
if (registerAttribute is null)
|
||||
{
|
||||
|
@ -108,7 +114,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation {
|
|||
{
|
||||
FramePointerIndex = index;
|
||||
}
|
||||
FieldOffsetAttribute offsetAttribute = field.GetCustomAttributes<FieldOffsetAttribute>(inherit: false).Single();
|
||||
RegisterInfo registerInfo = new(index, offsetAttribute.Value, Marshal.SizeOf(field.FieldType), registerAttribute.Name ?? field.Name.ToLowerInvariant());
|
||||
registers.Add(registerInfo);
|
||||
index++;
|
||||
|
@ -187,43 +192,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation {
|
|||
return _lookupByIndex.TryGetValue(registerIndex, out info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the register value for the thread context and register index. This function
|
||||
/// can only return register values that are 64 bits or less and currently the clrmd data
|
||||
/// targets don't return any floating point or larger registers.
|
||||
/// </summary>
|
||||
/// <param name="context">thread context</param>
|
||||
/// <param name="registerIndex">register index</param>
|
||||
/// <param name="value">value returned</param>
|
||||
/// <returns>true if value found</returns>
|
||||
public bool TryGetRegisterValue(ReadOnlySpan<byte> context, int registerIndex, out ulong value)
|
||||
{
|
||||
if (TryGetRegisterInfo(registerIndex, out RegisterInfo info))
|
||||
{
|
||||
ReadOnlySpan<byte> threadSpan = context.Slice(info.RegisterOffset, info.RegisterSize);
|
||||
switch (info.RegisterSize)
|
||||
{
|
||||
case 1:
|
||||
value = MemoryMarshal.Read<byte>(threadSpan);
|
||||
return true;
|
||||
case 2:
|
||||
value = MemoryMarshal.Read<ushort>(threadSpan);
|
||||
return true;
|
||||
case 4:
|
||||
value = MemoryMarshal.Read<uint>(threadSpan);
|
||||
return true;
|
||||
case 8:
|
||||
value = MemoryMarshal.Read<ulong>(threadSpan);
|
||||
return true;
|
||||
default:
|
||||
Trace.TraceError($"GetRegisterValue: {info.RegisterName} invalid size {info.RegisterSize}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerate all the native threads
|
||||
/// </summary>
|
||||
|
@ -268,32 +236,6 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation {
|
|||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Get the thread context
|
||||
/// </summary>
|
||||
/// <param name="thread">thread instance</param>
|
||||
/// <returns>context array</returns>
|
||||
/// <exception cref="DiagnosticsException">invalid thread id</exception>
|
||||
internal byte[] GetThreadContext(Thread thread)
|
||||
{
|
||||
byte[] threadContext = new byte[_contextSize];
|
||||
if (!GetThreadContext(thread.ThreadId, _contextFlags, (uint)_contextSize, threadContext))
|
||||
{
|
||||
throw new DiagnosticsException();
|
||||
}
|
||||
return threadContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the thread TEB
|
||||
/// </summary>
|
||||
/// <param name="thread">thread instance</param>
|
||||
/// <returns>TEB</returns>
|
||||
internal ulong GetThreadTeb(Thread thread)
|
||||
{
|
||||
return GetThreadTeb(thread.ThreadId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get/create the thread dictionary.
|
||||
/// </summary>
|
||||
|
@ -313,17 +255,16 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation {
|
|||
/// </summary>
|
||||
/// <param name="threadId">OS thread id</param>
|
||||
/// <param name="contextFlags">Windows context flags</param>
|
||||
/// <param name="contextSize">Context size</param>
|
||||
/// <param name="context">Context buffer</param>
|
||||
/// <returns>true succeeded, false failed</returns>
|
||||
/// <exception cref="DiagnosticsException">invalid thread id</exception>
|
||||
protected abstract bool GetThreadContext(uint threadId, uint contextFlags, uint contextSize, byte[] context);
|
||||
protected internal virtual bool GetThreadContext(uint threadId, uint contextFlags, byte[] context) => throw new NotImplementedException();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Windows TEB pointer for the thread
|
||||
/// </summary>
|
||||
/// <param name="threadId">OS thread id</param>
|
||||
/// <returns>TEB pointer or 0</returns>
|
||||
protected abstract ulong GetThreadTeb(uint threadId);
|
||||
/// <returns>TEB pointer or 0 if not implemented or thread id not found</returns>
|
||||
protected internal virtual ulong GetThreadTeb(uint threadId) => throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,16 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
_threadReader = (IThreadReader)dataReader;
|
||||
}
|
||||
|
||||
protected override bool GetThreadContext(uint threadId, uint contextFlags, uint contextSize, byte[] context)
|
||||
protected override IEnumerable<IThread> GetThreadsInner()
|
||||
{
|
||||
return _threadReader.EnumerateOSThreadIds().Select((uint id, int index) => new Thread(this, index, id)).Cast<IThread>();
|
||||
}
|
||||
|
||||
protected internal override bool GetThreadContext(uint threadId, uint contextFlags, byte[] context)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _dataReader.GetThreadContext(threadId, contextFlags, new Span<byte>(context, 0, unchecked((int)contextSize)));
|
||||
return _dataReader.GetThreadContext(threadId, contextFlags, new Span<byte>(context));
|
||||
}
|
||||
catch (ClrDiagnosticsException ex)
|
||||
{
|
||||
|
@ -38,12 +43,7 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<IThread> GetThreadsInner()
|
||||
{
|
||||
return _threadReader.EnumerateOSThreadIds().Select((uint id, int index) => new Thread(this, index, id)).Cast<IThread>();
|
||||
}
|
||||
|
||||
protected override ulong GetThreadTeb(uint threadId)
|
||||
protected internal override ulong GetThreadTeb(uint threadId)
|
||||
{
|
||||
return _threadReader.GetThreadTeb(threadId);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,29 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation
|
|||
/// </summary>
|
||||
public static string ToHex(this ImmutableArray<byte> array) => string.Concat(array.Select((b) => b.ToString("x2")));
|
||||
|
||||
/// <summary>
|
||||
/// Returns the pointer size for a given processor type
|
||||
/// </summary>
|
||||
/// <param name="architecture">processor type</param>
|
||||
/// <returns>pointer size</returns>
|
||||
/// <exception cref="NotSupportedException"></exception>
|
||||
public static int GetPointerSizeFromArchitecture(Architecture architecture)
|
||||
{
|
||||
switch (architecture)
|
||||
{
|
||||
case Architecture.X64:
|
||||
case Architecture.Arm64:
|
||||
case (Architecture)6 /* Architecture.LoongArch64 */:
|
||||
case (Architecture)9 /* Architecture.RiscV64 */:
|
||||
return 8;
|
||||
case Architecture.X86:
|
||||
case Architecture.Arm:
|
||||
return 4;
|
||||
default:
|
||||
throw new NotSupportedException("Architecture not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combines two hash codes into a single hash code, in an order-dependent manner.
|
||||
/// </summary>
|
||||
|
|
|
@ -55,5 +55,10 @@ namespace Microsoft.Diagnostics.DebugServices
|
|||
/// <param name="target">target instance</param>
|
||||
/// <returns>target id</returns>
|
||||
int AddTarget(ITarget target);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unique temporary directory for this debug session
|
||||
/// </summary>
|
||||
string GetTempDirectory();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Diagnostics.DebugServices
|
||||
{
|
||||
/// <summary>
|
||||
/// Attaches to live processes.
|
||||
/// </summary>
|
||||
public interface ILiveTargetFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Attaches to a live process and suspends it until the target is destroyed/closed.
|
||||
/// </summary>
|
||||
/// <returns>target instance</returns>
|
||||
/// <exception cref="DiagnosticsException">can not construct target instance</exception>
|
||||
ITarget Attach(int processId);
|
||||
}
|
||||
}
|
|
@ -97,5 +97,11 @@ namespace Microsoft.Diagnostics.DebugServices
|
|||
/// </summary>
|
||||
/// <returns>the symbol file name</returns>
|
||||
string LoadSymbols();
|
||||
|
||||
/// <summary>
|
||||
/// Downloads and returns the metadata for the assembly.
|
||||
/// </summary>
|
||||
/// <returns>metadata bytes</returns>
|
||||
ImmutableArray<byte> GetMetadata();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,5 +45,15 @@ namespace Microsoft.Diagnostics.DebugServices
|
|||
/// <param name="moduleName">module name to find</param>
|
||||
/// <returns>matching modules</returns>
|
||||
IEnumerable<IModule> GetModuleFromModuleName(string moduleName);
|
||||
|
||||
/// <summary>
|
||||
/// Create a module instance from a stream (memory or file).
|
||||
/// </summary>
|
||||
/// <param name="moduleIndex">artifical index</param>
|
||||
/// <param name="imageBase">module base address</param>
|
||||
/// <param name="imageSize">module size</param>
|
||||
/// <param name="imageName">module name</param>
|
||||
/// <returns>IModule</returns>
|
||||
IModule CreateModule(int moduleIndex, ulong imageBase, ulong imageSize, string imageName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,11 +43,6 @@ namespace Microsoft.Diagnostics.DebugServices
|
|||
/// </summary>
|
||||
uint? ProcessId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unique temporary directory for this instance of SOS
|
||||
/// </summary>
|
||||
string GetTempDirectory();
|
||||
|
||||
/// <summary>
|
||||
/// The per target services.
|
||||
/// </summary>
|
||||
|
|
|
@ -47,17 +47,6 @@ namespace Microsoft.Diagnostics.DebugServices
|
|||
/// <returns>true if index found</returns>
|
||||
bool TryGetRegisterInfo(int registerIndex, out RegisterInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the register value for the thread context and register index. This function
|
||||
/// can only return register values that are 64 bits or less and currently the clrmd data
|
||||
/// targets don't return any floating point or larger registers.
|
||||
/// </summary>
|
||||
/// <param name="context">thread context</param>
|
||||
/// <param name="registerIndex">register index</param>
|
||||
/// <param name="value">value returned</param>
|
||||
/// <returns>true if value found</returns>
|
||||
bool TryGetRegisterValue(ReadOnlySpan<byte> context, int registerIndex, out ulong value);
|
||||
|
||||
/// <summary>
|
||||
/// Enumerate all the native threads
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Diagnostics.DebugServices
|
||||
{
|
||||
public static class ThreadServiceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the register value for the thread context and register index. This function
|
||||
/// can only return register values that are 64 bits or less and currently the clrmd data
|
||||
/// targets don't return any floating point or larger registers.
|
||||
/// </summary>
|
||||
/// <param name="threadService">thread service instance</param>
|
||||
/// <param name="context">thread context</param>
|
||||
/// <param name="registerIndex">register index</param>
|
||||
/// <param name="value">value returned</param>
|
||||
/// <returns>true if value found</returns>
|
||||
public static bool TryGetRegisterValue(this IThreadService threadService, ReadOnlySpan<byte> context, int registerIndex, out ulong value)
|
||||
{
|
||||
if (threadService.TryGetRegisterInfo(registerIndex, out RegisterInfo info))
|
||||
{
|
||||
ReadOnlySpan<byte> threadSpan = context.Slice(info.RegisterOffset, info.RegisterSize);
|
||||
switch (info.RegisterSize)
|
||||
{
|
||||
case 1:
|
||||
value = MemoryMarshal.Read<byte>(threadSpan);
|
||||
return true;
|
||||
case 2:
|
||||
value = MemoryMarshal.Read<ushort>(threadSpan);
|
||||
return true;
|
||||
case 4:
|
||||
value = MemoryMarshal.Read<uint>(threadSpan);
|
||||
return true;
|
||||
case 8:
|
||||
value = MemoryMarshal.Read<ulong>(threadSpan);
|
||||
return true;
|
||||
default:
|
||||
Trace.TraceError($"GetRegisterValue: {info.RegisterName} invalid size {info.RegisterSize}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
value = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change a specific register.
|
||||
/// </summary>
|
||||
/// <param name="threadService">thread service instance</param>
|
||||
/// <param name="context">writeable context span</param>
|
||||
/// <param name="registerIndex">register index</param>
|
||||
/// <param name="value">value to write</param>
|
||||
/// <returns></returns>
|
||||
public static bool TrySetRegisterValue(this IThreadService threadService, Span<byte> context, int registerIndex, ulong value)
|
||||
{
|
||||
if (threadService.TryGetRegisterInfo(registerIndex, out RegisterInfo info))
|
||||
{
|
||||
Span<byte> threadSpan = context.Slice(info.RegisterOffset, info.RegisterSize);
|
||||
switch (info.RegisterSize)
|
||||
{
|
||||
case 1:
|
||||
byte byteValue = (byte)value;
|
||||
MemoryMarshal.Write<byte>(threadSpan, ref byteValue);
|
||||
return true;
|
||||
case 2:
|
||||
ushort ushortValue = (ushort)value;
|
||||
MemoryMarshal.Write<ushort>(threadSpan, ref ushortValue);
|
||||
return true;
|
||||
case 4:
|
||||
uint uintValue = (uint)value;
|
||||
MemoryMarshal.Write<uint>(threadSpan, ref uintValue);
|
||||
return true;
|
||||
case 8:
|
||||
MemoryMarshal.Write<ulong>(threadSpan, ref value);
|
||||
return true;
|
||||
default:
|
||||
Trace.TraceError($"SetRegisterValue: {info.RegisterName} invalid size {info.RegisterSize}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,7 +33,7 @@ namespace Microsoft.Diagnostics.TestHelpers
|
|||
{
|
||||
ITarget target = services.GetService<ITarget>();
|
||||
Debug.Assert(target is not null);
|
||||
AddMembers(Target, typeof(ITarget), target, nameof(ITarget.Id), nameof(ITarget.GetTempDirectory));
|
||||
AddMembers(Target, typeof(ITarget), target, nameof(ITarget.Id));
|
||||
|
||||
XElement modulesElement = new("Modules");
|
||||
Target.Add(modulesElement);
|
||||
|
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Diagnostics.DebugServices;
|
||||
using Microsoft.Diagnostics.DebugServices.Implementation;
|
||||
using Microsoft.Diagnostics.Runtime.Utilities;
|
||||
|
||||
namespace SOS.Extensions
|
||||
|
@ -26,19 +27,7 @@ namespace SOS.Extensions
|
|||
Debug.Assert(target != null);
|
||||
Debug.Assert(debuggerServices != null);
|
||||
_debuggerServices = debuggerServices;
|
||||
|
||||
switch (target.Architecture)
|
||||
{
|
||||
case Architecture.X64:
|
||||
case Architecture.Arm64:
|
||||
case (Architecture)6 /* Architecture.LoongArch64 */:
|
||||
PointerSize = 8;
|
||||
break;
|
||||
case Architecture.X86:
|
||||
case Architecture.Arm:
|
||||
PointerSize = 4;
|
||||
break;
|
||||
}
|
||||
PointerSize = Utilities.GetPointerSizeFromArchitecture(target.Architecture);
|
||||
}
|
||||
|
||||
#region IMemoryService
|
||||
|
|
|
@ -24,11 +24,6 @@ namespace SOS.Extensions
|
|||
_debuggerServices = debuggerServices;
|
||||
}
|
||||
|
||||
protected override bool GetThreadContext(uint threadId, uint contextFlags, uint contextSize, byte[] context)
|
||||
{
|
||||
return _debuggerServices.GetThreadContext(threadId, contextFlags, contextSize, context) == HResult.S_OK;
|
||||
}
|
||||
|
||||
protected override IEnumerable<IThread> GetThreadsInner()
|
||||
{
|
||||
HResult hr = _debuggerServices.GetNumberThreads(out uint number);
|
||||
|
@ -55,6 +50,11 @@ namespace SOS.Extensions
|
|||
}
|
||||
}
|
||||
|
||||
protected override bool GetThreadContext(uint threadId, uint contextFlags, byte[] context)
|
||||
{
|
||||
return _debuggerServices.GetThreadContext(threadId, contextFlags, (uint)context.Length, context).IsOK;
|
||||
}
|
||||
|
||||
protected override ulong GetThreadTeb(uint threadId)
|
||||
{
|
||||
_debuggerServices.GetThreadTeb(threadId, out ulong teb);
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace SOS.Hosting
|
|||
builder.AddMethod(new GetHostTypeDelegate(GetHostType));
|
||||
builder.AddMethod(new GetServiceDelegate(ServiceWrapper.GetService));
|
||||
builder.AddMethod(new GetCurrentTargetDelegate(GetCurrentTarget));
|
||||
builder.AddMethod(new GetTempDirectoryDelegate(GetTempDirectory));
|
||||
IHost = builder.Complete();
|
||||
|
||||
AddRef();
|
||||
|
@ -65,6 +66,12 @@ namespace SOS.Hosting
|
|||
return HResult.S_OK;
|
||||
}
|
||||
|
||||
private string GetTempDirectory(
|
||||
IntPtr self)
|
||||
{
|
||||
return _host.GetTempDirectory();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHost delegates
|
||||
|
@ -84,6 +91,11 @@ namespace SOS.Hosting
|
|||
[In] IntPtr self,
|
||||
[Out] out IntPtr target);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
[return: MarshalAs(UnmanagedType.LPStr)]
|
||||
private delegate string GetTempDirectoryDelegate(
|
||||
[In] IntPtr self);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Collections.Immutable;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Diagnostics.DebugServices;
|
||||
using Microsoft.Diagnostics.Runtime.Utilities;
|
||||
|
@ -70,21 +71,49 @@ namespace SOS.Hosting
|
|||
{
|
||||
return HResult.E_INVALIDARG;
|
||||
}
|
||||
int hr = HResult.S_OK;
|
||||
int hr = HResult.E_FAIL;
|
||||
int dataSize = 0;
|
||||
|
||||
ImmutableArray<byte> metadata = symbolService.GetMetadata(imagePath, imageTimestamp, imageSize);
|
||||
if (!metadata.IsEmpty)
|
||||
if (symbolService.IsSymbolStoreEnabled)
|
||||
{
|
||||
dataSize = metadata.Length;
|
||||
int size = Math.Min((int)bufferSize, dataSize);
|
||||
Marshal.Copy(metadata.ToArray(), 0, pMetadata, size);
|
||||
try
|
||||
{
|
||||
SymbolStoreKey key = PEFileKeyGenerator.GetKey(imagePath, imageTimestamp, imageSize);
|
||||
string localFilePath = symbolService.DownloadFile(key.Index, key.FullPathName);
|
||||
if (!string.IsNullOrWhiteSpace(localFilePath))
|
||||
{
|
||||
Stream peStream = TryOpenFile(localFilePath);
|
||||
if (peStream != null)
|
||||
{
|
||||
using PEReader peReader = new(peStream, PEStreamOptions.Default);
|
||||
if (peReader.HasMetadata)
|
||||
{
|
||||
PEMemoryBlock metadataInfo = peReader.GetMetadata();
|
||||
ImmutableArray<byte> metadata = metadataInfo.GetContent();
|
||||
if (!metadata.IsEmpty)
|
||||
{
|
||||
dataSize = metadata.Length;
|
||||
int size = Math.Min((int)bufferSize, dataSize);
|
||||
Marshal.Copy(metadata.ToArray(), 0, pMetadata, size);
|
||||
hr = HResult.S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Trace.TraceError($"GetMetaDataLocator: file not download {key.Index}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is InvalidOperationException or BadImageFormatException or IOException)
|
||||
{
|
||||
Trace.TraceError($"GetMetaDataLocator: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = HResult.E_FAIL;
|
||||
Trace.TraceError($"GetMetadataLocator: {imagePath} {imageTimestamp:X8} {imageSize:X8} symbol store not enabled");
|
||||
}
|
||||
|
||||
if (pMetadataSize != IntPtr.Zero)
|
||||
{
|
||||
Marshal.WriteInt32(pMetadataSize, dataSize);
|
||||
|
@ -115,9 +144,9 @@ namespace SOS.Hosting
|
|||
int actualSize = 0;
|
||||
|
||||
Debug.Assert(pwszPathBuffer != IntPtr.Zero);
|
||||
try
|
||||
if (symbolService.IsSymbolStoreEnabled)
|
||||
{
|
||||
if (symbolService.IsSymbolStoreEnabled)
|
||||
try
|
||||
{
|
||||
SymbolStoreKey key = PEFileKeyGenerator.GetKey(imagePath, imageTimestamp, imageSize);
|
||||
string localFilePath = symbolService.DownloadFile(key.Index, key.FullPathName);
|
||||
|
@ -143,19 +172,19 @@ namespace SOS.Hosting
|
|||
hr = HResult.E_FAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception ex) when
|
||||
(ex is UnauthorizedAccessException
|
||||
or BadImageFormatException
|
||||
or InvalidVirtualAddressException
|
||||
or IOException)
|
||||
{
|
||||
Trace.TraceError($"GetICorDebugMetadataLocator: {imagePath} {imageTimestamp:X8} {imageSize:X8} symbol store not enabled");
|
||||
Trace.TraceError($"GetICorDebugMetadataLocator: {imagePath} {imageTimestamp:X8} {imageSize:X8} ERROR {ex.Message}");
|
||||
hr = HResult.E_FAIL;
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when
|
||||
(ex is UnauthorizedAccessException or
|
||||
BadImageFormatException or
|
||||
InvalidVirtualAddressException or
|
||||
IOException)
|
||||
else
|
||||
{
|
||||
Trace.TraceError($"GetICorDebugMetadataLocator: {imagePath} {imageTimestamp:X8} {imageSize:X8} ERROR {ex.Message}");
|
||||
Trace.TraceError($"GetICorDebugMetadataLocator: {imagePath} {imageTimestamp:X8} {imageSize:X8} symbol store not enabled");
|
||||
hr = HResult.E_FAIL;
|
||||
}
|
||||
if (pPathBufferSize != IntPtr.Zero)
|
||||
|
@ -164,5 +193,27 @@ namespace SOS.Hosting
|
|||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to open a file stream.
|
||||
/// </summary>
|
||||
/// <param name="path">file path</param>
|
||||
/// <returns>stream or null if doesn't exist or error</returns>
|
||||
public static Stream TryOpenFile(string path)
|
||||
{
|
||||
if (path is not null && File.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
return File.OpenRead(path);
|
||||
}
|
||||
catch (Exception ex) when (ex is UnauthorizedAccessException or NotSupportedException or IOException)
|
||||
{
|
||||
Trace.TraceError($"TryOpenFile: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ namespace SOS.Hosting
|
|||
|
||||
builder.AddMethod(new GetOperatingSystemDelegate(GetOperatingSystem));
|
||||
builder.AddMethod(new HostWrapper.GetServiceDelegate(ServiceWrapper.GetService));
|
||||
builder.AddMethod(new GetTempDirectoryDelegate(GetTempDirectory));
|
||||
builder.AddMethod(new GetRuntimeDelegate(GetRuntime));
|
||||
builder.AddMethod(new FlushDelegate(Flush));
|
||||
|
||||
|
@ -84,12 +83,6 @@ namespace SOS.Hosting
|
|||
return OperatingSystem.Unknown;
|
||||
}
|
||||
|
||||
private string GetTempDirectory(
|
||||
IntPtr self)
|
||||
{
|
||||
return _target.GetTempDirectory();
|
||||
}
|
||||
|
||||
private int GetRuntime(
|
||||
IntPtr self,
|
||||
IntPtr* ppRuntime)
|
||||
|
@ -133,11 +126,6 @@ namespace SOS.Hosting
|
|||
private delegate OperatingSystem GetOperatingSystemDelegate(
|
||||
[In] IntPtr self);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
[return: MarshalAs(UnmanagedType.LPStr)]
|
||||
private delegate string GetTempDirectoryDelegate(
|
||||
[In] IntPtr self);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
private delegate int GetRuntimeDelegate(
|
||||
[In] IntPtr self,
|
||||
|
|
|
@ -277,38 +277,6 @@ LPCSTR Runtime::GetDacFilePath()
|
|||
if (access(dacModulePath.c_str(), F_OK) == 0)
|
||||
#endif
|
||||
{
|
||||
#if defined(__linux__)
|
||||
// We are creating a symlink to the DAC in a temp directory
|
||||
// where libcoreclrtraceptprovider.so doesn't exist so it
|
||||
// doesn't get loaded by the DAC causing a LTTng-UST exception.
|
||||
//
|
||||
// Issue #https://github.com/dotnet/coreclr/issues/20205
|
||||
LPCSTR tmpPath = m_target->GetTempDirectory();
|
||||
if (tmpPath != nullptr)
|
||||
{
|
||||
std::string dacSymLink(tmpPath);
|
||||
dacSymLink.append(NETCORE_DAC_DLL_NAME_A);
|
||||
|
||||
// Check if the DAC file already exists in the temp directory because
|
||||
// of a "loadsymbols" command which downloads everything.
|
||||
if (access(dacSymLink.c_str(), F_OK) == 0)
|
||||
{
|
||||
dacModulePath.assign(dacSymLink);
|
||||
}
|
||||
else
|
||||
{
|
||||
int error = symlink(dacModulePath.c_str(), dacSymLink.c_str());
|
||||
if (error == 0)
|
||||
{
|
||||
dacModulePath.assign(dacSymLink);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtErr("symlink(%s, %s) FAILED %s\n", dacModulePath.c_str(), dacSymLink.c_str(), strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_dacFilePath = _strdup(dacModulePath.c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,12 +46,6 @@ public:
|
|||
/// <returns>S_OK or E_NOINTERFACE</returns>
|
||||
virtual HRESULT STDMETHODCALLTYPE GetService(REFIID serviceId, PVOID* service) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the unique temporary directory for this instance of SOS
|
||||
/// </summary>
|
||||
/// <returns>temporary directory string</returns>
|
||||
virtual LPCSTR STDMETHODCALLTYPE GetTempDirectory() = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current runtime instance
|
||||
/// </summary>
|
||||
|
|
|
@ -504,6 +504,8 @@ namespace SOS.Hosting
|
|||
|
||||
public int AddTarget(ITarget target) => throw new NotImplementedException();
|
||||
|
||||
public string GetTempDirectory() => throw new NotImplementedException();
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICLRDebuggingLibraryProvider* delegates
|
||||
|
|
|
@ -71,9 +71,6 @@ namespace Microsoft.Diagnostics.DebugServices.UnitTests
|
|||
|
||||
// Check that the ITarget properties match the test data
|
||||
host.TestData.CompareMembers(host.TestData.Target, target);
|
||||
|
||||
// Test temp directory
|
||||
AssertX.DirectoryExists("Target temporary directory", target.GetTempDirectory(), Output);
|
||||
}
|
||||
|
||||
[SkippableTheory, MemberData(nameof(GetConfigurations))]
|
||||
|
|
|
@ -105,6 +105,8 @@ namespace Microsoft.Diagnostics.DebugServices.UnitTests
|
|||
|
||||
public int AddTarget(ITarget target) => throw new NotImplementedException();
|
||||
|
||||
public string GetTempDirectory() => throw new NotImplementedException();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче