Skip to content

Commit

Permalink
Add a new implementation of ExternalTypeResolver. Some improvements…
Browse files Browse the repository at this point in the history
… in the `watch` window
  • Loading branch information
JaneySprings committed May 4, 2024
1 parent 11b2c73 commit affdc4d
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 133 deletions.
4 changes: 1 addition & 3 deletions src/DotNet.Meteor.Debug/Agents/DebugLaunchAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ public DebugLaunchAgent(LaunchConfiguration configuration) : base(configuration)
ArgumentNullException.ThrowIfNull(startArguments, "Debugger connection arguments not implemented.");

startInformation = new SoftDebuggerStartInfo(startArguments);
startInformation.SetAssemblySymbols(configuration.GetApplicationAssembliesDirectory(), configuration.DebuggerSessionOptions);
if (configuration.DebuggerSessionOptions.ProjectAssembliesOnly)
startInformation.SetUserAssemblyNames(configuration.GetApplicationAssembliesDirectory(), configuration.DebuggerSessionOptions);
startInformation.SetAssemblies(configuration.GetApplicationAssembliesDirectory(), configuration.DebuggerSessionOptions);
}

public override void Connect(SoftDebuggerSession session) {
Expand Down
9 changes: 2 additions & 7 deletions src/DotNet.Meteor.Debug/DebugSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
namespace DotNet.Meteor.Debug;

public class DebugSession : Session {
private ExternalTypeResolver typeResolver;
private BaseLaunchAgent launchAgent;

private readonly Handles<MonoClient.StackFrame> frameHandles = new Handles<MonoClient.StackFrame>();
Expand All @@ -28,6 +27,7 @@ public DebugSession(Stream input, Stream output) : base(input, output) {
session.DebugWriter = OnDebugLog;
session.OutputWriter = OnLog;
session.ExceptionHandler = OnExceptionHandled;
session.TypeResolverHandler = TypeResolverExtensions.ResolveType;

session.TargetStopped += TargetStopped;
session.TargetHitBreakpoint += TargetHitBreakpoint;
Expand Down Expand Up @@ -71,10 +71,6 @@ protected override LaunchResponse HandleLaunchRequest(LaunchArguments arguments)
SymbolServerExtensions.SetEventLogger(OnDebugDataReceived);
launchAgent = configuration.GetLauchAgent();
typeResolver = new ExternalTypeResolver(configuration.TempDirectoryPath, configuration.DebuggerSessionOptions);
launchAgent.Disposables.Add(() => typeResolver.Dispose());
session.TypeResolverHandler = typeResolver.Handle;
launchAgent.Launch(this);
launchAgent.Connect(session);
return new LaunchResponse();
Expand Down Expand Up @@ -381,8 +377,7 @@ protected override EvaluateResponse HandleEvaluateRequest(EvaluateArguments argu
if (!frame.ValidateExpression(arguments.Expression))
throw new ProtocolException("invalid expression");
var useExternalTypeResolver = arguments.Context != EvaluateArguments.ContextValue.Hover;
var value = frame.GetExpressionValue(arguments.Expression, session.Options.EvaluationOptions, useExternalTypeResolver);
var value = frame.GetExpressionValue(arguments.Expression, session.Options.EvaluationOptions);
value.WaitHandle.WaitOne(session.Options.EvaluationOptions.EvaluationTimeout);
if (value.IsEvaluating)
Expand Down
96 changes: 35 additions & 61 deletions src/DotNet.Meteor.Debug/Extensions/MonoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,6 @@ public static ExceptionInfo FindException(this SoftDebuggerSession session, long

return null;
}
public static ObjectValue GetExpressionValue(this StackFrame frame, string expression, EvaluationOptions evaluationOptions, bool useExternalTypeResolver) {
var options = evaluationOptions.Clone();
options.UseExternalTypeResolver = useExternalTypeResolver;
return frame.GetExpressionValue(expression, options);
}
public static string RemapSourceLocation(this SoftDebuggerSession session, SourceLocation location) {
if (location == null || string.IsNullOrEmpty(location.FileName))
return null;
Expand All @@ -68,72 +63,51 @@ public static string RemapSourceLocation(this SoftDebuggerSession session, Sourc
return location.FileName;
}

public static void SetUserAssemblyNames(this SoftDebuggerStartInfo startInfo, string assembliesDirectory, DebuggerSessionOptions options) {
var includeSymbolServers = options.SearchMicrosoftSymbolServer || options.SearchNuGetSymbolServer;
var assembliesPaths = Directory.EnumerateFiles(assembliesDirectory, "*.dll");
var files = assembliesPaths.Where(it => SymbolServerExtensions.HasDebugSymbols(it, includeSymbolServers));
if (!files.Any())
return;

var pathMap = new Dictionary<string, string>();
var names = new List<AssemblyName>();
public static void SetAssemblies(this SoftDebuggerStartInfo startInfo, string assembliesDirectory, DebuggerSessionOptions options) {
var useSymbolServers = options.SearchMicrosoftSymbolServer || options.SearchNuGetSymbolServer;
var assemblyPaths = Directory.EnumerateFiles(assembliesDirectory, "*.dll");
var assemblyPathMap = new Dictionary<string, string>();
var assemblySymbolPathMap = new Dictionary<string, string>();
var assemblyNames = new List<AssemblyName>();

foreach (var file in files) {
foreach (var assemblyPath in assemblyPaths) {
try {
using var asm = Mono.Cecil.AssemblyDefinition.ReadAssembly(file);
if (string.IsNullOrEmpty(asm.Name.Name)) {
DebuggerLoggingService.CustomLogger.LogMessage($"Assembly '{file}' has no name");
string assemblySymbolsFilePath = null;
if (!File.Exists(Path.ChangeExtension(assemblyPath, ".pdb"))) {
if (string.IsNullOrEmpty(assemblySymbolsFilePath) && options.SearchMicrosoftSymbolServer)
assemblySymbolsFilePath = SymbolServerExtensions.DownloadSourceSymbols(assemblyPath, SymbolServerExtensions.MicrosoftSymbolServerAddress);
if (string.IsNullOrEmpty(assemblySymbolsFilePath) && options.SearchNuGetSymbolServer)
assemblySymbolsFilePath = SymbolServerExtensions.DownloadSourceSymbols(assemblyPath, SymbolServerExtensions.NuGetSymbolServerAddress);
if (string.IsNullOrEmpty(assemblySymbolsFilePath))
DebuggerLoggingService.CustomLogger.LogMessage($"No symbols found for '{assemblyPath}'");
}

using var assemblyDefinition = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyPath);
if (string.IsNullOrEmpty(assemblyDefinition.Name.FullName)) {
DebuggerLoggingService.CustomLogger.LogMessage($"Assembly '{assemblyPath}' has no name");
continue;
}

AssemblyName name = new AssemblyName(asm.Name.FullName);
if (!pathMap.ContainsKey(asm.Name.FullName))
pathMap.Add(asm.Name.FullName, file);
if (options.EvaluationOptions.UseExternalTypeResolver)
TypeResolverExtensions.RegisterTypes(assemblyDefinition.MainModule.Types);

names.Add(name);
DebuggerLoggingService.CustomLogger.LogMessage($"User assembly '{name.Name}' added");
} catch (Exception e) {
DebuggerLoggingService.CustomLogger.LogError($"Error reading assembly '{file}'", e);
}
}
if (!string.IsNullOrEmpty(assemblySymbolsFilePath))
assemblySymbolPathMap.Add(assemblyDefinition.Name.FullName, assemblySymbolsFilePath);

startInfo.UserAssemblyNames = names;
startInfo.AssemblyPathMap = pathMap;
}
public static void SetAssemblySymbols(this SoftDebuggerStartInfo startInfo, string assembliesDirectory, DebuggerSessionOptions options) {
var useMicrosoftServer = options.SearchMicrosoftSymbolServer;
var useNuGetServer = options.SearchNuGetSymbolServer;
startInfo.SetAssemblySymbols(assembliesDirectory, useMicrosoftServer, useNuGetServer);
}
public static void SetAssemblySymbols(this SoftDebuggerStartInfo startInfo, string assembliesDirectory, bool useMicrosoftServer, bool useNuGetServer) {
var assemblyPaths = Directory.EnumerateFiles(assembliesDirectory, "*.dll");
var targetAssemblyPaths = assemblyPaths.Where(it => !File.Exists(Path.ChangeExtension(it, ".pdb")));
if (!targetAssemblyPaths.Any() || (!useMicrosoftServer && !useNuGetServer))
return;

var symbolPathMap = new Dictionary<string, string>();
foreach (var assemblyPath in targetAssemblyPaths) {
string symbolsFilePath = null;
string assemblyName = null;

if (string.IsNullOrEmpty(symbolsFilePath) && useMicrosoftServer)
symbolsFilePath = SymbolServerExtensions.DownloadSourceSymbols(assemblyPath, SymbolServerExtensions.MicrosoftSymbolServerAddress);
if (string.IsNullOrEmpty(symbolsFilePath) && useNuGetServer)
symbolsFilePath = SymbolServerExtensions.DownloadSourceSymbols(assemblyPath, SymbolServerExtensions.NuGetSymbolServerAddress);

if (string.IsNullOrEmpty(symbolsFilePath)) {
DebuggerLoggingService.CustomLogger.LogMessage($"No symbols found for '{assemblyPath}'");
continue;
if (options.ProjectAssembliesOnly && SymbolServerExtensions.HasDebugSymbols(assemblyPath, useSymbolServers)) {
var assemblyName = new AssemblyName(assemblyDefinition.Name.FullName);
assemblyPathMap.TryAdd(assemblyDefinition.Name.FullName, assemblyPath);
assemblyNames.Add(assemblyName);
DebuggerLoggingService.CustomLogger.LogMessage($"User assembly '{assemblyName.Name}' added");
}
} catch (Exception e) {
DebuggerLoggingService.CustomLogger.LogError($"Error while processing assembly '{assemblyPath}'", e);
}

using var asm = Mono.Cecil.AssemblyDefinition.ReadAssembly(assemblyPath);
assemblyName = asm.Name.FullName;

if (!string.IsNullOrEmpty(assemblyName) && !string.IsNullOrEmpty(symbolsFilePath))
symbolPathMap.Add(assemblyName, symbolsFilePath);
}

startInfo.SymbolPathMap = symbolPathMap;
startInfo.SymbolPathMap = assemblySymbolPathMap;
startInfo.AssemblyPathMap = assemblyPathMap;
startInfo.UserAssemblyNames = assemblyNames;
}

public static void WriteSdbCommand(this ISoftDebuggerConnectionProvider connectionProvider, Stream stream, string command) {
Expand Down
22 changes: 22 additions & 0 deletions src/DotNet.Meteor.Debug/Extensions/TypeResolverExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Debugging.Client;

namespace DotNet.Meteor.Debug.Extensions;

public static class TypeResolverExtensions {
private static readonly Dictionary<string, string> typesCache = new Dictionary<string, string>();

public static void RegisterTypes(IEnumerable<TypeDefinition> types) {
foreach (var type in types) {
if (string.IsNullOrEmpty(type.FullName) || string.IsNullOrEmpty(type.Name))
continue;

typesCache.TryAdd(type.Name, type.FullName);
}
}

public static string ResolveType(string type, SourceLocation _) {
return typesCache.TryGetValue(type, out var resolvedType) ? resolvedType : type;
}
}
62 changes: 0 additions & 62 deletions src/DotNet.Meteor.Debug/Plugins/ExternalTypeResolver.cs

This file was deleted.

0 comments on commit affdc4d

Please sign in to comment.