From 739e88d92caca7c25b00eaf33132960ad1f7beac Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 11 Nov 2022 10:10:52 +0000 Subject: [PATCH 1/2] [#1349] Always use `--simple-values` in newer versions of GDB. In newer versions of GDB, the `--simple-values` option to the `-stack-list-arguments`, `-stack-list-locals` and `-stack-list-variables` commands no longer prints the value for references to compound types. This improves the performance of these commands when the stack has references to large data structures. When these versions of GDB are available, take advantage by using `--simple-values` in `DebuggedProcess.GetParameterInfoOnly` to fetch names and types in a single `-stack-list-arguments` command. This is faster than the old approach of using `--no-values` followed with `-var-create` and `-var-delete` for each parameter to get the type. The new method `MICommandFactory.SupportsSimpleValuesExcludesRefTypes` determines if the debugger supports the improved behaviour of the `--simple-values` option, by executing the `-list-features` command and checking for the `"simple-values-ref-types"` feature in the output. We cache the result on the `DebuggedProcess` object as the set of supported features does not change during the lifetime of the debug session. --- .../CommandFactories/MICommandFactory.cs | 18 ++++++++++++++++++ src/MICore/CommandFactories/gdb.cs | 12 ++++++++++++ .../Engine.Impl/DebuggedProcess.cs | 13 +++++++++++-- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/MICore/CommandFactories/MICommandFactory.cs b/src/MICore/CommandFactories/MICommandFactory.cs index eb2e22773..700ddd46f 100644 --- a/src/MICore/CommandFactories/MICommandFactory.cs +++ b/src/MICore/CommandFactories/MICommandFactory.cs @@ -711,6 +711,24 @@ public virtual bool SupportsBreakpointChecksums() { return false; } + + /// + /// Get the set of features supported by the underlying debugger. + /// + public virtual Task> GetFeatures() + { + return Task.FromResult(new HashSet()); + } + + /// + /// True if the underlying debugger excludes the printing of references to + /// compound types when PrintValue.SimpleValues is used as an argument to + /// StackListLocals(), StackListArguments() and StackListVariables(). + /// + public virtual Task SupportsSimpleValuesExcludesRefTypes() + { + return Task.FromResult(false); + } #endregion } } diff --git a/src/MICore/CommandFactories/gdb.cs b/src/MICore/CommandFactories/gdb.cs index 65246bbfd..636a8a275 100644 --- a/src/MICore/CommandFactories/gdb.cs +++ b/src/MICore/CommandFactories/gdb.cs @@ -198,6 +198,18 @@ public override async Task EnableTargetAsyncOption() } } + public override async Task> GetFeatures() + { + Results results = await _debugger.CmdAsync("-list-features", ResultClass.done); + return new HashSet(results.Find("features").AsStrings); + } + + public override async Task SupportsSimpleValuesExcludesRefTypes() + { + HashSet features = await GetFeatures(); + return features.Contains("simple-values-ref-types"); + } + public override async Task Terminate() { // Although the mi documentation states that the correct command to terminate is -exec-abort diff --git a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs index 538bef49a..701a6b2e7 100755 --- a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs +++ b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs @@ -52,6 +52,7 @@ internal class DebuggedProcess : MICore.Debugger private IProcessSequence _childProcessHandler; private bool _deleteEntryPointBreakpoint; private string _entryPointBreakpoint = string.Empty; + private bool _simpleValuesExcludesRefTypes = false; public DebuggedProcess(bool bLaunched, LaunchOptions launchOptions, ISampleEngineCallback callback, WorkerThread worker, BreakpointManager bpman, AD7Engine engine, HostConfigurationStore configStore, HostWaitLoop waitLoop = null) : base(launchOptions, engine.Logger) { @@ -550,6 +551,8 @@ public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token) try { + _simpleValuesExcludesRefTypes = await this.MICommandFactory.SupportsSimpleValuesExcludesRefTypes(); + await this.MICommandFactory.EnableTargetAsyncOption(); await this.CheckCygwin(_launchOptions as LocalLaunchOptions); @@ -1985,8 +1988,14 @@ public async Task> GetParameterInfoOnly(AD7Threa //NOTE: eval is not called public async Task> GetParameterInfoOnly(AD7Thread thread, bool values, bool types, uint low, uint high) { - // If values are requested, request simple values, otherwise we'll use -var-create to get the type of argument it is. - var frames = await MICommandFactory.StackListArguments(values ? PrintValue.SimpleValues : PrintValue.NoValues, thread.Id, low, high); + // If SimpleValues excludes printing values for references to compound types, + // use SimpleValues (even if values are not requested) as it gets types too. + // Otherwise, if values are requested, use SimpleValues, but if not, the + // potential performance penalty of fetching values for references to compound + // types is too high, so use NoValues and follow up with -var-create to get + // the types. + PrintValue printValue = (_simpleValuesExcludesRefTypes || values) ? PrintValue.SimpleValues : PrintValue.NoValues; + var frames = await MICommandFactory.StackListArguments(printValue, thread.Id, low, high); List parameters = new List(); foreach (var f in frames) From 550bcbcca25918cbb94f0ff70874c3c9874b3750 Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Fri, 26 May 2023 11:29:10 +0100 Subject: [PATCH 2/2] fixup! [#1349] Always use `--simple-values` in newer versions of GDB. --- .../Engine.Impl/DebuggedProcess.cs | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs index 701a6b2e7..6b9632386 100755 --- a/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs +++ b/src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs @@ -52,7 +52,7 @@ internal class DebuggedProcess : MICore.Debugger private IProcessSequence _childProcessHandler; private bool _deleteEntryPointBreakpoint; private string _entryPointBreakpoint = string.Empty; - private bool _simpleValuesExcludesRefTypes = false; + private bool? _simpleValuesExcludesRefTypes = null; public DebuggedProcess(bool bLaunched, LaunchOptions launchOptions, ISampleEngineCallback callback, WorkerThread worker, BreakpointManager bpman, AD7Engine engine, HostConfigurationStore configStore, HostWaitLoop waitLoop = null) : base(launchOptions, engine.Logger) { @@ -551,8 +551,6 @@ public async Task Initialize(HostWaitLoop waitLoop, CancellationToken token) try { - _simpleValuesExcludesRefTypes = await this.MICommandFactory.SupportsSimpleValuesExcludesRefTypes(); - await this.MICommandFactory.EnableTargetAsyncOption(); await this.CheckCygwin(_launchOptions as LocalLaunchOptions); @@ -1988,13 +1986,25 @@ public async Task> GetParameterInfoOnly(AD7Threa //NOTE: eval is not called public async Task> GetParameterInfoOnly(AD7Thread thread, bool values, bool types, uint low, uint high) { - // If SimpleValues excludes printing values for references to compound types, - // use SimpleValues (even if values are not requested) as it gets types too. - // Otherwise, if values are requested, use SimpleValues, but if not, the - // potential performance penalty of fetching values for references to compound - // types is too high, so use NoValues and follow up with -var-create to get - // the types. - PrintValue printValue = (_simpleValuesExcludesRefTypes || values) ? PrintValue.SimpleValues : PrintValue.NoValues; + PrintValue printValue = values ? PrintValue.SimpleValues : PrintValue.NoValues; + if (types && !values) + { + // We want types but not values. There is no PrintValue option for this, but if + // SimpleValues excludes printing values for references to compound types, then + // the fastest approach is to use SimpleValues (and ignore the values). + // Otherwise, the potential performance penalty of fetching values for + // references to compound types is too high, so use NoValues and follow up with + // -var-create to get the types. + if (!_simpleValuesExcludesRefTypes.HasValue) + { + _simpleValuesExcludesRefTypes = await this.MICommandFactory.SupportsSimpleValuesExcludesRefTypes(); + } + if (_simpleValuesExcludesRefTypes.Value) + { + printValue = PrintValue.SimpleValues; + } + } + var frames = await MICommandFactory.StackListArguments(printValue, thread.Id, low, high); List parameters = new List();