================
@@ -14,298 +14,312 @@
#include "Protocol/ProtocolTypes.h"
#include "ProtocolUtils.h"
#include "SBAPIExtras.h"
+#include "lldb/API/SBDeclaration.h"
#include "lldb/API/SBFrame.h"
-#include "lldb/API/SBProcess.h"
#include "lldb/API/SBValue.h"
#include "lldb/API/SBValueList.h"
#include "llvm/ADT/Sequence.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstdint>
#include <optional>
#include <vector>
+using namespace llvm;
using namespace lldb_dap;
using namespace lldb_dap::protocol;
-namespace lldb_dap {
+namespace {
-protocol::Scope CreateScope(ScopeKind kind, var_ref_t variablesReference,
- bool expensive) {
- protocol::Scope scope;
- scope.variablesReference = variablesReference;
- scope.expensive = expensive;
+bool HasInnerVarref(lldb::SBValue &v) {
+ return v.MightHaveChildren() || ValuePointsToCode(v) ||
+ v.GetDeclaration().IsValid();
+}
- // TODO: Support "arguments" and "return value" scope.
- // At the moment lldb-dap includes the arguments and return_value into the
- // "locals" scope.
- // VS Code only expands the first non-expensive scope. This causes friction
- // if we add the arguments above the local scope, as the locals scope will
not
- // be expanded if we enter a function with arguments. It becomes more
- // annoying when the scope has arguments, return_value and locals.
- switch (kind) {
- case eScopeKindLocals:
- scope.presentationHint = protocol::Scope::eScopePresentationHintLocals;
- scope.name = "Locals";
- break;
- case eScopeKindGlobals:
- scope.name = "Globals";
- break;
- case eScopeKindRegisters:
- scope.presentationHint = protocol::Scope::eScopePresentationHintRegisters;
- scope.name = "Registers";
- break;
+template <typename T> StringMap<uint32_t> distinct_names(T &container) {
+ StringMap<uint32_t> variable_name_counts;
+ for (auto variable : container) {
+ if (!variable.IsValid())
+ break;
+ variable_name_counts[GetNonNullVariableName(variable)]++;
}
-
- return scope;
+ return variable_name_counts;
}
-std::vector<Variable>
-ScopeStore::GetVariables(VariableReferenceStorage &storage,
- const Configuration &config,
- const VariablesArguments &args) {
- LoadVariables();
- if (m_kind == lldb_dap::eScopeKindRegisters)
- SetRegistersFormat();
-
- const bool format_hex = args.format ? args.format->hex : false;
+template <typename T>
+std::vector<Variable> make_variables(VariableReferenceStorage &storage,
+ const Configuration &config,
+ const VariablesArguments &args,
+ T &container, bool is_permanent) {
std::vector<Variable> variables;
- if (m_kind == eScopeKindLocals)
- AddReturnValue(storage, config, variables, format_hex);
-
- const uint64_t count = args.count;
- const uint32_t start_idx = 0;
- const uint32_t num_children = m_children.GetSize();
- const uint32_t end_idx = start_idx + ((count == 0) ? num_children : count);
// We first find out which variable names are duplicated.
- std::map<llvm::StringRef, uint32_t> variable_name_counts;
- for (auto i = start_idx; i < end_idx; ++i) {
- lldb::SBValue variable = m_children.GetValueAtIndex(i);
- if (!variable.IsValid())
- break;
- variable_name_counts[GetNonNullVariableName(variable)]++;
- }
+ StringMap<uint32_t> variable_name_counts = distinct_names(container);
- // Now we construct the result with unique display variable names.
- for (auto i = start_idx; i < end_idx; ++i) {
- lldb::SBValue variable = m_children.GetValueAtIndex(i);
+ const bool format_hex = args.format ? args.format->hex : false;
+ auto start_it = begin(container) + args.start;
+ auto end_it = args.count == 0 ? end(container) : start_it + args.count;
+ // Now we construct the result with unique display variable names.
+ for (; start_it != end_it; start_it++) {
+ lldb::SBValue variable = *start_it;
if (!variable.IsValid())
break;
- const var_ref_t frame_var_ref =
- storage.InsertVariable(variable, /*is_permanent=*/false);
- if (LLVM_UNLIKELY(frame_var_ref.AsUInt32() >=
+ const var_ref_t var_ref =
+ HasInnerVarref(variable)
+ ? storage.Insert(variable, /*is_permanent=*/is_permanent)
+ : var_ref_t(var_ref_t::k_no_child);
+ if (LLVM_UNLIKELY(var_ref.AsUInt32() >=
var_ref_t::k_variables_reference_threshold)) {
DAP_LOG(storage.log,
- "warning: scopes variablesReference threshold reached. "
+ "warning: variablesReference threshold reached. "
"current: {} threshold: {}, maximum {}.",
- frame_var_ref.AsUInt32(),
- var_ref_t::k_variables_reference_threshold,
+ var_ref.AsUInt32(), var_ref_t::k_variables_reference_threshold,
var_ref_t::k_max_variables_references);
+ break;
}
- if (LLVM_UNLIKELY(frame_var_ref.Kind() == eReferenceKindInvalid))
+ if (LLVM_UNLIKELY(var_ref.Kind() == eReferenceKindInvalid))
break;
variables.emplace_back(CreateVariable(
- variable, frame_var_ref, format_hex,
config.enableAutoVariableSummaries,
+ variable, var_ref, format_hex, config.enableAutoVariableSummaries,
config.enableSyntheticChildDebugging,
variable_name_counts[GetNonNullVariableName(variable)] > 1));
}
+
return variables;
}
-lldb::SBValue ScopeStore::FindVariable(llvm::StringRef name) {
- LoadVariables();
-
- lldb::SBValue variable;
- const bool is_name_duplicated = name.contains(" @");
- // variablesReference is one of our scopes, not an actual variable it is
- // asking for a variable in locals or globals or registers.
- const uint32_t end_idx = m_children.GetSize();
- // Searching backward so that we choose the variable in closest scope
- // among variables of the same name.
- for (const uint32_t i : llvm::reverse(llvm::seq<uint32_t>(0, end_idx))) {
- lldb::SBValue curr_variable = m_children.GetValueAtIndex(i);
- std::string variable_name =
- CreateUniqueVariableNameForDisplay(curr_variable, is_name_duplicated);
- if (variable_name == name) {
- variable = curr_variable;
- break;
+/// A Variable store for fetching variables within a specific scope (locals,
+/// globals, or registers) for a given stack frame.
+class ScopeStore final : public VariableStore {
+public:
+ explicit ScopeStore(ScopeKind kind, const lldb::SBFrame &frame)
+ : m_frame(frame), m_kind(kind) {}
+
+ std::vector<Variable> GetVariables(VariableReferenceStorage &storage,
+ const Configuration &config,
+ const VariablesArguments &args) override {
+ LoadVariables();
+ if (m_children.GetSize() == 0) {
+ // Check for an error in the SBValueList that might explain why we don't
+ // have locals. If we have an error display it as the sole value in the
+ // the locals.
+ // "error" owns the error string so we must keep it alive as long as we
+ // want to use the returns "const char *".
+ lldb::SBError error = m_children.GetError();
+ if (const char *var_err = error.GetCString()) {
+ // Create a fake variable named "<error>" to explain why variables were
+ // not available. This new error will help let users know when there
+ // was a problem that kept variables from being available for display
+ // and allow users to fix this issue instead of seeing no variables.
+ // The errors are only set when there is a problem that the user could
+ // fix, so no error will show up when you have no debug info, only
+ // when we do have debug info and something that is fixable can be
+ // done.
+ Variable err_var;
+ err_var.name = "<error>";
+ err_var.type = "const char *";
+ err_var.value = var_err;
+ return {err_var};
+ }
----------------
ashgti wrote:
Updated to return an error which shows up to the user
https://github.com/llvm/llvm-project/pull/183176
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits