Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc service and implementation cleanup #5129

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public static void Enable()

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;
Expand All @@ -39,10 +39,10 @@ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEven

// 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;
}

Expand All @@ -51,10 +51,10 @@ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEven
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;
}
}
Expand Down
36 changes: 36 additions & 0 deletions src/Microsoft.Diagnostics.DebugServices.Implementation/Host.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.IO;
using Microsoft.Diagnostics.DebugServices;

Expand All @@ -14,6 +15,7 @@ public class Host : IHost
private readonly ServiceManager _serviceManager;
private ServiceContainer _serviceContainer;
private readonly List<ITarget> _targets = new();
private string _tempDirectory;
private int _targetIdFactory;

public Host(HostType type)
Expand Down Expand Up @@ -61,6 +63,7 @@ public void DestoryTargets()
target.Destroy();
}
_targets.Clear();
CleanupTempDirectory();
}

#region IHost
Expand All @@ -84,6 +87,39 @@ public int AddTarget(ITarget target)
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
{
foreach (string file in Directory.EnumerateFiles(_tempDirectory))
{
File.Delete(file);
}
Directory.Delete(_tempDirectory);
}
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
{
}
_tempDirectory = null;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public virtual void Dispose()

public virtual uint? IndexTimeStamp { get; protected set; }

public bool IsPEImage
public virtual bool IsPEImage
{
get
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public override string LoadSymbols()

#endregion

internal void AddService<T>(T service) => _serviceContainer.AddService(service);

protected override ModuleService ModuleService { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,19 @@ IEnumerable<IModule> IModuleService.GetModuleFromModuleName(string moduleName)
}
}

/// <summary>
/// Create a module instance
/// </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 IModuleService.CreateModule(int moduleIndex, ulong imageBase, ulong imageSize, string imageName)
{
return new ModuleFromAddress(this, moduleIndex, imageBase, imageSize, imageName);
}

#endregion

/// <summary>
Expand Down Expand Up @@ -220,7 +233,7 @@ internal PEFile GetPEInfo(ulong address, ulong size, out IEnumerable<PdbFileInfo
// 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)
Expand Down Expand Up @@ -288,9 +301,6 @@ private PEFile GetPEInfo(bool isVirtual, ulong address, ulong size, out List<Pdb
/// <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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public ModuleFromDataReader(ModuleServiceFromDataReader moduleService, int modul

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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public ServiceEvent()
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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public SymbolService(IHost host)
/// <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 uses the VS symbol cache path: %TEMPDIR%\SymbolCache
/// * dotnet-dump/lldb on Linux/MacOS uses: $HOME/.dotnet/symbolcache
/// </summary>
public string DefaultSymbolCache
Expand All @@ -86,8 +86,7 @@ public string DefaultSymbolCache
_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
Expand Down Expand Up @@ -461,6 +460,32 @@ public string DownloadSymbolFile(IModule module)
/// <param name="file">the full path name of the file</param>
public string DownloadFile(string index, string file) => DownloadFile(new SymbolStoreKey(index, file));

/// <summary>
/// Downloads and returns the metadata for the assembly.
/// </summary>
/// <param name="module">module assembly</param>
/// <returns>metadata bytes</returns>
public ImmutableArray<byte> GetMetadata(IModule module)
{
try
{
PEReader reader = module.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;
}

/// <summary>
/// Returns the metadata for the assembly
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -82,23 +81,6 @@ protected void Finished()
/// </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>
Expand Down Expand Up @@ -132,7 +114,6 @@ public virtual void Destroy()
OnDestroyEvent.Fire();
_serviceContainer.RemoveService(typeof(ITarget));
_serviceContainer.DisposeServices();
CleanupTempDirectory();
}

#endregion
Expand All @@ -154,25 +135,6 @@ private static Reader CreateReader(IServiceProvider services)
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;
Expand All @@ -192,10 +154,6 @@ public override string ToString()
{
sb.Append($" {_dumpPath}");
}
if (_tempDirectory != null)
{
sb.Append($" {_tempDirectory}");
}
return sb.ToString();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace Microsoft.Diagnostics.DebugServices.Implementation
{
Expand All @@ -23,7 +24,7 @@ public Thread(ThreadService threadService, int index, uint id)
_serviceContainer.AddService<IThread>(this);
}

void IDisposable.Dispose()
public void Dispose()
{
_serviceContainer.RemoveService(typeof(IThread));
_serviceContainer.DisposeServices();
Expand Down Expand Up @@ -58,22 +59,47 @@ public ReadOnlySpan<byte> GetThreadContext()
{
if (_threadContext.IsEmpty)
{
_threadContext = _threadService.GetThreadContext(this);
byte[] threadContext = new byte[_threadService.ContextSize];
if (!GetThreadContextInner(_threadService.ContextFlags, threadContext))
{
throw new DiagnosticsException();
}
_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;
Expand Down
Loading