https://github.com/Anthony-Eid updated 
https://github.com/llvm/llvm-project/pull/124232

>From e741fc75ccb6e2a725b3b26dd4c503cdea6c5fbb Mon Sep 17 00:00:00 2001
From: Anthony Eid <he...@anthonyeid.me>
Date: Fri, 24 Jan 2025 00:43:39 -0500
Subject: [PATCH 1/2] Stop using replicated variable ids

---
 lldb/tools/lldb-dap/DAP.cpp         | 28 ++++++++++++---
 lldb/tools/lldb-dap/DAP.h           | 15 ++++++--
 lldb/tools/lldb-dap/JSONUtils.cpp   |  6 ++--
 lldb/tools/lldb-dap/JSONUtils.h     |  3 +-
 lldb/tools/lldb-dap/ProgressEvent.h |  5 +++
 lldb/tools/lldb-dap/lldb-dap.cpp    | 54 ++++++++++++++++++-----------
 6 files changed, 80 insertions(+), 31 deletions(-)

diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 35250d9eef608a..0836fbf9f32dd6 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -8,6 +8,7 @@
 
 #include <chrono>
 #include <cstdarg>
+#include <cstdint>
 #include <fstream>
 #include <mutex>
 
@@ -137,6 +138,15 @@ void DAP::PopulateExceptionBreakpoints() {
   });
 }
 
