Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/debugger-libs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThays Grazia <thaystg@gmail.com>2022-06-24 20:04:17 +0300
committerGitHub <noreply@github.com>2022-06-24 20:04:17 +0300
commit74da8b11c514d57edd21379c860d289ddc228c30 (patch)
treefc15050184ab8e1bbe939cd3b55e3fce44f927ab
parent7cc29ac19969ffdda3844efd8f9984c90df7430e (diff)
Support new hotreload features and support line changes (#365)
* About HotReload now we can do in an android app and the debug will continue working: 1) add lines before the breakpoint and the breakpoint will continue working 2) remove lines before the breakpoint and the breakpoint will continue working 3) add new static methods 4) add new static fields 5) add new classes Also we check what is supported by runtime to make it possible from debugger. * Addressing @lewing comments. * Fix wrong implementation. * Changing enum as it was changed on runtime * Addressing @nosami comments.
-rw-r--r--Mono.Debugger.Soft/Mono.Debugger.Soft.csproj1
-rw-r--r--Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyMirror.cs46
-rw-r--r--Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs9
-rw-r--r--Mono.Debugger.Soft/Mono.Debugger.Soft/EncEvents.cs1
-rw-r--r--Mono.Debugger.Soft/Mono.Debugger.Soft/Location.cs5
-rw-r--r--Mono.Debugger.Soft/Mono.Debugger.Soft/MethodMirror.cs40
-rw-r--r--Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs74
-rw-r--r--Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs11
-rw-r--r--Mono.Debugging.Soft/SoftDebuggerSession.cs64
-rw-r--r--Mono.Debugging/Mono.Debugging.Client/BreakEventInfo.cs2
-rw-r--r--Mono.Debugging/Mono.Debugging.Client/Breakpoint.cs4
11 files changed, 216 insertions, 41 deletions
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj b/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj
index 263a216..94045d1 100644
--- a/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft.csproj
@@ -27,6 +27,7 @@
<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="$(NuGetVersionCecil)" PrivateAssets="all" />
<PackageReference Include="System.Runtime" Version="4.3.1" />
+ <PackageReference Include="System.Reflection.Metadata" Version="5.0" />
</ItemGroup>
</Project>
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyMirror.cs
index 4d2b091..5cb4d33 100644
--- a/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyMirror.cs
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/AssemblyMirror.cs
@@ -4,6 +4,9 @@ using Mono.Debugger;
using System.Collections.Generic;
using System.IO;
+using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
+
#if ENABLE_CECIL
using Mono.Cecil;
#endif
@@ -28,7 +31,7 @@ namespace Mono.Debugger.Soft
Dictionary<uint, long> tokenMethodCache = new Dictionary<uint, long> ();
#if ENABLE_CECIL
- AssemblyDefinition meta;
+ Mono.Cecil.AssemblyDefinition meta;
#endif
internal AssemblyMirror (VirtualMachine vm, long id) : base (vm, id) {
@@ -130,7 +133,7 @@ namespace Mono.Debugger.Soft
* An optional Cecil assembly which could be used to access metadata instead
* of reading it from the debuggee.
*/
- public AssemblyDefinition Metadata {
+ public Mono.Cecil.AssemblyDefinition Metadata {
get {
if (meta != null)
return meta;
@@ -147,12 +150,12 @@ namespace Mono.Debugger.Soft
// Read assembly metadata from the debuggee
// Since protocol version 2.47
- public AssemblyDefinition GetMetadata () {
+ public Mono.Cecil.AssemblyDefinition GetMetadata () {
if (IsDynamic)
throw new NotSupportedException ();
using (var ms = new MemoryStream (GetMetadataBlob ()))
- return meta = AssemblyDefinition.ReadAssembly (ms);
+ return meta = Mono.Cecil.AssemblyDefinition.ReadAssembly (ms);
}
#endif
@@ -237,5 +240,40 @@ namespace Mono.Debugger.Soft
return has_debug_info.Value;
}
}
+
+ public void ApplyChanges_DebugInformation (byte[] metadataDelta, byte[] pdbDelta)
+ {
+ var asmStream = new MemoryStream (metadataDelta);
+ MetadataReader asmMetadataReaderParm = MetadataReaderProvider.FromMetadataStream (asmStream).GetMetadataReader ();
+ var pdbStream = new MemoryStream (pdbDelta);
+ MetadataReader pdbMetadataReaderParm = MetadataReaderProvider.FromPortablePdbStream (pdbStream).GetMetadataReader ();
+
+ TypeInfo typeInfo = null;
+ int methodIdxAsm = 1;
+ foreach (var entry in asmMetadataReaderParm.GetEditAndContinueLogEntries ()) {
+ if (entry.Operation == EditAndContinueOperation.AddField) {
+ var typeHandle = (TypeDefinitionHandle)entry.Handle;
+ try
+ {
+ GetType ((uint)MetadataTokens.GetToken (asmMetadataReaderParm, typeHandle)).ClearCachedDebugInfo ();
+ }
+ catch (Exception) {
+ //type does not exist yet
+ }
+ }
+ }
+
+ foreach (var entry in pdbMetadataReaderParm.GetEditAndContinueMapEntries ()) {
+ if (entry.Kind == HandleKind.MethodDebugInformation) {
+ try {
+ var methodToken = (pdbMetadataReaderParm.GetRowNumber (entry) << 24) | (6);
+ this.GetMethod ((uint)methodToken).SetUpdatedByEnC ();
+ }
+ catch (Exception) {
+ //method does not exist yet
+ }
+ }
+ }
+ }
}
}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs
index 1c7d5d1..caa1ac7 100644
--- a/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/Connection.cs
@@ -514,7 +514,8 @@ namespace Mono.Debugger.Soft
GET_TYPES = 12,
INVOKE_METHODS = 13,
START_BUFFERING = 14,
- STOP_BUFFERING = 15
+ STOP_BUFFERING = 15,
+ GET_ENC_CAPABILITIES = 21
}
enum CmdEvent {
@@ -1961,6 +1962,12 @@ namespace Mono.Debugger.Soft
}
}
+ internal string VM_EnCCapabilities ()
+ {
+ PacketReader r = SendReceive (CommandSet.VM, (int)CmdVM.GET_ENC_CAPABILITIES, new PacketWriter ());
+ return r.ReadString ();
+ }
+
internal delegate void InvokeMethodCallback (ValueImpl v, ValueImpl exc, ValueImpl out_this, ValueImpl[] out_args, ErrorCode error, object state);
void read_invoke_res (PacketReader r, out ValueImpl v, out ValueImpl exc, out ValueImpl out_this, out ValueImpl[] out_args) {
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/EncEvents.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/EncEvents.cs
index 3228175..9eff4da 100644
--- a/Mono.Debugger.Soft/Mono.Debugger.Soft/EncEvents.cs
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/EncEvents.cs
@@ -9,7 +9,6 @@ namespace Mono.Debugger.Soft
{
this.id = id;
method = vm.GetMethod (id);
- method.ClearCachedLocalsDebugInfo ();
}
public MethodMirror GetMethod()
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/Location.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/Location.cs
index 6833e9a..be3a8cb 100644
--- a/Mono.Debugger.Soft/Mono.Debugger.Soft/Location.cs
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/Location.cs
@@ -48,7 +48,10 @@ namespace Mono.Debugger.Soft
get {
return line_number;
}
- }
+ set {
+ this.line_number = value;
+ }
+ }
// Since protocol version 2.19, 0 in earlier protocol versions
public int ColumnNumber {
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodMirror.cs
index 1500aa4..f64f7d8 100644
--- a/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodMirror.cs
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/MethodMirror.cs
@@ -25,7 +25,8 @@ namespace Mono.Debugger.Soft
MethodBodyMirror body;
MethodMirror gmd;
TypeMirror[] type_args;
-
+ bool updatedByEnC;
+
#if ENABLE_CECIL
C.MethodDefinition meta;
#endif
@@ -254,9 +255,12 @@ namespace Mono.Debugger.Soft
public void ClearCachedLocalsDebugInfo ()
{
- locals = null;
- debug_info = null;
- locations = null;
+ if (updatedByEnC) {
+ locals = null;
+ debug_info = null;
+ locations = null;
+ }
+ updatedByEnC = false;
}
public LocalScope [] GetScopes () {
@@ -460,6 +464,32 @@ namespace Mono.Debugger.Soft
var interp = new ILInterpreter (this);
return interp.Evaluate (this_val, args);
- }
+ }
+
+ internal void ApplySourceChanges (SourceUpdate sourceUpdate)
+ {
+ if (updatedByEnC)
+ return;
+ var lineDiff = 0;
+ if (Locations.Count > 0) {
+ lineDiff = sourceUpdate.FindLineDiff (locations[0].LineNumber);
+ }
+ if (lineDiff != 0)
+ {
+ foreach (var location in locations)
+ {
+ location.LineNumber += lineDiff;
+ }
+ for (int i = 0; i < debug_info.end_line_numbers.Count(); i++) {
+ debug_info.end_line_numbers[i] += lineDiff;
+ debug_info.line_numbers[i] += lineDiff;
+ }
+ }
+ }
+
+ internal void SetUpdatedByEnC ()
+ {
+ updatedByEnC = true;
+ }
}
}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs
index a13543a..b15e68a 100644
--- a/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/TypeMirror.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@@ -16,7 +17,7 @@ namespace Mono.Debugger.Soft
*/
public class TypeMirror : Mirror, IInvokable
{
- MethodMirror[] methods;
+ List<MethodMirror> methods;
AssemblyMirror ass;
ModuleMirror module;
FieldInfoMirror[] fields;
@@ -416,20 +417,26 @@ namespace Mono.Debugger.Soft
public MethodMirror[] GetMethods () {
if (methods == null) {
long[] ids = vm.conn.Type_GetMethods (id);
- MethodMirror[] m = new MethodMirror [ids.Length];
+ methods = new List<MethodMirror>(ids.Length);
for (int i = 0; i < ids.Length; ++i) {
- m [i] = vm.GetMethod (ids [i]);
+ methods.Add(vm.GetMethod (ids [i]));
}
- methods = m;
}
- return methods;
- }
-
- // FIXME: Sync this with Type
+ return methods.ToArray();
+ }
+ public void AddMethodIfNotExist (MethodMirror method)
+ {
+ if (!Array.Exists(GetMethods (), (m => m.GetId() == method.GetId()))) {
+ //is EnC
+ methods.Add (method);
+ }
+ }
+
+ // FIXME: Sync this with Type
public MethodMirror GetMethod (string name) {
- foreach (var m in GetMethods ())
- if (m.Name == name)
- return m;
+ foreach (var m in GetMethods ())
+ if (m.Name == name)
+ return m;
return null;
}
@@ -450,6 +457,12 @@ namespace Mono.Debugger.Soft
return fields;
}
+ public void ClearCachedDebugInfo ()
+ {
+ fields = null;
+ properties = null;
+ }
+
public FieldInfoMirror GetField (string name) {
if (name == null)
throw new ArgumentNullException ("name");
@@ -896,10 +909,19 @@ namespace Mono.Debugger.Soft
if (!iface_map.TryGetValue (interfaceType, out res))
throw new ArgumentException ("Interface not found", "interfaceType");
return res;
- }
-
- // Return whenever the type initializer of this type has ran
- // Since protocol version 2.23
+ }
+
+ public void ApplySourceChanges (SourceUpdate sourceUpdate)
+ {
+ var methods = GetMethods ();
+ foreach (var method in methods)
+ {
+ method.ApplySourceChanges (sourceUpdate);
+ }
+ }
+
+ // Return whenever the type initializer of this type has ran
+ // Since protocol version 2.23
public bool IsInitialized {
get {
vm.CheckProtocolVersion (2, 23);
@@ -908,5 +930,25 @@ namespace Mono.Debugger.Soft
return inited;
}
}
- }
+ }
+
+ public class SourceUpdate
+ {
+ public List<Tuple<int, int>> LineUpdates { get; } //Tuple<oldLine, newLine>
+ public string FileName { get; }
+
+ public SourceUpdate (string fileName)
+ {
+ this.FileName = fileName;
+ LineUpdates = new List<Tuple<int, int>> ();
+ }
+
+ internal int FindLineDiff (int lineNumber)
+ {
+ var line = LineUpdates.FirstOrDefault (item => item.Item1 + 1 == lineNumber);
+ if (line != null)
+ return line.Item2 - line.Item1;
+ return 0;
+ }
+ }
}
diff --git a/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs b/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs
index 3d51655..078a0c9 100644
--- a/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs
+++ b/Mono.Debugger.Soft/Mono.Debugger.Soft/VirtualMachine.cs
@@ -792,8 +792,15 @@ namespace Mono.Debugger.Soft
internal void CheckProtocolVersion (int major, int minor) {
if (!conn.Version.AtLeast (major, minor))
throw new NotSupportedException ("This request is not supported by the protocol version implemented by the debuggee.");
- }
- }
+ }
+
+ public string GetEnCCapabilities ()
+ {
+ if (conn.Version.AtLeast (2, 61))
+ return conn.VM_EnCCapabilities ();
+ return "Baseline";
+ }
+ }
class EventHandler : MarshalByRefObject, IEventHandler
{
diff --git a/Mono.Debugging.Soft/SoftDebuggerSession.cs b/Mono.Debugging.Soft/SoftDebuggerSession.cs
index a173d25..ecd28ca 100644
--- a/Mono.Debugging.Soft/SoftDebuggerSession.cs
+++ b/Mono.Debugging.Soft/SoftDebuggerSession.cs
@@ -48,6 +48,7 @@ using Mono.Debugging.Client;
using Mono.Debugging.Evaluation;
using StackFrame = Mono.Debugger.Soft.StackFrame;
+using System.Collections.Immutable;
namespace Mono.Debugging.Soft
{
@@ -76,6 +77,7 @@ namespace Mono.Debugging.Soft
bool loggedSymlinkedRuntimesBug;
SoftDebuggerStartArgs startArgs;
List<string> userAssemblyNames;
+ List<SourceUpdate> sourceUpdates;
ThreadInfo[] current_threads;
string remoteProcessName;
long currentAddress = -1;
@@ -99,6 +101,7 @@ namespace Mono.Debugging.Soft
Adaptor = CreateSoftDebuggerAdaptor ();
Adaptor.BusyStateChanged += (sender, e) => SetBusyState (e);
Adaptor.DebuggerSession = this;
+ sourceUpdates = new List<SourceUpdate> ();
}
protected virtual SoftDebuggerAdaptor CreateSoftDebuggerAdaptor ()
@@ -1193,12 +1196,12 @@ namespace Mono.Debugging.Soft
found = true;
breakInfo.SetStatus (BreakEventStatus.Bound, null);
}
-
lock (pending_bes) {
pending_bes.Add (breakInfo);
}
if (!found) {
+ breakInfo.Breakpoint = breakpoint;
if (insideLoadedRange)
breakInfo.SetStatus (BreakEventStatus.Invalid, null);
else
@@ -2415,15 +2418,33 @@ namespace Mono.Debugging.Soft
void HandleMethodUpdateEvents(MethodUpdateEvent[] methods)
{
- foreach (var method in methods)
+ foreach (var method in methods) //add new methods to type
{
- foreach (var bp in breakpoints) {
- if (bp.Value.Location.Method.GetId() == method.GetMethod().GetId())
- {
- bool dummy = false;
- var l = FindLocationByMethod (bp.Value.Location.Method, bp.Value.Location.SourceFile, bp.Value.Location.LineNumber, bp.Value.Location.ColumnNumber, ref dummy);
- bp.Value.Location = l;
- UpdateBreakpoint ((Breakpoint)bp.Value.BreakEvent, bp.Value);
+ method.GetMethod ().ClearCachedLocalsDebugInfo ();
+ method.GetMethod ().DeclaringType.AddMethodIfNotExist (method.GetMethod ());
+ }
+ foreach (var breakpoint in breakpoints) {
+ Breakpoint bp = ((Breakpoint)breakpoint.Value.BreakEvent);
+ if (bp.UpdatedByEnC) {
+ bool dummy = false;
+ var l = FindLocationByMethod (breakpoint.Value.Location.Method, bp.FileName, bp.Line, bp.Column, ref dummy);
+ if (l != null) {
+ breakpoint.Value.Location = l;
+ UpdateBreakpoint (bp, breakpoint.Value);
+ bp.UpdatedByEnC = false;
+ }
+ }
+ }
+ foreach (var bp in pending_bes) {
+ if (bp.Status != BreakEventStatus.Bound) {
+ foreach (var location in FindLocationsByFile (bp.Breakpoint.FileName, bp.Breakpoint.Line, bp.Breakpoint.Column, out _, out bool insideLoadedRange)) {
+ OnDebuggerOutput (false, string.Format ("Resolved pending breakpoint at '{0}:{1},{2}' to {3} [0x{4:x5}].\n",
+ bp.Breakpoint.FileName, bp.Breakpoint.Line, bp.Breakpoint.Column,
+ GetPrettyMethodName (location.Method), location.ILOffset));
+
+ bp.Location = location;
+ InsertBreakpoint (bp.Breakpoint, bp);
+ bp.SetStatus (BreakEventStatus.Bound, null);
}
}
}
@@ -3342,6 +3363,14 @@ namespace Mono.Debugging.Soft
return lines.ToArray ();
}
+ public void AddSourceUpdate (string fileName)
+ {
+ sourceUpdates.Add (new SourceUpdate(fileName));
+ }
+ public void AddLineUpdate (int oldLine, int newLine)
+ {
+ sourceUpdates.Last().LineUpdates.Add (new Tuple<int, int>(oldLine, newLine));
+ }
public void ApplyChanges (ModuleMirror module, byte[] metadataDelta, byte[] ilDelta, byte[] pdbDelta = null)
{
var rootDomain = VirtualMachine.RootDomain;
@@ -3353,7 +3382,22 @@ namespace Mono.Debugging.Soft
else
pdbArray = rootDomain.CreateByteArray (pdbDelta);
- module.ApplyChanges (metadataArray, ilArray, pdbArray);
+ module.Assembly.ApplyChanges_DebugInformation (metadataDelta, pdbDelta);
+ module.ApplyChanges (metadataArray, ilArray, pdbArray);
+ foreach (var sourceUpdate in sourceUpdates)
+ {
+ var types = VirtualMachine.GetTypesForSourceFile (sourceUpdate.FileName, false);
+ foreach (var type in types)
+ {
+ type.ApplySourceChanges (sourceUpdate);
+ }
+ }
+ sourceUpdates.Clear ();
+ }
+
+ public string GetEnCCapabilities()
+ {
+ return vm.GetEnCCapabilities ();
}
static string EscapeString (string text)
{
diff --git a/Mono.Debugging/Mono.Debugging.Client/BreakEventInfo.cs b/Mono.Debugging/Mono.Debugging.Client/BreakEventInfo.cs
index 074d098..dfda575 100644
--- a/Mono.Debugging/Mono.Debugging.Client/BreakEventInfo.cs
+++ b/Mono.Debugging/Mono.Debugging.Client/BreakEventInfo.cs
@@ -52,6 +52,8 @@ namespace Mono.Debugging.Client
/// </summary>
public BreakEventStatus Status { get; private set; }
+ public Breakpoint Breakpoint { get; set; }
+
/// <summary>
/// Gets a description of the status
/// </summary>
diff --git a/Mono.Debugging/Mono.Debugging.Client/Breakpoint.cs b/Mono.Debugging/Mono.Debugging.Client/Breakpoint.cs
index 8770b1d..f201f2c 100644
--- a/Mono.Debugging/Mono.Debugging.Client/Breakpoint.cs
+++ b/Mono.Debugging/Mono.Debugging.Client/Breakpoint.cs
@@ -117,7 +117,9 @@ namespace Mono.Debugging.Client
ResetAdjustedColumn ();
column = newColumn;
}
-
+
+ public bool UpdatedByEnC { get; set; }
+
public void SetLine (int newLine)
{
ResetAdjustedLine ();