https://github.com/Da-Viper updated https://github.com/llvm/llvm-project/pull/106919
>From d2bddca1753b4c960895f51d7eb80b6efa7dc986 Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Sun, 1 Sep 2024 17:26:11 +0100 Subject: [PATCH 1/8] [lldb-dap] Make environment option an object --- .../tools/lldb-dap/launch/TestDAP_launch.py | 4 +- lldb/tools/lldb-dap/JSONUtils.cpp | 40 ++++++++++++++++--- lldb/tools/lldb-dap/JSONUtils.h | 22 ++++++++++ lldb/tools/lldb-dap/README.md | 5 ++- lldb/tools/lldb-dap/lldb-dap.cpp | 8 +++- lldb/tools/lldb-dap/package.json | 11 +++-- 6 files changed, 77 insertions(+), 13 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index a16f2da3c4df71..6b9993a2548b8d 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -229,7 +229,7 @@ def test_environment(self): Tests launch of a simple program with environment variables """ program = self.getBuildArtifact("a.out") - env = ["NO_VALUE", "WITH_VALUE=BAR", "EMPTY_VALUE=", "SPACE=Hello World"] + env = {"NO_VALUE": "", "WITH_VALUE":"BAR", "EMPTY_VALUE": "", "SPACE": "Hello World"} self.build_and_launch(program, env=env) self.continue_to_exit() @@ -242,7 +242,7 @@ def test_environment(self): lines.pop(0) # Make sure each environment variable in "env" is actually set in the # program environment that was printed to STDOUT - for var in env: + for var in env.keys(): found = False for program_var in lines: if var in program_var: diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 7338e7cf41eb03..29b3ad490af0b6 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> +GetStringMap(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,16 @@ 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 = + GetStringMap(*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..60d5db06560657 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 { @@ -152,6 +153,27 @@ bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key); 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 object 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> +GetStringMap(const llvm::json::Object &obj, llvm::StringRef key); + /// Fill a response object given the request object. /// /// The \a response object will get its "type" set to "response", diff --git a/lldb/tools/lldb-dap/README.md b/lldb/tools/lldb-dap/README.md index 11a14d29ab51e2..5b6fc5ef990e60 100644 --- a/lldb/tools/lldb-dap/README.md +++ b/lldb/tools/lldb-dap/README.md @@ -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..da0935dff69878 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -1831,7 +1831,13 @@ 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 = GetStringMap(*arguments, "env"); + std::vector<std::string> envs; + envs.reserve(envMap.size()); + for (const auto &[key, value] : envMap) { + 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..3867302a841913 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. E.g. `{ \"FOO\": \"1\" }`", + "patternProperties": { + ".*": { + "type": "string" + } + }, + "default": {} }, "stopOnEntry": { "type": "boolean", >From a3827ed57f655ab803fa28ea7f97e5274322bf0e Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Mon, 2 Sep 2024 14:25:07 +0100 Subject: [PATCH 2/8] [lldb-dap] format python test code --- lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 6b9993a2548b8d..a56ad032772cbb 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -229,7 +229,12 @@ def test_environment(self): Tests launch of a simple program with environment variables """ program = self.getBuildArtifact("a.out") - env = {"NO_VALUE": "", "WITH_VALUE":"BAR", "EMPTY_VALUE": "", "SPACE": "Hello World"} + env = { + "NO_VALUE": "", + "WITH_VALUE": "BAR", + "EMPTY_VALUE": "", + "SPACE": "Hello World", + } self.build_and_launch(program, env=env) self.continue_to_exit() >From b0dcf84e0b38dd69813f3aa0f827fb5a70d369f8 Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Mon, 2 Sep 2024 23:56:40 +0100 Subject: [PATCH 3/8] [lldb-dap] Clean: use Environment class instead of manual concatenation --- lldb/tools/lldb-dap/lldb-dap.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index da0935dff69878..7df84bd72794fd 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -51,6 +51,7 @@ #include <thread> #include <vector> +#include "lldb/API/SBEnvironment.h" #include "lldb/API/SBStream.h" #include "lldb/Host/Config.h" #include "llvm/ADT/ArrayRef.h" @@ -1832,14 +1833,13 @@ lldb::SBError LaunchProcess(const llvm::json::Object &request) { // Pass any environment variables along that the user specified. auto envMap = GetStringMap(*arguments, "env"); - std::vector<std::string> envs; - envs.reserve(envMap.size()); + lldb::SBEnvironment envs{}; for (const auto &[key, value] : envMap) { - envs.emplace_back(key + '=' + value); + envs.Set(key.c_str(), value.c_str(), true); } - if (!envs.empty()) - launch_info.SetEnvironmentEntries(MakeArgv(envs).data(), true); + if (envs.GetNumValues() != 0) + launch_info.SetEnvironment(envs, true); auto flags = launch_info.GetLaunchFlags(); >From e82fe88453be92352ea56ffbf3a585384c54544a Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Wed, 4 Sep 2024 18:54:35 +0100 Subject: [PATCH 4/8] [lldb-dap] support both array and object env types --- .../tools/lldb-dap/launch/TestDAP_launch.py | 34 ++++++++++++++++- lldb/tools/lldb-dap/lldb-dap.cpp | 37 +++++++++++++++---- lldb/tools/lldb-dap/package.json | 28 ++++++++++---- 3 files changed, 81 insertions(+), 18 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index a56ad032772cbb..7898d01457afc4 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -224,7 +224,7 @@ def test_args(self): 'arg[%i] "%s" not in "%s"' % (i + 1, quoted_arg, lines[i]), ) - def test_environment(self): + def test_environment_with_object(self): """ Tests launch of a simple program with environment variables """ @@ -235,6 +235,36 @@ def test_environment(self): "EMPTY_VALUE": "", "SPACE": "Hello World", } + + self.build_and_launch(program, env=env) + self.continue_to_exit() + + # Now get the STDOUT and verify our arguments got passed correctly + output = self.get_stdout() + self.assertTrue(output and len(output) > 0, "expect program output") + lines = output.splitlines() + # Skip the all arguments so we have only environment vars left + while len(lines) and lines[0].startswith("arg["): + lines.pop(0) + # Make sure each environment variable in "env" is actually set in the + # program environment that was printed to STDOUT + for var in env: + found = False + for program_var in lines: + if var in program_var: + found = True + break + self.assertTrue( + found, '"%s" must exist in program environment (%s)' % (var, lines) + ) + + def test_environment_with_array(self): + """ + Tests launch of a simple program with environment variables + """ + program = self.getBuildArtifact("a.out") + env = ["NO_VALUE", "WITH_VALUE=BAR", "EMPTY_VALUE=", "SPACE=Hello World"] + self.build_and_launch(program, env=env) self.continue_to_exit() @@ -247,7 +277,7 @@ def test_environment(self): lines.pop(0) # Make sure each environment variable in "env" is actually set in the # program environment that was printed to STDOUT - for var in env.keys(): + for var in env: found = False for program_var in lines: if var in program_var: diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index 7df84bd72794fd..1bb39e9aab1cb7 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -185,6 +185,33 @@ std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) { return argv; } +// Gets all the environment variables from the json object depending on if the +// kind is an object or an array. +lldb::SBEnvironment +GetEnvironmentFromArguments(const llvm::json::Object &arguments) { + lldb::SBEnvironment envs{}; + constexpr llvm::StringRef env_key = "env"; + const auto *env_type = arguments.get(env_key); + + if (!env_type) + return envs; + + if (env_type->kind() == llvm::json::Value::Object) { + auto env_map = GetStringMap(arguments, env_key); + for (const auto &[key, value] : env_map) { + envs.Set(key.c_str(), value.c_str(), true); + } + } else if (env_type->kind() == llvm::json::Value::Array) { + const auto envs_strings = GetStrings(&arguments, env_key); + lldb::SBStringList entries{}; + for (const auto &env : envs_strings) { + entries.AppendString(env.c_str()); + } + envs.SetEntries(entries, true); + } + return envs; +} + // Send a "exited" event to indicate the process has exited. void SendProcessExitedEvent(lldb::SBProcess &process) { llvm::json::Object event(CreateEventObject("exited")); @@ -1832,14 +1859,8 @@ 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 envMap = GetStringMap(*arguments, "env"); - lldb::SBEnvironment envs{}; - for (const auto &[key, value] : envMap) { - envs.Set(key.c_str(), value.c_str(), true); - } - - if (envs.GetNumValues() != 0) - launch_info.SetEnvironment(envs, true); + const auto envs = GetEnvironmentFromArguments(*arguments); + launch_info.SetEnvironment(envs, true); auto flags = launch_info.GetLaunchFlags(); diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index 3867302a841913..c0e72690162763 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -160,14 +160,26 @@ "default": "${workspaceRoot}" }, "env": { - "type": "object", - "description": "Additional environment variables to set when launching the program. E.g. `{ \"FOO\": \"1\" }`", - "patternProperties": { - ".*": { - "type": "string" + "anyOf": [ + { + "type": "object", + "description": "Additional environment variables to set when launching the program. E.g. `{ \"FOO\": \"1\" }`", + "patternProperties": { + ".*": { + "type": "string" + } + }, + "default": {} + }, + { + "type": "array", + "description": "Additional environment variables to set when launching the program. E.g. `[\"FOO=1\", \"BAR\"]`", + "items": { + "type": "string" + }, + "default": {} } - }, - "default": {} + ] }, "stopOnEntry": { "type": "boolean", @@ -426,4 +438,4 @@ } ] } -} +} \ No newline at end of file >From 7c20d5d91d6a456058437af73e56f311b513d8ff Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Wed, 4 Sep 2024 20:59:28 +0100 Subject: [PATCH 5/8] [lldb-dap] support object type of setting source map --- .../lldb-dap/coreFile/TestDAP_coreFile.py | 16 +++++- lldb/tools/lldb-dap/lldb-dap.cpp | 23 +++++--- lldb/tools/lldb-dap/package.json | 56 +++++++++++++++++-- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py index b85b6048439639..5189435185607f 100644 --- a/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py +++ b/lldb/test/API/tools/lldb-dap/coreFile/TestDAP_coreFile.py @@ -58,7 +58,7 @@ def test_core_file(self): self.assertEqual(self.get_stackFrames(), expected_frames) @skipIfLLVMTargetMissing("X86") - def test_core_file_source_mapping(self): + def test_core_file_source_mapping_array(self): """Test that sourceMap property is correctly applied when loading a core""" current_dir = os.path.dirname(__file__) exe_file = os.path.join(current_dir, "linux-x86_64.out") @@ -70,3 +70,17 @@ def test_core_file_source_mapping(self): self.attach(exe_file, coreFile=core_file, sourceMap=source_map) self.assertIn(current_dir, self.get_stackFrames()[0]["source"]["path"]) + + @skipIfLLVMTargetMissing("X86") + def test_core_file_source_mapping_object(self): + """Test that sourceMap property is correctly applied when loading a core""" + current_dir = os.path.dirname(__file__) + exe_file = os.path.join(current_dir, "linux-x86_64.out") + core_file = os.path.join(current_dir, "linux-x86_64.core") + + self.create_debug_adaptor() + + source_map = {"/home/labath/test": current_dir} + self.attach(exe_file, coreFile=core_file, sourceMap=source_map) + + self.assertIn(current_dir, self.get_stackFrames()[0]["source"]["path"]) diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index 1bb39e9aab1cb7..df999fd7316b50 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -633,25 +633,32 @@ void SetSourceMapFromArguments(const llvm::json::Object &arguments) { 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(); + constexpr llvm::StringRef sourceMapKey = "sourceMap"; + + if (const auto *sourceMapArray = arguments.getArray(sourceMapKey)) { + for (const auto &value : *sourceMapArray) { + const auto *mapping = value.getAsArray(); if (mapping == nullptr || mapping->size() != 2 || (*mapping)[0].kind() != llvm::json::Value::String || (*mapping)[1].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 auto mapFrom = GetAsString((*mapping)[0]); + const auto mapTo = GetAsString((*mapping)[1]); strm << "\"" << mapFrom << "\" \"" << mapTo << "\" "; } + } else if (const auto *sourceMapObj = arguments.getObject(sourceMapKey)) { + for (const auto &[key, value] : *sourceMapObj) { + if (value.kind() == llvm::json::Value::String) { + strm << "\"" << key.str() << "\" \"" << GetAsString(value) << "\" "; + } + } } else { - if (ObjectContainsKey(arguments, "sourceMap")) { + if (ObjectContainsKey(arguments, sourceMapKey)) { g_dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp)); return; } diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index c0e72690162763..ee5d473c728540 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -211,9 +211,31 @@ "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": [] + "anyOf": [ + { + "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": {} + }, + { + "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.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "string" + } + }, + "default": [] + } + ] }, "debuggerRoot": { "type": "string", @@ -316,9 +338,31 @@ "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": [] + "anyOf": [ + { + "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": {} + }, + { + "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.", + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": { + "type": "string" + } + }, + "default": [] + } + ] }, "debuggerRoot": { "type": "string", >From d98881a1fc991285ee876edf047420691ebe0571 Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Thu, 12 Sep 2024 00:53:46 +0100 Subject: [PATCH 6/8] [lldb-dap] Move getEnvrioment.. to LLDBUtils.cpp --- lldb/tools/lldb-dap/JSONUtils.cpp | 18 ++++++++++-------- lldb/tools/lldb-dap/LLDBUtils.cpp | 25 +++++++++++++++++++++++++ lldb/tools/lldb-dap/LLDBUtils.h | 14 +++++++++++++- lldb/tools/lldb-dap/lldb-dap.cpp | 27 --------------------------- 4 files changed, 48 insertions(+), 36 deletions(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 29b3ad490af0b6..0284c336342116 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -1395,19 +1395,21 @@ CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request, if (!cwd.empty()) run_in_terminal_args.try_emplace("cwd", cwd); - std::unordered_map<std::string, std::string> envMap = - GetStringMap(*launch_request_arguments, "env"); - llvm::json::Object environment; - for (const auto &[key, value] : envMap) { + auto envs = GetEnvironmentFromArguments(*launch_request_arguments); + llvm::json::Object env_json; + for (size_t index = 0; index < envs.GetNumValues(); index++) { + auto key = llvm::StringRef(envs.GetNameAtIndex(index)); + auto value = llvm::StringRef(envs.GetValueAtIndex(index)); + if (key.empty()) g_dap.SendOutput(OutputType::Stderr, - "empty environment variable for value: \"" + value + - '\"'); + "empty environment variable for value: \"" + + value.str() + '\"'); else - environment.try_emplace(key, value); + env_json.try_emplace(key, value); } run_in_terminal_args.try_emplace("env", - llvm::json::Value(std::move(environment))); + llvm::json::Value(std::move(env_json))); return run_in_terminal_args; } diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 2da107887604b4..78b3fc46e8be11 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -135,4 +135,29 @@ int64_t MakeDAPFrameID(lldb::SBFrame &frame) { frame.GetFrameID(); } +lldb::SBEnvironment +GetEnvironmentFromArguments(const llvm::json::Object &arguments) { + lldb::SBEnvironment envs{}; + constexpr llvm::StringRef env_key = "env"; + const auto *env_type = arguments.get(env_key); + + if (!env_type) + return envs; + + if (env_type->kind() == llvm::json::Value::Object) { + auto env_map = GetStringMap(arguments, env_key); + for (const auto &[key, value] : env_map) { + envs.Set(key.c_str(), value.c_str(), true); + } + } else if (env_type->kind() == llvm::json::Value::Array) { + const auto envs_strings = GetStrings(&arguments, env_key); + lldb::SBStringList entries{}; + for (const auto &env : envs_strings) { + entries.AppendString(env.c_str()); + } + envs.SetEntries(entries, true); + } + return envs; +} + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h index ee701da2230fe0..d5072d19029a1e 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ b/lldb/tools/lldb-dap/LLDBUtils.h @@ -10,11 +10,12 @@ #define LLDB_TOOLS_LLDB_DAP_LLDBUTILS_H #include "DAPForward.h" +#include "lldb/API/SBEnvironment.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" #include <string> -#include <vector> namespace lldb_dap { @@ -135,6 +136,17 @@ uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id); /// The LLDB frame index ID. uint32_t GetLLDBFrameID(uint64_t dap_frame_id); +/// Gets all the environment variables from the json object depending on if the +/// kind is an object or an array. +/// +/// \param[in] arguments +/// The json object with the launch options +/// +/// \return +/// The environment variables stored in the env key +lldb::SBEnvironment +GetEnvironmentFromArguments(const llvm::json::Object &arguments); + } // namespace lldb_dap #endif diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index df999fd7316b50..8e51219634a0f9 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -185,33 +185,6 @@ std::vector<const char *> MakeArgv(const llvm::ArrayRef<std::string> &strs) { return argv; } -// Gets all the environment variables from the json object depending on if the -// kind is an object or an array. -lldb::SBEnvironment -GetEnvironmentFromArguments(const llvm::json::Object &arguments) { - lldb::SBEnvironment envs{}; - constexpr llvm::StringRef env_key = "env"; - const auto *env_type = arguments.get(env_key); - - if (!env_type) - return envs; - - if (env_type->kind() == llvm::json::Value::Object) { - auto env_map = GetStringMap(arguments, env_key); - for (const auto &[key, value] : env_map) { - envs.Set(key.c_str(), value.c_str(), true); - } - } else if (env_type->kind() == llvm::json::Value::Array) { - const auto envs_strings = GetStrings(&arguments, env_key); - lldb::SBStringList entries{}; - for (const auto &env : envs_strings) { - entries.AppendString(env.c_str()); - } - envs.SetEntries(entries, true); - } - return envs; -} - // Send a "exited" event to indicate the process has exited. void SendProcessExitedEvent(lldb::SBProcess &process) { llvm::json::Object event(CreateEventObject("exited")); >From f474097f9721923da75b92b8effc2bc7ddd9e400 Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Thu, 12 Sep 2024 01:18:55 +0100 Subject: [PATCH 7/8] [lldb-dap] match the environment format --- lldb/tools/lldb-dap/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index ee5d473c728540..bcf55ae9f912a1 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -175,9 +175,10 @@ "type": "array", "description": "Additional environment variables to set when launching the program. E.g. `[\"FOO=1\", \"BAR\"]`", "items": { - "type": "string" + "type": "string", + "pattern": "^((\\w+=.*)|^\\w+)$" }, - "default": {} + "default": [] } ] }, >From ca162d322f524946096a51ee0e2174954ceafde0 Mon Sep 17 00:00:00 2001 From: Ezike Ebuka <yerimy...@gmail.com> Date: Thu, 12 Sep 2024 23:54:44 +0100 Subject: [PATCH 8/8] [lldb-dap] Add requested changes --- lldb/tools/lldb-dap/JSONUtils.cpp | 7 ++++--- lldb/tools/lldb-dap/LLDBUtils.cpp | 16 ++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 0284c336342116..1770ccd478b94e 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -1397,9 +1397,10 @@ CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request, auto envs = GetEnvironmentFromArguments(*launch_request_arguments); llvm::json::Object env_json; - for (size_t index = 0; index < envs.GetNumValues(); index++) { - auto key = llvm::StringRef(envs.GetNameAtIndex(index)); - auto value = llvm::StringRef(envs.GetValueAtIndex(index)); + for (size_t index = 0, env_count = envs.GetNumValues(); index < env_count; + index++) { + llvm::StringRef key = envs.GetNameAtIndex(index); + llvm::StringRef value = envs.GetValueAtIndex(index); if (key.empty()) g_dap.SendOutput(OutputType::Stderr, diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp index 78b3fc46e8be11..b929e92ac9e70e 100644 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ b/lldb/tools/lldb-dap/LLDBUtils.cpp @@ -139,22 +139,22 @@ lldb::SBEnvironment GetEnvironmentFromArguments(const llvm::json::Object &arguments) { lldb::SBEnvironment envs{}; constexpr llvm::StringRef env_key = "env"; - const auto *env_type = arguments.get(env_key); + const llvm::json::Value *raw_json_env = arguments.get(env_key); - if (!env_type) + if (!raw_json_env) return envs; - if (env_type->kind() == llvm::json::Value::Object) { + if (raw_json_env->kind() == llvm::json::Value::Object) { auto env_map = GetStringMap(arguments, env_key); - for (const auto &[key, value] : env_map) { + for (const auto &[key, value] : env_map) envs.Set(key.c_str(), value.c_str(), true); - } - } else if (env_type->kind() == llvm::json::Value::Array) { + + } else if (raw_json_env->kind() == llvm::json::Value::Array) { const auto envs_strings = GetStrings(&arguments, env_key); lldb::SBStringList entries{}; - for (const auto &env : envs_strings) { + for (const auto &env : envs_strings) entries.AppendString(env.c_str()); - } + envs.SetEntries(entries, true); } return envs; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits