[Lldb-commits] [lldb] Make env and source map dictionaries #95137 (PR #106919)

via lldb-commits lldb-commits at lists.llvm.org
Sun Sep 1 12:06:30 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: None (Da-Viper)

<details>
<summary>Changes</summary>

Fixes #<!-- -->95137

---
Full diff: https://github.com/llvm/llvm-project/pull/106919.diff


5 Files Affected:

- (modified) lldb/tools/lldb-dap/JSONUtils.cpp (+33-6) 
- (modified) lldb/tools/lldb-dap/JSONUtils.h (+21) 
- (modified) lldb/tools/lldb-dap/README.md (+5-2) 
- (modified) lldb/tools/lldb-dap/lldb-dap.cpp (+21-13) 
- (modified) lldb/tools/lldb-dap/package.json (+24-9) 


``````````diff
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 7338e7cf41eb03..333c0b21e57d01 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -136,6 +136,31 @@ std::vector<std::string> GetStrings(const llvm::json::Object *obj,
   return strs;
 }
 
+std::unordered_map<std::string, std::string>
+GetStringObject(const llvm::json::Object &obj, llvm::StringRef key) {
+  std::unordered_map<std::string, std::string> strs;
+  const auto *const json_object = obj.getObject(key);
+  if (!json_object)
+    return strs;
+
+  for (const auto &[key, value] : *json_object) {
+    switch (value.kind()) {
+    case llvm::json::Value::String:
+      strs.emplace(key.str(), value.getAsString()->str());
+      break;
+    case llvm::json::Value::Number:
+    case llvm::json::Value::Boolean:
+      strs.emplace(key.str(), llvm::to_string(value));
+      break;
+    case llvm::json::Value::Null:
+    case llvm::json::Value::Object:
+    case llvm::json::Value::Array:
+      break;
+    }
+  }
+  return strs;
+}
+
 static bool IsClassStructOrUnionType(lldb::SBType t) {
   return (t.GetTypeClass() & (lldb::eTypeClassUnion | lldb::eTypeClassStruct |
                               lldb::eTypeClassArray)) != 0;
@@ -1370,13 +1395,15 @@ CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request,
   if (!cwd.empty())
     run_in_terminal_args.try_emplace("cwd", cwd);
 
-  // We need to convert the input list of environments variables into a
-  // dictionary
-  std::vector<std::string> envs = GetStrings(launch_request_arguments, "env");
+  std::unordered_map<std::string, std::string> envMap =
+      GetStringObject(*launch_request_arguments, "env");
   llvm::json::Object environment;
-  for (const std::string &env : envs) {
-    size_t index = env.find('=');
-    environment.try_emplace(env.substr(0, index), env.substr(index + 1));
+  for (const auto &[key, value] : envMap) {
+    if (key.empty())
+      g_dap.SendOutput(OutputType::Stderr,
+                       "empty environment variable for value: \"" + value + '\"');
+    else
+      environment.try_emplace(key, value);
   }
   run_in_terminal_args.try_emplace("env",
                                    llvm::json::Value(std::move(environment)));
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index b6356630b72682..de6228a0429944 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -16,6 +16,7 @@
 #include "llvm/Support/JSON.h"
 #include <cstdint>
 #include <optional>
+#include <unordered_map>
 
 namespace lldb_dap {
 
@@ -151,6 +152,26 @@ bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key);
 ///     strings, numbers or booleans.
 std::vector<std::string> GetStrings(const llvm::json::Object *obj,
                                     llvm::StringRef key);
+/// Extract an object of key value strings for the specified key from an object.
+///
+/// String values in the array will be extracted without any quotes
+/// around them. Numbers and Booleans will be converted into
+/// strings. Any NULL, array or objects values in the array will be
+/// ignored.
+///
+/// \param[in] obj
+///     A JSON object that we will attempt to extract the array from
+///
+/// \param[in] key
+///     The key to use when extracting the value
+///
+/// \return
+///     An object of key value strings for the specified \a key, or
+///     \a fail_value if there is no key that matches or if the
+///     value is not an object or key and values in the object are not
+///     strings, numbers or booleans.
+std::unordered_map<std::string, std::string>
+GetStringObject(const llvm::json::Object &obj, llvm::StringRef key);
 
 /// Fill a response object given the request object.
 ///
diff --git a/lldb/tools/lldb-dap/README.md b/lldb/tools/lldb-dap/README.md
index 11a14d29ab51e2..c4f48001dad19a 100644
--- a/lldb/tools/lldb-dap/README.md
+++ b/lldb/tools/lldb-dap/README.md
@@ -34,7 +34,7 @@ file that defines how your program will be run. The JSON configuration file can
 |**launchCommands** |[string]| | LLDB commands executed to launch the program. Commands and command output will be sent to the debugger console when they are executed.
 |**exitCommands**   |[string]| | LLDB commands executed when the program exits. Commands and command output will be sent to the debugger console when they are executed.
 |**terminateCommands** |[string]| | LLDB commands executed when the debugging session ends. Commands and command output will be sent to the debugger console when they are executed.
-|**sourceMap**      |[string[2]]| | Specify an array of path re-mappings. Each element in the array must be a two element array containing a source and destination pathname.
+|**sourceMap**      |dictionary| | Specify an array of path re-mappings. Each element in the array must be a two element array containing a source and destination pathname.
 |**debuggerRoot**   | string| |Specify a working directory to use when launching lldb-dap. If the debug information in your executable contains relative paths, this option can be used so that `lldb-dap` can find source files and object files that have relative paths.
 
 ### Attaching Settings
@@ -77,7 +77,10 @@ adds `FOO=1` and `bar` to the environment:
   "name": "Debug",
   "program": "/tmp/a.out",
   "args": [ "one", "two", "three" ],
-  "env": [ "FOO=1", "BAR" ],
+  "env": {
+    "FOO": "1"
+    "BAR": ""
+  }
 }
 ```
 
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index c5c4b09f15622b..59957344ff7f50 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -599,27 +599,28 @@ lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name) {
 // argument (or neither), from which we need to set the target.source-map.
 void SetSourceMapFromArguments(const llvm::json::Object &arguments) {
   const char *sourceMapHelp =
-      "source must be be an array of two-element arrays, "
-      "each containing a source and replacement path string.\n";
+      "source must be be an object of key-value strings. "
+      "e.g sourceMap: { \"/path/to/source\": \"/path/to/destination\" }.\n";
 
   std::string sourceMapCommand;
   llvm::raw_string_ostream strm(sourceMapCommand);
   strm << "settings set target.source-map ";
-  auto sourcePath = GetString(arguments, "sourcePath");
+  const auto sourcePath = GetString(arguments, "sourcePath");
 
   // sourceMap is the new, more general form of sourcePath and overrides it.
-  auto sourceMap = arguments.getArray("sourceMap");
-  if (sourceMap) {
-    for (const auto &value : *sourceMap) {
-      auto mapping = value.getAsArray();
-      if (mapping == nullptr || mapping->size() != 2 ||
-          (*mapping)[0].kind() != llvm::json::Value::String ||
-          (*mapping)[1].kind() != llvm::json::Value::String) {
+  const auto *sourceMap = arguments.getObject("sourceMap");
+  if (sourceMap && !sourceMap->empty()) {
+    for (const auto &[key, value] : *sourceMap) {
+      const auto mapFrom = llvm::StringRef(key);
+      if (mapFrom.empty()) {
+        return;
+      }
+      if (value.kind() != llvm::json::Value::String) {
         g_dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
         return;
       }
-      auto mapFrom = GetAsString((*mapping)[0]);
-      auto mapTo = GetAsString((*mapping)[1]);
+
+      const llvm::StringRef mapTo = GetAsString(value);
       strm << "\"" << mapFrom << "\" \"" << mapTo << "\" ";
     }
   } else {
@@ -1831,7 +1832,14 @@ lldb::SBError LaunchProcess(const llvm::json::Object &request) {
     launch_info.SetArguments(MakeArgv(args).data(), true);
 
   // Pass any environment variables along that the user specified.
-  auto envs = GetStrings(arguments, "env");
+  auto envMap = GetStringObject(*arguments, "env");
+  std::vector<std::string> envs;
+  envs.reserve(envMap.size());
+  for (const auto &[key, value] : envMap) {
+    if (!key.empty())
+      envs.emplace_back(key + '=' + value);
+  }
+
   if (!envs.empty())
     launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true);
 
diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json
index 4f4261d1718c01..1404a1f29c6bb0 100644
--- a/lldb/tools/lldb-dap/package.json
+++ b/lldb/tools/lldb-dap/package.json
@@ -160,9 +160,14 @@
                 "default": "${workspaceRoot}"
               },
               "env": {
-                "type": "array",
-                "description": "Additional environment variables to set when launching the program. This is an array of strings that contains the variable name followed by an optional '=' character and the environment variable's value.",
-                "default": []
+                "type": "object",
+                "description": "Additional environment variables to set when launching the program. eg { \"FOO\": \"1\" }",
+                "patternProperties": {
+                  ".*": {
+                    "type": "string"
+                  }
+                },
+                "default": {}
               },
               "stopOnEntry": {
                 "type": "boolean",
@@ -194,9 +199,14 @@
                 "description": "Specify a source path to remap \"./\" to allow full paths to be used when setting breakpoints in binaries that have relative source paths."
               },
               "sourceMap": {
-                "type": "array",
-                "description": "Specify an array of path remappings; each element must itself be a two element array containing a source and destination path name. Overrides sourcePath.",
-                "default": []
+                "type": "object",
+                "description": "Specify an object of path remappings; each entry has a key containing the source path and a value containing the destination path. E.g { \"/the/source/path\": \"/the/destination/path\" } Overrides sourcePath.",
+                "patternProperties": {
+                  ".*": {
+                    "type": "string"
+                  }
+                },
+                "default": {}
               },
               "debuggerRoot": {
                 "type": "string",
@@ -299,9 +309,14 @@
                 "description": "Specify a source path to remap \"./\" to allow full paths to be used when setting breakpoints in binaries that have relative source paths."
               },
               "sourceMap": {
-                "type": "array",
-                "description": "Specify an array of path remappings; each element must itself be a two element array containing a source and destination path name. Overrides sourcePath.",
-                "default": []
+                "type": "object",
+                "description": "Specify an object of path remappings; each entry has a key containing the source path and a value containing the destination path. E.g { \"/the/source/path\": \"/the/destination/path\" } Overrides sourcePath.",
+                "patternProperties": {
+                  ".*": {
+                    "type": "string"
+                  }
+                },
+                "default": {}
               },
               "debuggerRoot": {
                 "type": "string",

``````````

</details>


https://github.com/llvm/llvm-project/pull/106919


More information about the lldb-commits mailing list