diff --git a/loc/lcl/CHS/OpenFolderSchema.json.lcl b/loc/lcl/CHS/OpenFolderSchema.json.lcl
index 140e54f7f..a17ab9b24 100644
--- a/loc/lcl/CHS/OpenFolderSchema.json.lcl
+++ b/loc/lcl/CHS/OpenFolderSchema.json.lcl
@@ -865,6 +865,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
diff --git a/loc/lcl/CHT/OpenFolderSchema.json.lcl b/loc/lcl/CHT/OpenFolderSchema.json.lcl
index d05fe03da..0ce4d648b 100644
--- a/loc/lcl/CHT/OpenFolderSchema.json.lcl
+++ b/loc/lcl/CHT/OpenFolderSchema.json.lcl
@@ -865,6 +865,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
diff --git a/loc/lcl/CSY/OpenFolderSchema.json.lcl b/loc/lcl/CSY/OpenFolderSchema.json.lcl
index e444a35ba..d3dd4ad6f 100644
--- a/loc/lcl/CSY/OpenFolderSchema.json.lcl
+++ b/loc/lcl/CSY/OpenFolderSchema.json.lcl
@@ -865,6 +865,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
diff --git a/loc/lcl/DEU/OpenFolderSchema.json.lcl b/loc/lcl/DEU/OpenFolderSchema.json.lcl
index d00b8ffe8..b8941d421 100644
--- a/loc/lcl/DEU/OpenFolderSchema.json.lcl
+++ b/loc/lcl/DEU/OpenFolderSchema.json.lcl
@@ -865,6 +865,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
diff --git a/loc/lcl/ESN/OpenFolderSchema.json.lcl b/loc/lcl/ESN/OpenFolderSchema.json.lcl
index 08193bf9a..8a9a7376d 100644
--- a/loc/lcl/ESN/OpenFolderSchema.json.lcl
+++ b/loc/lcl/ESN/OpenFolderSchema.json.lcl
@@ -814,6 +814,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
diff --git a/loc/lcl/JPN/OpenFolderSchema.json.lcl b/loc/lcl/JPN/OpenFolderSchema.json.lcl
index 319c23253..68e3dd5f7 100644
--- a/loc/lcl/JPN/OpenFolderSchema.json.lcl
+++ b/loc/lcl/JPN/OpenFolderSchema.json.lcl
@@ -865,6 +865,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
diff --git a/loc/lcl/KOR/OpenFolderSchema.json.lcl b/loc/lcl/KOR/OpenFolderSchema.json.lcl
index fcc9775b5..2aa095794 100644
--- a/loc/lcl/KOR/OpenFolderSchema.json.lcl
+++ b/loc/lcl/KOR/OpenFolderSchema.json.lcl
@@ -865,6 +865,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
diff --git a/loc/lcl/RUS/OpenFolderSchema.json.lcl b/loc/lcl/RUS/OpenFolderSchema.json.lcl
index 23799a41e..03db31052 100644
--- a/loc/lcl/RUS/OpenFolderSchema.json.lcl
+++ b/loc/lcl/RUS/OpenFolderSchema.json.lcl
@@ -814,6 +814,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
diff --git a/src/DebugEngineHost.VSCode/HostMarshal.cs b/src/DebugEngineHost.VSCode/HostMarshal.cs
index f6a243124..41f780164 100644
--- a/src/DebugEngineHost.VSCode/HostMarshal.cs
+++ b/src/DebugEngineHost.VSCode/HostMarshal.cs
@@ -4,6 +4,7 @@
using Microsoft.DebugEngineHost.VSCode;
using Microsoft.VisualStudio.Debugger.Interop;
using System;
+using System.Runtime.InteropServices;
namespace Microsoft.DebugEngineHost
{
@@ -110,7 +111,7 @@ public static IDebugFunctionPosition2 GetDebugFunctionPositionForIntPtr(IntPtr f
///
public static string GetDataBreakpointStringForIntPtr(IntPtr stringId)
{
- throw new NotImplementedException();
+ return Marshal.PtrToStringBSTR(stringId);
}
///
@@ -120,7 +121,7 @@ public static string GetDataBreakpointStringForIntPtr(IntPtr stringId)
/// IntPtr to a BSTR which can be returned to VS.
public static IntPtr GetIntPtrForDataBreakpointAddress(string address)
{
- throw new NotImplementedException();
+ return Marshal.StringToBSTR(address);
}
///
diff --git a/src/DebugEngineHost.VSCode/VSCode/EngineConfiguration.cs b/src/DebugEngineHost.VSCode/VSCode/EngineConfiguration.cs
index 938ed4a49..265d4246c 100644
--- a/src/DebugEngineHost.VSCode/VSCode/EngineConfiguration.cs
+++ b/src/DebugEngineHost.VSCode/VSCode/EngineConfiguration.cs
@@ -33,6 +33,7 @@ public sealed class EngineConfiguration
private bool _conditionalBP;
private bool _functionBP;
private bool _clipboardContext;
+ private bool _dataBP;
// NOTE: CoreCLR doesn't support providing a code base when loading assemblies. So all debug engines
// must be placed in the directory of OpenDebugAD7.exe
@@ -74,6 +75,12 @@ public bool ClipboardContext
set { SetProperty(out _clipboardContext, value); }
}
+ public bool DataBP
+ {
+ get { return _dataBP; }
+ set { SetProperty(out _dataBP, value); }
+ }
+
///
/// Provides the directory of the debug adapter. This is the directory where
diff --git a/src/IOSDebugLauncher/Launcher.cs b/src/IOSDebugLauncher/Launcher.cs
index 084a24cd3..9c5461a4c 100644
--- a/src/IOSDebugLauncher/Launcher.cs
+++ b/src/IOSDebugLauncher/Launcher.cs
@@ -92,7 +92,7 @@ void IPlatformAppLauncher.SetupForDebugging(out LaunchOptions debuggerLaunchOpti
return _client.ServerCertificateValidationCallback(sender, (X509Certificate)certificate, (X509Chain)chain, sslPolicyErrors);
};
}
-
+
debuggerLaunchOptions.TargetArchitecture = _launchOptions.TargetArchitecture;
debuggerLaunchOptions.AdditionalSOLibSearchPath = _launchOptions.AdditionalSOLibSearchPath;
debuggerLaunchOptions.DebuggerMIMode = MIMode.Lldb;
diff --git a/src/MICore/JsonLaunchOptions.cs b/src/MICore/JsonLaunchOptions.cs
index 2b63b144c..5dc63d0bb 100644
--- a/src/MICore/JsonLaunchOptions.cs
+++ b/src/MICore/JsonLaunchOptions.cs
@@ -72,6 +72,12 @@ public abstract partial class BaseOptions
[JsonProperty("miDebuggerServerAddress", DefaultValueHandling = DefaultValueHandling.Ignore)]
public string MiDebuggerServerAddress { get; set; }
+ ///
+ /// If true, use gdb extended-remote mode to connect to gdbserver.
+ ///
+ [JsonProperty("useExtendedRemote", DefaultValueHandling = DefaultValueHandling.Ignore)]
+ public bool? UseExtendedRemote { get; set; }
+
///
/// Optional source file mappings passed to the debug engine. Example: '{ "/original/source/path":"/current/source/path" }'
///
@@ -137,6 +143,7 @@ public AttachOptions(
string miDebuggerPath = null,
string miDebuggerArgs = null,
string miDebuggerServerAddress = null,
+ bool? useExtendedRemote = null,
HardwareBreakpointInfo hardwareBreakpointInfo = null,
Dictionary sourceFileMap = null,
PipeTransport pipeTransport = null,
@@ -152,6 +159,7 @@ public AttachOptions(
this.MiDebuggerPath = miDebuggerPath;
this.MiDebuggerArgs = miDebuggerArgs;
this.MiDebuggerServerAddress = miDebuggerServerAddress;
+ this.UseExtendedRemote = useExtendedRemote;
this.ProcessId = processId;
this.HardwareBreakpointInfo = hardwareBreakpointInfo;
this.SourceFileMap = sourceFileMap;
@@ -390,6 +398,7 @@ public LaunchOptions(
string miDebuggerPath = null,
string miDebuggerArgs = null,
string miDebuggerServerAddress = null,
+ bool? useExtendedRemote = null,
bool? stopAtEntry = null,
string debugServerPath = null,
string debugServerArgs = null,
@@ -421,6 +430,7 @@ public LaunchOptions(
this.MiDebuggerPath = miDebuggerPath;
this.MiDebuggerArgs = miDebuggerArgs;
this.MiDebuggerServerAddress = miDebuggerServerAddress;
+ this.UseExtendedRemote = useExtendedRemote;
this.StopAtEntry = stopAtEntry;
this.DebugServerPath = debugServerPath;
this.DebugServerArgs = debugServerArgs;
diff --git a/src/MICore/LaunchOptions.cs b/src/MICore/LaunchOptions.cs
index 2315055b6..ad4740091 100644
--- a/src/MICore/LaunchOptions.cs
+++ b/src/MICore/LaunchOptions.cs
@@ -443,6 +443,18 @@ public LocalLaunchOptions(string MIDebuggerPath, string MIDebuggerServerAddress,
this.MIDebuggerArgs = MIDebuggerArgs;
}
+ public LocalLaunchOptions(string MIDebuggerPath, string MIDebuggerServerAddress, bool UseExtendedRemote) :
+ this(MIDebuggerPath, MIDebuggerServerAddress)
+ {
+ this.UseExtendedRemote = UseExtendedRemote;
+ }
+
+ public LocalLaunchOptions(string MIDebuggerPath, string MIDebuggerServerAddress, string MIDebuggerArgs, bool UseExtendedRemote) :
+ this(MIDebuggerPath, MIDebuggerServerAddress, MIDebuggerArgs)
+ {
+ this.UseExtendedRemote = UseExtendedRemote;
+ }
+
private void InitializeServerOptions(Json.LaunchOptions.LaunchOptions launchOptions)
{
if (!String.IsNullOrWhiteSpace(launchOptions.DebugServerPath))
@@ -533,7 +545,8 @@ static internal LocalLaunchOptions CreateFromJson(JObject parsedOptions)
LocalLaunchOptions localLaunchOptions = new LocalLaunchOptions(RequireAttribute(miDebuggerPath, nameof(miDebuggerPath)),
launchOptions.MiDebuggerServerAddress,
- launchOptions.MiDebuggerArgs
+ launchOptions.MiDebuggerArgs,
+ launchOptions.UseExtendedRemote.GetValueOrDefault(false)
);
// Load up common options
@@ -561,7 +574,8 @@ static internal LocalLaunchOptions CreateFromXml(Xml.LaunchOptions.LocalLaunchOp
var options = new LocalLaunchOptions(
RequireAttribute(miDebuggerPath, "MIDebuggerPath"),
source.MIDebuggerServerAddress,
- source.MIDebuggerArgs);
+ source.MIDebuggerArgs,
+ source.UseExtendedRemote);
options.InitializeCommonOptions(source);
options.InitializeServerOptions(source);
options._useExternalConsole = source.ExternalConsole;
@@ -666,6 +680,11 @@ private static string EnsureDebuggerPath(string miDebuggerPath, string debuggerB
///
public string MIDebuggerServerAddress { get; private set; }
+ ///
+ /// [Optional] If true, use gdb extended-remote mode to connect to gdbserver.
+ ///
+ public bool UseExtendedRemote { get; private set; }
+
///
/// [Optional] MI Debugger Server exe, if non-null then the MIEngine will start the debug server before starting the debugger
///
diff --git a/src/MICore/LaunchOptions.xsd b/src/MICore/LaunchOptions.xsd
index b5ef5db1e..2e3f63b9b 100644
--- a/src/MICore/LaunchOptions.xsd
+++ b/src/MICore/LaunchOptions.xsd
@@ -230,6 +230,11 @@
Network address of the MI Debugger Server to connect to (example: localhost:1234).
+
+
+ If true, use gdb extended-remote mode to connect to gdbserver.
+
+
Full path to the server executable. If non-null then the MIEngine will start the server.
diff --git a/src/MICore/LaunchOptions.xsd.types.designer.cs b/src/MICore/LaunchOptions.xsd.types.designer.cs
index 5551c7e82..f8b2766a2 100644
--- a/src/MICore/LaunchOptions.xsd.types.designer.cs
+++ b/src/MICore/LaunchOptions.xsd.types.designer.cs
@@ -575,7 +575,11 @@ public partial class LocalLaunchOptions : BaseLaunchOptions {
///
[System.Xml.Serialization.XmlAttributeAttribute()]
public string MIDebuggerServerAddress;
-
+
+ ///
+ [System.Xml.Serialization.XmlAttributeAttribute()]
+ public bool UseExtendedRemote;
+
///
[System.Xml.Serialization.XmlAttributeAttribute()]
public string DebugServer;
diff --git a/src/MIDebugEngine/AD7.Impl/AD7PendingBreakpoint.cs b/src/MIDebugEngine/AD7.Impl/AD7PendingBreakpoint.cs
index e284d76b9..3dab46a82 100644
--- a/src/MIDebugEngine/AD7.Impl/AD7PendingBreakpoint.cs
+++ b/src/MIDebugEngine/AD7.Impl/AD7PendingBreakpoint.cs
@@ -321,6 +321,11 @@ private int BindWithTimeout()
this.SetError(new AD7ErrorBreakpoint(this, ResourceStrings.LongBind, enum_BP_ERROR_TYPE.BPET_SEV_LOW | enum_BP_ERROR_TYPE.BPET_TYPE_WARNING), true);
return Constants.S_FALSE;
}
+ else if (this._BPError != null)
+ {
+ // Ran into some sort of error
+ return Constants.E_FAIL;
+ }
else
{
if ((enum_BP_LOCATION_TYPE)_bpRequestInfo.bpLocation.bpLocationType == enum_BP_LOCATION_TYPE.BPLT_DATA_STRING)
@@ -364,7 +369,16 @@ internal async Task BindAsync()
}
else
{
- bindResult = await PendingBreakpoint.Bind(_address, _size, _engine.DebuggedProcess, _condition, this);
+ try
+ {
+ bindResult = await PendingBreakpoint.Bind(_address, _size, _engine.DebuggedProcess, _condition, this);
+ }
+ catch (ArgumentException ex)
+ {
+ // There was an error binding at the address with the specified size. This could happen if the size is greater
+ // than the max size a data bp can watch.
+ bindResult = new PendingBreakpoint.BindResult(ex.Message);
+ }
}
lock (_boundBreakpoints)
diff --git a/src/MIDebugEngine/AD7.Impl/AD7Property.cs b/src/MIDebugEngine/AD7.Impl/AD7Property.cs
index 6387aed3c..596068765 100644
--- a/src/MIDebugEngine/AD7.Impl/AD7Property.cs
+++ b/src/MIDebugEngine/AD7.Impl/AD7Property.cs
@@ -141,10 +141,32 @@ public int EnumChildren(enum_DEBUGPROP_INFO_FLAGS dwFields, uint dwRadix, ref Gu
{
_engine.DebuggedProcess.Natvis.WaitDialog.ShowWaitDialog(_variableInformation.Name);
var children = _engine.DebuggedProcess.Natvis.Expand(_variableInformation);
- DEBUG_PROPERTY_INFO[] properties = new DEBUG_PROPERTY_INFO[children.Length];
- for (int i = 0; i < children.Length; i++)
+
+ // Count number of children that fit filter (results saved in "fitsFilter")
+ int propertyCount = children.Length;
+ bool[] fitsFilter = null;
+ if (!string.IsNullOrEmpty(pszNameFilter))
+ {
+ fitsFilter = new bool[children.Length];
+ for (int i = 0; i < children.Length; i++)
+ {
+ fitsFilter[i] = string.Equals(children[i].Name, pszNameFilter, StringComparison.Ordinal);
+ if (!fitsFilter[i])
+ {
+ propertyCount--;
+ }
+ }
+ }
+
+ // Create property array
+ DEBUG_PROPERTY_INFO[] properties = new DEBUG_PROPERTY_INFO[propertyCount];
+ for (int i = 0, j = 0; i < children.Length; i++)
{
- properties[i] = (new AD7Property(_engine, children[i])).ConstructDebugPropertyInfo(dwFields);
+ if (fitsFilter == null || fitsFilter[i])
+ {
+ properties[j] = (new AD7Property(_engine, children[i])).ConstructDebugPropertyInfo(dwFields);
+ ++j; // increment j if we fit filter, this allows us to traverse "properties" array properly.
+ }
}
ppEnum = new AD7PropertyEnum(properties);
return Constants.S_OK;
diff --git a/src/MIDebugEngine/Engine.Impl/CygwinFileMapper.cs b/src/MIDebugEngine/Engine.Impl/CygwinFileMapper.cs
index 534a6ef5a..a8339fb8d 100644
--- a/src/MIDebugEngine/Engine.Impl/CygwinFileMapper.cs
+++ b/src/MIDebugEngine/Engine.Impl/CygwinFileMapper.cs
@@ -22,6 +22,14 @@ public CygwinFilePathMapper(DebuggedProcess debuggedProcess)
_cygwinToWindows = new Dictionary();
}
+ ///
+ /// Maps cygwin paths (/usr/bin) to Windows Paths (C:\User\bin)
+ ///
+ /// We cache these paths because most of the time it comes from callstacks that we need to provide
+ /// source file maps.
+ ///
+ /// A string representing the cygwin path.
+ /// A string as a full Windows path
public string MapCygwinToWindows(string origCygwinPath)
{
if (!(_debuggedProcess.LaunchOptions is LocalLaunchOptions))
@@ -39,7 +47,7 @@ public string MapCygwinToWindows(string origCygwinPath)
{
if (!_cygwinToWindows.TryGetValue(cygwinPath, out windowsPath))
{
- if (!LaunchCygPathAndReadResult(cygwinPath, localLaunchOptions.MIDebuggerPath, out windowsPath))
+ if (!LaunchCygPathAndReadResult(cygwinPath, localLaunchOptions.MIDebuggerPath, convertToWindowsPath: true, out windowsPath))
{
return origCygwinPath;
}
@@ -51,14 +59,40 @@ public string MapCygwinToWindows(string origCygwinPath)
return windowsPath;
}
+ ///
+ /// Maps Windows paths (C:\User\bin) to Cygwin Paths (/usr/bin)
+ ///
+ /// Not cached since we only do this for setting the program, symbol, and working dir.
+ ///
+ /// A string representing the Windows path.
+ /// A string as a full unix path
+ public string MapWindowsToCygwin(string origWindowsPath)
+ {
+ if (!(_debuggedProcess.LaunchOptions is LocalLaunchOptions))
+ {
+ return origWindowsPath;
+ }
+
+ LocalLaunchOptions localLaunchOptions = (LocalLaunchOptions)_debuggedProcess.LaunchOptions;
+
+ string windowsPath = PlatformUtilities.UnixPathToWindowsPath(origWindowsPath);
+
+ if (!LaunchCygPathAndReadResult(windowsPath, localLaunchOptions.MIDebuggerPath, convertToWindowsPath: false, out string cygwinPath))
+ {
+ return origWindowsPath;
+ }
+
+ return cygwinPath;
+ }
+
// There is an issue launching Cygwin apps that if a process is launched using a bitness mismatched console,
// process launch will fail. To avoid that, launch cygpath with its own console. This requires calling CreateProcess
// directly because the creation flags are not exposed in System.Diagnostics.Process.
//
// Return true if successful. False otherwise.
- private bool LaunchCygPathAndReadResult(string cygwinPath, string miDebuggerPath, out string windowsPath)
+ private bool LaunchCygPathAndReadResult(string inputPath, string miDebuggerPath, bool convertToWindowsPath, out string outputPath)
{
- windowsPath = "";
+ outputPath = "";
if (String.IsNullOrEmpty(miDebuggerPath))
{
@@ -108,8 +142,19 @@ private bool LaunchCygPathAndReadResult(string cygwinPath, string miDebuggerPath
const uint DETACHED_PROCESS = 0x00000008;
uint flags = DETACHED_PROCESS;
- // ex: "C:\\cygwin64\\bin\\cygpath.exe -w " + cygwinPath,
- string command = String.Concat(cygpathPath, " -w ", cygwinPath);
+ string command = string.Empty;
+ if (convertToWindowsPath)
+ {
+ // -w, --windows print Windows form of NAMEs (C:\WINNT)
+ // ex: "C:\\cygwin64\\bin\\cygpath.exe -w " + inputPath,
+ command = String.Concat(cygpathPath, " -w ", inputPath);
+ }
+ else
+ {
+ // -u, --unix (default) print Unix form of NAMEs (/cygdrive/c/winnt)
+ // ex: "C:\\cygwin64\\bin\\cygpath.exe -u " + inputPath,
+ command = String.Concat(cygpathPath, " -u ", inputPath);
+ }
if (!CreateProcess(
null,
command,
@@ -153,7 +198,7 @@ out processInfo
FileStream fs = new FileStream(stdoutRead, FileAccess.Read);
StreamReader sr = new StreamReader(fs);
- windowsPath = sr.ReadLine();
+ outputPath = sr.ReadLine();
}
finally
{
diff --git a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs
index e4f655971..5375744d9 100755
--- a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs
+++ b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs
@@ -551,6 +551,9 @@ public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token)
try
{
await this.MICommandFactory.EnableTargetAsyncOption();
+
+ await this.CheckCygwin(_launchOptions as LocalLaunchOptions);
+
List commands = await GetInitializeCommands();
_childProcessHandler?.Enable();
@@ -632,9 +635,11 @@ private async Task
> GetInitializeCommands()
commands.Add(new LaunchCommand("-gdb-set solib-absolute-prefix " + _launchOptions.AbsolutePrefixSOLibSearchPath));
}
- // On Windows ';' appears to correctly works as a path seperator and from the documentation, it is ':' on unix
- string pathEntrySeperator = _launchOptions.UseUnixSymbolPaths ? ":" : ";";
- string escapedSearchPath = string.Join(pathEntrySeperator, _launchOptions.GetSOLibSearchPath().Select(path => EscapeSymbolPath(path, ignoreSpaces: true)));
+ // On Windows ';' appears to correctly works as a path seperator and from the documentation, it is ':' on unix or cygwin envrionments
+ string pathEntrySeperator = (_launchOptions.UseUnixSymbolPaths || IsCygwin) ? ":" : ";";
+ string escapedSearchPath = string.Join(pathEntrySeperator, _launchOptions.GetSOLibSearchPath().Select(path => {
+ return EnsureProperPathSeparators(path, ignoreSpaces: true);
+ }));
if (!string.IsNullOrWhiteSpace(escapedSearchPath))
{
if (_launchOptions.DebuggerMIMode == MIMode.Gdb)
@@ -691,7 +696,7 @@ private async Task> GetInitializeCommands()
this.AddGetTargetArchitectureCommand(commands);
// Add core dump information (linux/mac does not support quotes around this path but spaces in the path do work)
- string coreDump = this.UseUnixPathSeparators ? _launchOptions.CoreDumpPath : this.EnsureProperPathSeparators(_launchOptions.CoreDumpPath);
+ string coreDump = this.UseUnixPathSeparators ? _launchOptions.CoreDumpPath : this.EnsureProperPathSeparators(_launchOptions.CoreDumpPath, true);
string coreDumpCommand = _launchOptions.DebuggerMIMode == MIMode.Lldb ? String.Concat("target create --core ", coreDump) : String.Concat("-target-select core ", coreDump);
string coreDumpDescription = String.Format(CultureInfo.CurrentCulture, ResourceStrings.LoadingCoreDumpMessage, _launchOptions.CoreDumpPath);
commands.Add(new LaunchCommand(coreDumpCommand, coreDumpDescription, ignoreFailures: false));
@@ -700,8 +705,6 @@ private async Task> GetInitializeCommands()
{
// This is an attach
- CheckCygwin(commands, localLaunchOptions);
-
if (this.MICommandFactory.Mode == MIMode.Gdb)
{
if (_launchOptions is UnixShellPortLaunchOptions)
@@ -723,11 +726,14 @@ private async Task> GetInitializeCommands()
// check for remote
string destination = localLaunchOptions?.MIDebuggerServerAddress;
+ bool useExtendedRemote = localLaunchOptions?.UseExtendedRemote ?? false;
if (!string.IsNullOrWhiteSpace(destination))
{
- commands.Add(new LaunchCommand("-target-select remote " + destination, string.Format(CultureInfo.CurrentCulture, ResourceStrings.ConnectingMessage, destination)));
+ string remoteMode = useExtendedRemote ? "extended-remote" : "remote";
+ commands.Add(new LaunchCommand($"-target-select {remoteMode} {destination}", string.Format(CultureInfo.CurrentCulture, ResourceStrings.ConnectingMessage, destination)));
}
- else // gdbserver is already attached when using LocalLaunchOptions
+ // Allow attach after connection only in extended-remote mode
+ if (useExtendedRemote || (!useExtendedRemote && string.IsNullOrWhiteSpace(destination)))
{
Action failureHandler = (string miError) =>
{
@@ -766,7 +772,8 @@ private async Task> GetInitializeCommands()
if (!string.IsNullOrWhiteSpace(_launchOptions.WorkingDirectory))
{
- string escapedDir = this.EnsureProperPathSeparators(_launchOptions.WorkingDirectory);
+ string escapedDir = this.EnsureProperPathSeparators(_launchOptions.WorkingDirectory, true);
+
commands.Add(new LaunchCommand("-environment-cd " + escapedDir));
}
@@ -779,8 +786,6 @@ private async Task> GetInitializeCommands()
commands.Add(new LaunchCommand("-gdb-set new-console on", ignoreFailures: true));
}
- CheckCygwin(commands, localLaunchOptions);
-
this.AddExecutablePathCommand(commands);
// Important: this must occur after file-exec-and-symbols but before anything else.
@@ -829,7 +834,8 @@ private async Task> GetInitializeCommands()
string destination = localLaunchOptions.MIDebuggerServerAddress;
if (!string.IsNullOrWhiteSpace(destination))
{
- commands.Add(new LaunchCommand("-target-select remote " + destination, string.Format(CultureInfo.CurrentCulture, ResourceStrings.ConnectingMessage, destination)));
+ string remoteMode = localLaunchOptions.UseExtendedRemote ? "extended-remote" : "remote";
+ commands.Add(new LaunchCommand($"-target-select {remoteMode} {destination}", string.Format(CultureInfo.CurrentCulture, ResourceStrings.ConnectingMessage, destination)));
if (localLaunchOptions.RequireHardwareBreakpoints && localLaunchOptions.HardwareBreakpointLimit > 0) {
commands.Add(new LaunchCommand(string.Format(CultureInfo.InvariantCulture, "-interpreter-exec console \"set remote hardware-breakpoint-limit {0}\"", localLaunchOptions.HardwareBreakpointLimit.ToString(CultureInfo.InvariantCulture))));
}
@@ -853,40 +859,54 @@ private async Task> GetInitializeCommands()
return commands;
}
- private void CheckCygwin(List commands, LocalLaunchOptions localLaunchOptions)
+ ///
+ /// Checks to see if we are running Cygwin or not.
+ ///
+ ///
+ ///
+ private async Task CheckCygwin(LocalLaunchOptions localLaunchOptions)
{
- // If running locally on windows, determine if gdb is running from cygwin
- if (localLaunchOptions != null && PlatformUtilities.IsWindows() && this.MICommandFactory.Mode == MIMode.Gdb)
- {
+ // Checks to see if:
+ // 1. LocalLaunch Debugging
+ // 2. On Windows
+ // 3. With GDB
+ // 4. Does not have custom commands
+ // 5. Is not Android Debugging
+ // 6. Is not Dump Debugging
+ if (localLaunchOptions != null &&
+ PlatformUtilities.IsWindows() &&
+ this.MICommandFactory.Mode == MIMode.Gdb &&
+ localLaunchOptions.CustomLaunchSetupCommands == null &&
+ localLaunchOptions.DeviceAppLauncher == null &&
+ !this.IsCoreDump)
+ {
+ string resultString = await ConsoleCmdAsync("show configuration", allowWhileRunning: false, ignoreFailures: true);
+
// mingw will not implement this command, but to be safe, also check if the results contains the string cygwin.
- LaunchCommand lc = new LaunchCommand("show configuration", null, true, null, (string resStr) =>
- {
- // Look to see if configuration has "cywgin" within a word boundry.
- // Also look for "msys" since it is a modified version of Cygwin.
- if (Regex.IsMatch(resStr, "\\bcygwin\\b|\\bmsys\\b"))
- {
- this.IsCygwin = true;
- this.CygwinFilePathMapper = new CygwinFilePathMapper(this);
- _engineTelemetry.SendWindowsRuntimeEnvironment(EngineTelemetry.WindowsRuntimeEnvironment.Cygwin);
- }
- else
- {
- this.IsMinGW = true;
- // Gdb on windows and not cygwin implies mingw
- _engineTelemetry.SendWindowsRuntimeEnvironment(EngineTelemetry.WindowsRuntimeEnvironment.MinGW);
- }
+ // Look to see if configuration has "cywgin" within a word boundry.
+ // Also look for "msys" since it is a modified version of Cygwin.
+ if (Regex.IsMatch(resultString, "\\bcygwin\\b|\\bmsys\\b"))
+ {
+ this.IsCygwin = true;
+ this.CygwinFilePathMapper = new CygwinFilePathMapper(this);
- return Task.FromResult(0);
- });
- commands.Add(lc);
+ _engineTelemetry.SendWindowsRuntimeEnvironment(EngineTelemetry.WindowsRuntimeEnvironment.Cygwin);
+ }
+ else
+ {
+ this.IsMinGW = true;
+ // Gdb on windows and not cygwin implies mingw
+ _engineTelemetry.SendWindowsRuntimeEnvironment(EngineTelemetry.WindowsRuntimeEnvironment.MinGW);
+ }
}
}
private void AddExecutablePathCommand(IList commands)
{
- string exe = this.EnsureProperPathSeparators(_launchOptions.ExePath);
- string description = string.Format(CultureInfo.CurrentCulture, ResourceStrings.LoadingSymbolMessage, _launchOptions.ExePath);
+ string exe = this.EnsureProperPathSeparators(_launchOptions.ExePath, true);
+
+ string description = string.Format(CultureInfo.CurrentCulture, ResourceStrings.LoadingSymbolMessage, exe);
Action failureHandler = (string miError) =>
{
@@ -1424,36 +1444,22 @@ internal WorkerThread WorkerThread
get { return _worker; }
}
+ private readonly char[] RemotePathSeperators = new char[] { ' ', '\'' };
+ private readonly char[] LocalPathSeperators = new char[] { ' ' };
+
///
- /// Use to ensure path separators are correct for files that exist on the target debugger's machine.
- /// If you are debugging on Windows to a remote instance of gdb or gdbserver, it will update it to Unix path separators.
+ /// Use to ensure path separators are correct for files we are setting for GDB.
+ /// If you are debugging on Windows to a remote instance of gdb or gdbserver, it will update it to Unix path separators that exist on the target debugger's machine.
+ /// If you are debugging on Windows locally, it will escape the Windows path seperator.
+ /// If you are debugging on Windows locally with Cygwin, we will update it to use unix path seperators and resolve the cygwin path.
///
- internal string EnsureProperPathSeparators(string path)
+ internal string EnsureProperPathSeparators(string path, bool isRemote = false, bool ignoreSpaces = false)
{
- if (this.UseUnixPathSeparators)
- {
- path = PlatformUtilities.WindowsPathToUnixPath(path);
- }
- else
- {
- path = path.Trim();
- path = path.Replace(@"\", @"\\");
- }
-
- if (path.IndexOfAny(new char[] { ' ', '\'' }) != -1)
+ if (IsCygwin)
{
- path = '"' + path + '"';
+ path = CygwinFilePathMapper.MapWindowsToCygwin(path);
}
- return path;
- }
-
- ///
- /// This method should be used to escape paths that are used by GDB (and NOT gdbserver) locally.
- /// Any path that gdbserver would use in remote server scenarios should use EnsureProperPathSeparators instead.
- ///
- internal string EscapeSymbolPath(string path, bool ignoreSpaces = false)
- {
- if (this.UseUnixSymbolPaths)
+ else if (this.UseUnixPathSeparators)
{
path = PlatformUtilities.WindowsPathToUnixPath(path);
}
@@ -1463,7 +1469,9 @@ internal string EscapeSymbolPath(string path, bool ignoreSpaces = false)
path = path.Replace(@"\", @"\\");
}
- if (!ignoreSpaces && path.IndexOf(' ') != -1)
+ char[] pathSeperator = isRemote ? RemotePathSeperators : LocalPathSeperators;
+
+ if (!ignoreSpaces && path.IndexOfAny(pathSeperator) != -1)
{
path = '"' + path + '"';
}
@@ -2244,7 +2252,7 @@ public bool MapCurrentSrcToCompileTimeSrc(string currentSrc, out string compiler
continue; // match didn't end at a directory separator, not actually a match
}
compilerSrc = Path.Combine(e.CompileTimePath, file); // map to the compiled location
- if (compilerSrc.IndexOf('\\') > 0)
+ if (compilerSrc.IndexOf('\\') != -1)
{
compilerSrc = PlatformUtilities.WindowsPathToUnixPath(compilerSrc); // use Unix notation for the compiled path
}
diff --git a/src/MIDebugEngine/Engine.Impl/Disassembly.cs b/src/MIDebugEngine/Engine.Impl/Disassembly.cs
index eb2d07993..f08b928ec 100644
--- a/src/MIDebugEngine/Engine.Impl/Disassembly.cs
+++ b/src/MIDebugEngine/Engine.Impl/Disassembly.cs
@@ -323,7 +323,7 @@ internal async Task> Disassemble(DebuggedProcess
{
if (file.IndexOf(' ') >= 0) // only needs escaping if filename contains a space
{
- file = process.EscapeSymbolPath(file);
+ file = process.EnsureProperPathSeparators(file);
}
string cmd = "-data-disassemble -f " + file + " -l " + line.ToString(CultureInfo.InvariantCulture) + " -n " + dwInstructions.ToString(CultureInfo.InvariantCulture) + " -- 1";
Results results = await process.CmdAsync(cmd, ResultClass.None);
diff --git a/src/MIDebugEngine/Engine.Impl/SourceLine.cs b/src/MIDebugEngine/Engine.Impl/SourceLine.cs
index 37b439018..f05464a68 100644
--- a/src/MIDebugEngine/Engine.Impl/SourceLine.cs
+++ b/src/MIDebugEngine/Engine.Impl/SourceLine.cs
@@ -92,7 +92,7 @@ internal async Task GetLinesForFile(string file)
}
private async Task LinesForFile(string file)
{
- string cmd = "-symbol-list-lines " + _process.EscapeSymbolPath(file);
+ string cmd = "-symbol-list-lines " + _process.EnsureProperPathSeparators(file);
Results results = await _process.CmdAsync(cmd, ResultClass.None);
if (results.ResultClass != ResultClass.done)
diff --git a/src/MIDebugPackage/OpenFolderSchema.json b/src/MIDebugPackage/OpenFolderSchema.json
index 4d69d7b0c..c7c60efec 100644
--- a/src/MIDebugPackage/OpenFolderSchema.json
+++ b/src/MIDebugPackage/OpenFolderSchema.json
@@ -113,6 +113,10 @@
"type": "string",
"description": "Network address of the MI-enabled debugger server to connect to. \nExample: localhost:1234."
},
+ "useExtendedRemote": {
+ "type": "boolean",
+ "description": "If true, use gdb extended-remote mode to connect to gdbserver."
+ },
"setupCommands": {
"type": "array",
"description": "One or more GDB/LLDB commands to execute in order to setup the underlying debugger. \nExample: \"setupCommands\": [ { \"text\": \"-enable-pretty-printing\", \"description\": \"Enable GDB pretty printing\", \"ignoreFailures\": true }].",
diff --git a/src/OpenDebugAD7/AD7DebugSession.cs b/src/OpenDebugAD7/AD7DebugSession.cs
index 0c145ad68..bb46637d6 100644
--- a/src/OpenDebugAD7/AD7DebugSession.cs
+++ b/src/OpenDebugAD7/AD7DebugSession.cs
@@ -51,6 +51,8 @@ internal sealed class AD7DebugSession : DebugAdapterBase, IDebugPortNotify2, IDe
private Dictionary m_functionBreakpoints;
private Dictionary m_instructionBreakpoints;
+ private Dictionary m_dataBreakpoints;
+
private List m_exceptionBreakpoints;
private readonly HandleCollection m_frameHandles;
@@ -122,6 +124,7 @@ public AD7DebugSession(Stream debugAdapterStdIn, Stream debugAdapterStdOut, List
m_breakpoints = new Dictionary>();
m_functionBreakpoints = new Dictionary();
m_instructionBreakpoints = new Dictionary();
+ m_dataBreakpoints = new Dictionary();
m_exceptionBreakpoints = new List();
m_variableManager = new VariableManager();
}
@@ -649,6 +652,7 @@ private VariablesResponse VariablesFromFrame(VariableScope vref, uint radix)
while (varEnum.Next(1, props, out nProps) == HRConstants.S_OK)
{
response.Variables.Add(m_variableManager.CreateVariable(props[0].pProperty, GetDefaultPropertyInfoFlags()));
+ m_variableManager.AddFrameVariable(frame, props[0]);
}
}
@@ -905,6 +909,7 @@ protected override void HandleInitializeRequestAsync(IRequestResponder responder)
+ {
+ if (responder.Arguments.Name == null)
+ {
+ responder.SetError(new ProtocolException("DataBreakpointInfo failed: Missing 'Name'."));
+ return;
+ }
+
+ DataBreakpointInfoResponse response = new DataBreakpointInfoResponse();
+
+ try
+ {
+ string name = responder.Arguments.Name;
+ IDebugProperty2 property = null;
+ string errorMessage = null;
+ ErrorBuilder eb = new ErrorBuilder(() => AD7Resources.Error_DataBreakpointInfoFail);
+ int hr = HRConstants.S_OK;
+
+ // Did our request come with a parent object?
+ if (responder.Arguments.VariablesReference.HasValue)
+ {
+ int variableReference = responder.Arguments.VariablesReference.Value;
+ if (!m_variableManager.TryGet(variableReference, out object variableObj))
+ {
+ responder.SetError(new ProtocolException("DataBreakpointInfo failed: Invalid 'VariableReference'."));
+ return;
+ }
+
+ if (variableObj is VariableScope varScope)
+ {
+ // We have a scope object. We can grab a frame for evaluation from this
+ IDebugStackFrame2 frame = varScope.StackFrame;
+ m_variableManager.TryGetProperty((frame, name), out property);
+ }
+ else if (variableObj is VariableEvaluationData varEvalData)
+ {
+ // We have a variable parent object.
+ IDebugProperty2 parentProperty = varEvalData.DebugProperty;
+ m_variableManager.TryGetProperty((variableReference, name), out property);
+ }
+ }
+ else
+ {
+ // We don't have a parent object. Default to using top stack frame
+ if (m_frameHandles == null || !m_frameHandles.TryGetFirst(out IDebugStackFrame2 frame))
+ {
+ response.Description = string.Format(CultureInfo.CurrentCulture, AD7Resources.Error_DataBreakpointInfoFail, AD7Resources.Error_NoParentObject);
+ }
+ else
+ {
+ m_variableManager.TryGetProperty((frame, name), out property);
+ }
+ }
+
+ // If we've found a valid child property to set the data breakpoint on, get the address/size and return the DataId.
+ if (property != null && property is IDebugProperty160 property160)
+ {
+ hr = property160.GetDataBreakpointInfo160(out string address, out uint size, out string displayName, out errorMessage);
+ eb.CheckHR(hr);
+ if (!string.IsNullOrEmpty(errorMessage))
+ {
+ response.Description = string.Format(CultureInfo.CurrentCulture, AD7Resources.Error_DataBreakpointInfoFail, errorMessage);
+ }
+ else
+ {
+ // If we succeeded, return response that we can set a data bp.
+ string sSize = size.ToString(CultureInfo.InvariantCulture);
+ response.DataId = $"{address},{sSize}";
+ response.Description = string.Format(CultureInfo.CurrentCulture, AD7Resources.DataBreakpointDisplayString, displayName, sSize);
+ response.AccessTypes = new List() { DataBreakpointAccessType.Write };
+ }
+ }
+ else if (response.Description == null)
+ {
+ response.Description = string.Format(CultureInfo.CurrentCulture, AD7Resources.Error_DataBreakpointInfoFail, AD7Resources.Error_ChildPropertyNotFound);
+ }
+ }
+ catch (Exception ex)
+ {
+ if (ex is AD7Exception ad7ex)
+ response.Description = ad7ex.Message;
+ else
+ response.Description = string.Format(CultureInfo.CurrentCulture, AD7Resources.Error_DataBreakpointInfoFail, "");
+ }
+ finally
+ {
+ responder.SetResponse(response);
+ }
+ }
+
+ protected override void HandleSetDataBreakpointsRequestAsync(IRequestResponder responder)
+ {
+ if (responder.Arguments.Breakpoints == null)
+ {
+ responder.SetError(new ProtocolException("SetDataBreakpointRequest failed: Missing 'breakpoints'."));
+ return;
+ }
+
+ List breakpoints = responder.Arguments.Breakpoints;
+ SetDataBreakpointsResponse response = new SetDataBreakpointsResponse();
+ Dictionary newBreakpoints = new Dictionary();
+ ErrorBuilder eb = new ErrorBuilder(() => AD7Resources.Error_DataBreakpointInfoFail);
+
+ try
+ {
+ foreach (KeyValuePair b in m_dataBreakpoints)
+ {
+ if (breakpoints.Find((p) => p.DataId == b.Key) != null)
+ {
+ newBreakpoints[b.Key] = b.Value; // breakpoint still in new list
+ }
+ else
+ {
+ b.Value.Delete(); // not in new list so delete it
+ }
+ }
+
+ foreach (DataBreakpoint b in breakpoints)
+ {
+ if (m_dataBreakpoints.ContainsKey(b.DataId))
+ { // already created
+ IDebugBreakpointRequest2 breakpointRequest;
+ if (m_dataBreakpoints[b.DataId].GetBreakpointRequest(out breakpointRequest) == 0 &&
+ breakpointRequest is AD7BreakPointRequest ad7BPRequest)
+ {
+ // Check to see if this breakpoint has a condition that has changed.
+ if (!StringComparer.Ordinal.Equals(ad7BPRequest.Condition, b.Condition))
+ {
+ // Condition has been modified. Delete breakpoint so it will be recreated with the updated condition.
+ var toRemove = m_dataBreakpoints[b.DataId];
+ toRemove.Delete();
+ m_dataBreakpoints.Remove(b.DataId);
+ }
+ else
+ {
+ if (ad7BPRequest.BindResult != null)
+ {
+ response.Breakpoints.Add(ad7BPRequest.BindResult);
+ }
+ else
+ {
+ response.Breakpoints.Add(new Breakpoint()
+ {
+ Id = (int)ad7BPRequest.Id,
+ Verified = false,
+ Line = 0
+ });
+
+ }
+ continue;
+ }
+ }
+ }
+
+ // Bind the new data bp
+ if (!m_dataBreakpoints.ContainsKey(b.DataId))
+ {
+ int hr = HRConstants.S_OK;
+
+ int lastCommaIdx = b.DataId.LastIndexOf(',');
+ if (lastCommaIdx == -1)
+ {
+ eb.ThrowHR(HRConstants.E_FAIL);
+ }
+
+ // format is "{dataId},{size}" where dataId = "{address},{displayName}"
+ string strSize = b.DataId.Substring(lastCommaIdx + 1);
+ string address = b.DataId.Substring(0, lastCommaIdx);
+ uint size = uint.Parse(strSize, CultureInfo.InvariantCulture);
+
+ AD7BreakPointRequest pBPRequest = new AD7BreakPointRequest(address, size);
+ hr = m_engine.CreatePendingBreakpoint(pBPRequest, out IDebugPendingBreakpoint2 pendingBp);
+ eb.CheckHR(hr);
+
+ hr = pendingBp.Bind();
+ if (hr == HRConstants.S_OK)
+ {
+ newBreakpoints[b.DataId] = pendingBp;
+ }
+ response.Breakpoints.Add(pBPRequest.BindResult);
+ }
+ }
+ responder.SetResponse(response);
+ }
+ catch (Exception ex)
+ {
+ responder.SetError(new ProtocolException(ex.Message));
+ }
+ finally
+ {
+ m_dataBreakpoints = newBreakpoints;
+ }
+ }
+
+
protected override void HandleSetExceptionBreakpointsRequestAsync(IRequestResponder responder)
{
HashSet activeExceptionCategories = new HashSet();
@@ -3310,7 +3512,7 @@ public void HandleIDebugBreakpointErrorEvent2(IDebugEngine2 pEngine, IDebugProce
};
}
}
- else
+ else if (ad7BPRequest.FunctionPosition != null)
{
bp = new Breakpoint()
{
@@ -3324,6 +3526,18 @@ public void HandleIDebugBreakpointErrorEvent2(IDebugEngine2 pEngine, IDebugProce
string outputMsg = string.Format(CultureInfo.CurrentCulture, AD7Resources.Error_FunctionBreakpoint, ad7BPRequest.FunctionPosition.Name, errorMsg);
m_logger.WriteLine(LoggingCategory.DebuggerError, outputMsg);
}
+ else // data bp
+ {
+ string outputMsg = string.Format(CultureInfo.CurrentCulture, AD7Resources.Error_InvalidDataBreakpoint, errorMsg);
+ bp = new Breakpoint()
+ {
+ Verified = false,
+ Id = (int)ad7BPRequest.Id,
+ Line = 0,
+ Message = outputMsg
+ };
+ m_logger.WriteLine(LoggingCategory.DebuggerError, outputMsg);
+ }
ad7BPRequest.BindResult = bp;
Protocol.SendEvent(new BreakpointEvent(BreakpointEvent.ReasonValue.Changed, bp));
diff --git a/src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs b/src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs
index 63f70afa0..2843beb40 100644
--- a/src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs
+++ b/src/OpenDebugAD7/AD7Impl/AD7BreakPointRequest.cs
@@ -25,13 +25,16 @@ static public uint GetNextBreakpointId()
public IDebugMemoryContext2 MemoryContext { get; private set; }
+ public string DataAddress { get; private set; }
+ public uint DataSize { get; private set; }
+
// Used for Releasing the MemoryContext.
// Caller of AD7BreakPointRequest(MemoryContext) is required to
// release it with HostMarshal.ReleaseCodeContextId
public IntPtr MemoryContextIntPtr { get; private set; }
// Unique identifier for breakpoint when communicating with VSCode
- public uint Id { get; private set; }
+ public uint Id { get; } = GetNextBreakpointId();
// Bind result from IDebugBreakpointErrorEvent2 or IDebugBreakpointBoundEvent2
public Breakpoint BindResult { get; set; }
@@ -40,7 +43,6 @@ public AD7BreakPointRequest(SessionConfiguration config, string path, int line,
{
DocumentPosition = new AD7DocumentPosition(config, path, line);
Condition = condition;
- Id = GetNextBreakpointId();
}
public AD7BreakPointRequest(string functionName)
@@ -48,6 +50,13 @@ public AD7BreakPointRequest(string functionName)
FunctionPosition = new AD7FunctionPosition(functionName);
}
+ // Data breakpoint constructor
+ public AD7BreakPointRequest(string address, uint size)
+ {
+ DataAddress = address;
+ DataSize = size;
+ }
+
public AD7BreakPointRequest(IDebugMemoryContext2 memoryContext)
{
MemoryContext = memoryContext;
@@ -67,7 +76,10 @@ public int GetLocationType(enum_BP_LOCATION_TYPE[] pBPLocationType)
{
pBPLocationType[0] = enum_BP_LOCATION_TYPE.BPLT_CODE_CONTEXT;
}
-
+ else if (DataAddress != null)
+ {
+ pBPLocationType[0] = enum_BP_LOCATION_TYPE.BPLT_DATA_STRING;
+ }
return 0;
}
@@ -92,7 +104,12 @@ public int GetRequestInfo(enum_BPREQI_FIELDS dwFields, BP_REQUEST_INFO[] pBPRequ
pBPRequestInfo[0].bpLocation.bpLocationType = (uint)enum_BP_LOCATION_TYPE.BPLT_CODE_CONTEXT;
MemoryContextIntPtr = HostMarshal.RegisterCodeContext(MemoryContext as IDebugCodeContext2);
pBPRequestInfo[0].bpLocation.unionmember1 = MemoryContextIntPtr;
-
+ }
+ else if (DataAddress != null)
+ {
+ pBPRequestInfo[0].bpLocation.bpLocationType = (uint)enum_BP_LOCATION_TYPE.BPLT_DATA_STRING;
+ pBPRequestInfo[0].bpLocation.unionmember3 = HostMarshal.GetIntPtrForDataBreakpointAddress(DataAddress);
+ pBPRequestInfo[0].bpLocation.unionmember4 = (IntPtr)DataSize;
}
}
if ((dwFields & enum_BPREQI_FIELDS.BPREQI_CONDITION) != 0 && !string.IsNullOrWhiteSpace(Condition))
diff --git a/src/OpenDebugAD7/AD7Resources.Designer.cs b/src/OpenDebugAD7/AD7Resources.Designer.cs
index 6ef7590b3..516b91680 100644
--- a/src/OpenDebugAD7/AD7Resources.Designer.cs
+++ b/src/OpenDebugAD7/AD7Resources.Designer.cs
@@ -60,6 +60,15 @@ internal AD7Resources() {
}
}
+ ///
+ /// Looks up a localized string similar to When '{0}' changes ({1} bytes).
+ ///
+ internal static string DataBreakpointDisplayString {
+ get {
+ return ResourceManager.GetString("DataBreakpointDisplayString", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Execute debugger commands using "-exec <command>", for example "-exec info registers" will list registers in use (when GDB is the debugger).
///
@@ -78,6 +87,15 @@ internal static string DebuggerDisconnectMessage {
}
}
+ ///
+ /// Looks up a localized string similar to Unable to find child property..
+ ///
+ internal static string Error_ChildPropertyNotFound {
+ get {
+ return ResourceManager.GetString("Error_ChildPropertyNotFound", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Condition "{0}" : {1}.
///
@@ -107,6 +125,15 @@ internal static string Error_CorruptingException {
}
}
+ ///
+ /// Looks up a localized string similar to Unable to get info for data breakpoint. {0}.
+ ///
+ internal static string Error_DataBreakpointInfoFail {
+ get {
+ return ResourceManager.GetString("Error_DataBreakpointInfoFail", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Exception occurred: '{0}'.
///
@@ -215,6 +242,15 @@ internal static string Error_Invalid_Exception_Condition {
}
}
+ ///
+ /// Looks up a localized string similar to Unable to set data breakpoint: {0}.
+ ///
+ internal static string Error_InvalidDataBreakpoint {
+ get {
+ return ResourceManager.GetString("Error_InvalidDataBreakpoint", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to DNX runtime process exited unexpectedly with error code {0}..
///
@@ -244,6 +280,15 @@ internal static string Error_MissingOutParam {
}
}
+ ///
+ /// Looks up a localized string similar to Unable to get parent object: No scope or variable found..
+ ///
+ internal static string Error_NoParentObject {
+ get {
+ return ResourceManager.GetString("Error_NoParentObject", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Set next statement is not supported by the current debugger..
///
diff --git a/src/OpenDebugAD7/AD7Resources.resx b/src/OpenDebugAD7/AD7Resources.resx
index f2f020d8a..443ed33ee 100644
--- a/src/OpenDebugAD7/AD7Resources.resx
+++ b/src/OpenDebugAD7/AD7Resources.resx
@@ -312,4 +312,23 @@
ERROR: '{0}' is an invalid exception condition. See https://aka.ms/VSCode-Cpp-ExceptionSettings for more information.
{0} is the exception condition
+
+ Unable to get info for data breakpoint. {0}
+ {0} is the reason (could be exception condition)
+
+
+ Unable to get parent object: No scope or variable found.
+ {0} is a number, {1} is the property name
+
+
+ When '{0}' changes ({1} bytes)
+ {0} is the variable name, {1} is a number (size of the variable)
+
+
+ Unable to find child property.
+
+
+ Unable to set data breakpoint: {0}
+ {0} is the reason
+
\ No newline at end of file
diff --git a/src/OpenDebugAD7/VariableManager.cs b/src/OpenDebugAD7/VariableManager.cs
index def25f74d..8f7d37e53 100644
--- a/src/OpenDebugAD7/VariableManager.cs
+++ b/src/OpenDebugAD7/VariableManager.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
+using System.Collections.Generic;
using Microsoft.DebugEngineHost.VSCode;
using Microsoft.VisualStudio.Debugger.Interop;
using Microsoft.VisualStudio.Shared.VSCodeDebugProtocol.Messages;
@@ -31,14 +32,24 @@ internal class VariableManager
// NOTE: The value being stored can be a VariableScope or a VariableEvaluationData
private readonly HandleCollection