From 73d569db5fc32003b8a9acf622d58ff22935f2cf Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Wed, 31 May 2023 00:10:18 +0100 Subject: [PATCH] [#1349] Always use `--simple-values` in newer versions of GDB. (#1400) * [#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. * fixup! [#1349] Always use `--simple-values` in newer versions of GDB. --- .../CommandFactories/MICommandFactory.cs | 18 +++++++++++++++ src/MICore/CommandFactories/gdb.cs | 12 ++++++++++ .../Engine.Impl/DebuggedProcess.cs | 23 +++++++++++++++++-- 3 files changed, 51 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..6b9632386 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 = null; public DebuggedProcess(bool bLaunched, LaunchOptions launchOptions, ISampleEngineCallback callback, WorkerThread worker, BreakpointManager bpman, AD7Engine engine, HostConfigurationStore configStore, HostWaitLoop waitLoop = null) : base(launchOptions, engine.Logger) { @@ -1985,8 +1986,26 @@ 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); + 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(); foreach (var f in frames)