+std::optional<ScopeKind> DAP::ScopeKind(const int64_t variablesReference) {
+  auto iter = scope_kinds.find(variablesReference);
+  if (iter != scope_kinds.end()) {
+    return iter->second;
+  }
+
+  return std::nullopt;
+}
+
 ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const std::string &filter) {
   // PopulateExceptionBreakpoints() is called after g_dap.debugger is created
   // in a request-initialize.
@@ -476,12 +486,22 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object 
&arguments) {
 
 llvm::json::Value DAP::CreateTopLevelScopes() {
   llvm::json::Array scopes;
-  scopes.emplace_back(
-      CreateScope("Locals", VARREF_LOCALS, variables.locals.GetSize(), false));
-  scopes.emplace_back(CreateScope("Globals", VARREF_GLOBALS,
+
+  scopes.emplace_back(CreateScope("Locals", variables.next_temporary_var_ref,
+                                  ScopeKind::Locals, 
variables.locals.GetSize(),
+                                  false));
+  scope_kinds[variables.next_temporary_var_ref++] = ScopeKind::Locals;
+
+  scopes.emplace_back(CreateScope("Globals", variables.next_temporary_var_ref,
+                                  ScopeKind::Globals,
                                   variables.globals.GetSize(), false));
-  scopes.emplace_back(CreateScope("Registers", VARREF_REGS,
+  scope_kinds[variables.next_temporary_var_ref++] = ScopeKind::Globals;
+
+  scopes.emplace_back(CreateScope("Registers", 
variables.next_temporary_var_ref,
+                                  ScopeKind::Registers,
                                   variables.registers.GetSize(), false));
+  scope_kinds[variables.next_temporary_var_ref++] = ScopeKind::Registers;
+
   return llvm::json::Value(std::move(scopes));
 }
 
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index ae496236f13369..68399e2e0410c7 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -13,6 +13,7 @@
 #include <iosfwd>
 #include <map>
 #include <optional>
+#include <set>
 #include <thread>
 
 #include "llvm/ADT/DenseMap.h"
@@ -39,6 +40,7 @@
 #include "InstructionBreakpoint.h"
 #include "ProgressEvent.h"
 #include "SourceBreakpoint.h"
+#include "lldb/API/SBValueList.h"
 
 #define VARREF_LOCALS (int64_t)1
 #define VARREF_GLOBALS (int64_t)2
@@ -86,6 +88,8 @@ struct Variables {
   int64_t next_temporary_var_ref{VARREF_FIRST_VAR_IDX};
   int64_t next_permanent_var_ref{PermanentVariableStartIndex};
 
+  std::set<uint32_t> added_frames;
+
   /// Variables that are alive in this stop state.
   /// Will be cleared when debuggee resumes.
   llvm::DenseMap<int64_t, lldb::SBValue> referenced_variables;
@@ -117,25 +121,27 @@ struct Variables {
 
 struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface {
   DAP &dap;
-  explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {};
+  explicit StartDebuggingRequestHandler(DAP &d) : dap(d){};
   bool DoExecute(lldb::SBDebugger debugger, char **command,
                  lldb::SBCommandReturnObject &result) override;
 };
 
 struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface {
   DAP &dap;
-  explicit ReplModeRequestHandler(DAP &d) : dap(d) {};
+  explicit ReplModeRequestHandler(DAP &d) : dap(d){};
   bool DoExecute(lldb::SBDebugger debugger, char **command,
                  lldb::SBCommandReturnObject &result) override;
 };
 
 struct SendEventRequestHandler : public lldb::SBCommandPluginInterface {
   DAP &dap;
-  explicit SendEventRequestHandler(DAP &d) : dap(d) {};
+  explicit SendEventRequestHandler(DAP &d) : dap(d){};
   bool DoExecute(lldb::SBDebugger debugger, char **command,
                  lldb::SBCommandReturnObject &result) override;
 };
 
+enum ScopeKind { Locals, Globals, Registers };
+
 struct DAP {
   llvm::StringRef debug_adaptor_path;
   InputStream input;
@@ -159,6 +165,7 @@ struct DAP {
   std::vector<std::string> exit_commands;
   std::vector<std::string> stop_commands;
   std::vector<std::string> terminate_commands;
+  std::map<int, ScopeKind> scope_kinds;
   // Map step in target id to list of function targets that user can choose.
   llvm::DenseMap<lldb::addr_t, std::string> step_in_targets;
   // A copy of the last LaunchRequest or AttachRequest so we can reuse its
@@ -231,6 +238,8 @@ struct DAP {
 
   void PopulateExceptionBreakpoints();
 
+  std::optional<ScopeKind> ScopeKind(const int64_t variablesReference);
+
   /// Attempt to determine if an expression is a variable expression or
   /// lldb command using a heuristic based on the first term of the
   /// expression.
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp 
b/lldb/tools/lldb-dap/JSONUtils.cpp
index 6ca4dfb4711a13..238343de055962 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -352,16 +352,16 @@ void FillResponse(const llvm::json::Object &request,
 //   "required": [ "name", "variablesReference", "expensive" ]
 // }
 llvm::json::Value CreateScope(const llvm::StringRef name,
-                              int64_t variablesReference,
+                              int64_t variablesReference, ScopeKind kind,
                               int64_t namedVariables, bool expensive) {
   llvm::json::Object object;
   EmplaceSafeString(object, "name", name.str());
 
   // TODO: Support "arguments" scope. At the moment lldb-dap includes the
   // arguments into the "locals" scope.
-  if (variablesReference == VARREF_LOCALS) {
+  if (kind == ScopeKind::Locals) {
     object.try_emplace("presentationHint", "locals");
-  } else if (variablesReference == VARREF_REGS) {
+  } else if (kind == ScopeKind::Registers) {
     object.try_emplace("presentationHint", "registers");
   }
 
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index db56d987773476..f117ad9fff792e 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_JSONUTILS_H
 #define LLDB_TOOLS_LLDB_DAP_JSONUTILS_H
 
+#include "DAP.h"
 #include "DAPForward.h"
 #include "lldb/API/SBCompileUnit.h"
 #include "lldb/API/SBFileSpec.h"
@@ -319,7 +320,7 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint 
&bp);
 ///     A "Scope" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
 llvm::json::Value CreateScope(const llvm::StringRef name,
-                              int64_t variablesReference,
+                              int64_t variablesReference, ScopeKind kind,
                               int64_t namedVariables, bool expensive);
 
 /// Create a "Source" JSON object as described in the debug adaptor definition.
diff --git a/lldb/tools/lldb-dap/ProgressEvent.h 
b/lldb/tools/lldb-dap/ProgressEvent.h
index 72317b879c803a..e029831f8f330b 100644
--- a/lldb/tools/lldb-dap/ProgressEvent.h
+++ b/lldb/tools/lldb-dap/ProgressEvent.h
@@ -6,6 +6,9 @@
 //
 
//===----------------------------------------------------------------------===//
 
+#ifndef PROGRESS_EVENT_H
+#define PROGRESS_EVENT_H
+
 #include <atomic>
 #include <chrono>
 #include <mutex>
@@ -155,3 +158,5 @@ class ProgressEventReporter {
 };
 
 } // namespace lldb_dap
+
+#endif // PROGRESS_EVENT_H
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 6b12569d90a831..52a31477d7092e 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -128,16 +128,19 @@ static void PrintWelcomeMessage(DAP &dap) {
 }
 
 lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t variablesReference) {
-  switch (variablesReference) {
-  case VARREF_LOCALS:
-    return &dap.variables.locals;
-  case VARREF_GLOBALS:
-    return &dap.variables.globals;
-  case VARREF_REGS:
-    return &dap.variables.registers;
-  default:
-    return nullptr;
+  std::optional<ScopeKind> scope_kind = dap.ScopeKind(variablesReference);
+
+  if (scope_kind.has_value()) {
+    switch (scope_kind.value()) {
+    case lldb_dap::ScopeKind::Locals:
+      return &dap.variables.locals;
+    case lldb_dap::ScopeKind::Globals:
+      return &dap.variables.globals;
+    case lldb_dap::ScopeKind::Registers:
+      return &dap.variables.registers;
+    }
   }
+  return nullptr;
 }
 
 SOCKET AcceptConnection(DAP &dap, int portno) {
@@ -2559,15 +2562,25 @@ void request_scopes(DAP &dap, const llvm::json::Object 
&request) {
     frame.GetThread().SetSelectedFrame(frame.GetFrameID());
   }
 
-  dap.variables.locals = frame.GetVariables(/*arguments=*/true,
-                                            /*locals=*/true,
-                                            /*statics=*/false,
-                                            /*in_scope_only=*/true);
-  dap.variables.globals = frame.GetVariables(/*arguments=*/false,
-                                             /*locals=*/false,
-                                             /*statics=*/true,
-                                             /*in_scope_only=*/true);
-  dap.variables.registers = frame.GetRegisters();
+  uint32_t frame_id = frame.GetFrameID();
+
+  if (dap.variables.added_frames.find(frame_id) ==
+      dap.variables.added_frames.end()) {
+    dap.variables.added_frames.insert(frame_id);
+
+    dap.variables.locals.Append(frame.GetVariables(/*arguments=*/true,
+                                                   /*locals=*/true,
+                                                   /*statics=*/false,
+                                                   /*in_scope_only=*/true));
+
+    dap.variables.globals.Append(frame.GetVariables(/*arguments=*/false,
+                                                    /*locals=*/false,
+                                                    /*statics=*/true,
+                                                    /*in_scope_only=*/true));
+
+    dap.variables.registers.Append(frame.GetRegisters());
+  }
+
   body.try_emplace("scopes", dap.CreateTopLevelScopes());
   response.try_emplace("body", std::move(body));
   dap.SendJSON(llvm::json::Value(std::move(response)));
@@ -3945,7 +3958,7 @@ void request_variables(DAP &dap, const llvm::json::Object 
&request) {
     int64_t start_idx = 0;
     int64_t num_children = 0;
 
-    if (variablesReference == VARREF_REGS) {
+    if (dap.ScopeKind(variablesReference) == ScopeKind::Registers) {
       // Change the default format of any pointer sized registers in the first
       // register set to be the lldb::eFormatAddressInfo so we show the pointer
       // and resolve what the pointer resolves to. Only change the format if 
the
@@ -3965,7 +3978,8 @@ void request_variables(DAP &dap, const llvm::json::Object 
&request) {
     }
 
     num_children = top_scope->GetSize();
-    if (num_children == 0 && variablesReference == VARREF_LOCALS) {
+    if (num_children == 0 &&
+        dap.ScopeKind(variablesReference) == ScopeKind::Locals) {
       // 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.

>From 0b7aaed3da01adb6c1e1fa0d7836ca36bc1842da Mon Sep 17 00:00:00 2001
From: Anthony Eid <he...@anthonyeid.me>
Date: Fri, 24 Jan 2025 03:09:58 -0500
Subject: [PATCH 2/2] Fix bug where some scope requests would be invalid

---
 lldb/tools/lldb-dap/DAP.cpp      | 30 +++++++++++++---
 lldb/tools/lldb-dap/DAP.h        | 12 +++++--
 lldb/tools/lldb-dap/lldb-dap.cpp | 62 +++++++++++++++++++-------------
 3 files changed, 72 insertions(+), 32 deletions(-)

diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 0836fbf9f32dd6..0f36c0a578b3bf 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -141,7 +141,7 @@ void DAP::PopulateExceptionBreakpoints() {
 std::optional<ScopeKind> DAP::ScopeKind(const int64_t variablesReference) {
   auto iter = scope_kinds.find(variablesReference);
   if (iter != scope_kinds.end()) {
-    return iter->second;
+    return iter->second.first;
   }
 
   return std::nullopt;
@@ -484,23 +484,26 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object 
&arguments) {
   return thread.GetFrameAtIndex(GetLLDBFrameID(frame_id));
 }
 
-llvm::json::Value DAP::CreateTopLevelScopes() {
+llvm::json::Value DAP::CreateTopLevelScopes(uint32_t frame_id) {
   llvm::json::Array scopes;
 
   scopes.emplace_back(CreateScope("Locals", variables.next_temporary_var_ref,
                                   ScopeKind::Locals, 
variables.locals.GetSize(),
                                   false));
-  scope_kinds[variables.next_temporary_var_ref++] = ScopeKind::Locals;
+  scope_kinds[variables.next_temporary_var_ref++] =
+      std::make_pair(ScopeKind::Locals, frame_id);
 
   scopes.emplace_back(CreateScope("Globals", variables.next_temporary_var_ref,
                                   ScopeKind::Globals,
                                   variables.globals.GetSize(), false));
-  scope_kinds[variables.next_temporary_var_ref++] = ScopeKind::Globals;
+  scope_kinds[variables.next_temporary_var_ref++] =
+      std::make_pair(ScopeKind::Globals, frame_id);
 
   scopes.emplace_back(CreateScope("Registers", 
variables.next_temporary_var_ref,
                                   ScopeKind::Registers,
                                   variables.registers.GetSize(), false));
-  scope_kinds[variables.next_temporary_var_ref++] = ScopeKind::Registers;
+  scope_kinds[variables.next_temporary_var_ref++] =
+      std::make_pair(ScopeKind::Registers, frame_id);
 
   return llvm::json::Value(std::move(scopes));
 }
@@ -846,11 +849,28 @@ lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) 
{
   return error;
 }
 
+bool Variables::SwitchFrame(uint32_t frame_id) {
+  auto iter = frames.find(frame_id);
+
+  if (iter == frames.end()) {
+    return false;
+  }
+
+  auto [frame_locals, frame_globals, frame_registers] = iter->second;
+
+  locals = frame_locals;
+  globals = frame_globals;
+  registers = frame_registers;
+
+  return true;
+}
+
 void Variables::Clear() {
   locals.Clear();
   globals.Clear();
   registers.Clear();
   referenced_variables.clear();
+  frames.clear();
 }
 
 int64_t Variables::GetNewVariableReference(bool is_permanent) {
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 68399e2e0410c7..a77e3c0389f5a1 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -15,6 +15,8 @@
 #include <optional>
 #include <set>
 #include <thread>
+#include <tuple>
+#include <utility>
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/DenseSet.h"
@@ -88,7 +90,9 @@ struct Variables {
   int64_t next_temporary_var_ref{VARREF_FIRST_VAR_IDX};
   int64_t next_permanent_var_ref{PermanentVariableStartIndex};
 
-  std::set<uint32_t> added_frames;
+  std::map<uint32_t,
+           std::tuple<lldb::SBValueList, lldb::SBValueList, lldb::SBValueList>>
+      frames;
 
   /// Variables that are alive in this stop state.
   /// Will be cleared when debuggee resumes.
@@ -115,6 +119,8 @@ struct Variables {
   /// \return variableReference assigned to this expandable variable.
   int64_t InsertVariable(lldb::SBValue variable, bool is_permanent);
 
+  bool SwitchFrame(uint32_t frame_id);
+
   /// Clear all scope variables and non-permanent expandable variables.
   void Clear();
 };
@@ -165,7 +171,7 @@ struct DAP {
   std::vector<std::string> exit_commands;
   std::vector<std::string> stop_commands;
   std::vector<std::string> terminate_commands;
-  std::map<int, ScopeKind> scope_kinds;
+  std::map<int, std::pair<ScopeKind, uint32_t>> scope_kinds;
   // Map step in target id to list of function targets that user can choose.
   llvm::DenseMap<lldb::addr_t, std::string> step_in_targets;
   // A copy of the last LaunchRequest or AttachRequest so we can reuse its
@@ -234,7 +240,7 @@ struct DAP {
 
   lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments);
 
-  llvm::json::Value CreateTopLevelScopes();
+  llvm::json::Value CreateTopLevelScopes(uint32_t frame_id);
 
   void PopulateExceptionBreakpoints();
 
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 52a31477d7092e..f61b667a70220e 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -51,6 +51,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <thread>
+#include <tuple>
 #include <vector>
 
 #if defined(_WIN32)
@@ -128,17 +129,25 @@ static void PrintWelcomeMessage(DAP &dap) {
 }
 
 lldb::SBValueList *GetTopLevelScope(DAP &dap, int64_t variablesReference) {
-  std::optional<ScopeKind> scope_kind = dap.ScopeKind(variablesReference);
-
-  if (scope_kind.has_value()) {
-    switch (scope_kind.value()) {
-    case lldb_dap::ScopeKind::Locals:
-      return &dap.variables.locals;
-    case lldb_dap::ScopeKind::Globals:
-      return &dap.variables.globals;
-    case lldb_dap::ScopeKind::Registers:
-      return &dap.variables.registers;
-    }
+  auto iter = dap.scope_kinds.find(variablesReference);
+  if (iter == dap.scope_kinds.end()) {
+    return nullptr;
+  }
+
+  ScopeKind scope_kind = iter->second.first;
+  uint32_t frame_id = iter->second.second;
+
+  if (!dap.variables.SwitchFrame(frame_id)) {
+    return nullptr;
+  }
+
+  switch (scope_kind) {
+  case lldb_dap::ScopeKind::Locals:
+    return &dap.variables.locals;
+  case lldb_dap::ScopeKind::Globals:
+    return &dap.variables.globals;
+  case lldb_dap::ScopeKind::Registers:
+    return &dap.variables.registers;
   }
   return nullptr;
 }
@@ -2564,24 +2573,29 @@ void request_scopes(DAP &dap, const llvm::json::Object 
&request) {
 
   uint32_t frame_id = frame.GetFrameID();
 
-  if (dap.variables.added_frames.find(frame_id) ==
-      dap.variables.added_frames.end()) {
-    dap.variables.added_frames.insert(frame_id);
+  if (dap.variables.frames.find(frame_id) == dap.variables.frames.end()) {
+
+    auto locals = frame.GetVariables(/*arguments=*/true,
+                                     /*locals=*/true,
+                                     /*statics=*/false,
+                                     /*in_scope_only=*/true);
+
+    auto globals = frame.GetVariables(/*arguments=*/false,
+                                      /*locals=*/false,
+                                      /*statics=*/true,
+                                      /*in_scope_only=*/true);
 
-    dap.variables.locals.Append(frame.GetVariables(/*arguments=*/true,
-                                                   /*locals=*/true,
-                                                   /*statics=*/false,
-                                                   /*in_scope_only=*/true));
+    auto registers = frame.GetRegisters();
 
-    dap.variables.globals.Append(frame.GetVariables(/*arguments=*/false,
-                                                    /*locals=*/false,
-                                                    /*statics=*/true,
-                                                    /*in_scope_only=*/true));
+    dap.variables.frames.insert(
+        std::make_pair(frame_id, std::make_tuple(locals, globals, registers)));
 
-    dap.variables.registers.Append(frame.GetRegisters());
+    dap.variables.locals = locals;
+    dap.variables.globals = globals;
+    dap.variables.registers = registers;
   }
 
-  body.try_emplace("scopes", dap.CreateTopLevelScopes());
+  body.try_emplace("scopes", dap.CreateTopLevelScopes(frame_id));
   response.try_emplace("body", std::move(body));
   dap.SendJSON(llvm::json::Value(std::move(response)));
 }

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to