Author: John Harrison
Date: 2026-02-19T08:50:19-08:00
New Revision: 070db69bebad7c5d35d7b8327fa9dce597f60991

URL: 
https://github.com/llvm/llvm-project/commit/070db69bebad7c5d35d7b8327fa9dce597f60991
DIFF: 
https://github.com/llvm/llvm-project/commit/070db69bebad7c5d35d7b8327fa9dce597f60991.diff

LOG: Reapply "[lldb-dap] Validate utf8 protocol messages." (#181930) (#182056)

This reverts commit 977d910d005c47f884ecf838e504da301b1124b9.

Addressing build issues with gcc.

Added: 
    lldb/unittests/DAP/ProtocolBaseTest.cpp

Modified: 
    lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
    lldb/test/API/tools/lldb-dap/variables/main.cpp
    lldb/tools/lldb-dap/DAP.cpp
    lldb/tools/lldb-dap/DAP.h
    lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
    lldb/tools/lldb-dap/Handler/RequestHandler.cpp
    lldb/tools/lldb-dap/JSONUtils.cpp
    lldb/tools/lldb-dap/JSONUtils.h
    lldb/tools/lldb-dap/LLDBUtils.cpp
    lldb/tools/lldb-dap/LLDBUtils.h
    lldb/tools/lldb-dap/Protocol/DAPTypes.h
    lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
    lldb/tools/lldb-dap/Protocol/ProtocolBase.h
    lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
    lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
    lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
    lldb/tools/lldb-dap/ProtocolUtils.cpp
    lldb/tools/lldb-dap/tool/lldb-dap.cpp
    lldb/unittests/DAP/CMakeLists.txt
    lldb/unittests/DAP/ProtocolTypesTest.cpp
    lldb/unittests/DAP/TestBase.cpp
    lldb/unittests/DAP/VariablesTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py 
b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
index a70fefd358b4b..7abcec56a7880 100644
--- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
+++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py
@@ -195,6 +195,8 @@ def do_test_scopes_variables_setVariable_evaluate(
                 },
                 "readOnly": True,
             },
+            "valid_str": {},
+            "malformed_str": {},
             "x": {"equals": {"type": "int"}},
         }
 
@@ -357,9 +359,9 @@ def do_test_scopes_variables_setVariable_evaluate(
 
         verify_locals["argc"]["equals"]["value"] = "123"
         verify_locals["pt"]["children"]["x"]["equals"]["value"] = "111"
-        verify_locals["x @ main.cpp:19"] = {"equals": {"type": "int", "value": 
"89"}}
-        verify_locals["x @ main.cpp:21"] = {"equals": {"type": "int", "value": 
"42"}}
-        verify_locals["x @ main.cpp:23"] = {"equals": {"type": "int", "value": 
"72"}}
+        verify_locals["x @ main.cpp:23"] = {"equals": {"type": "int", "value": 
"89"}}
+        verify_locals["x @ main.cpp:25"] = {"equals": {"type": "int", "value": 
"42"}}
+        verify_locals["x @ main.cpp:27"] = {"equals": {"type": "int", "value": 
"72"}}
 
         self.verify_variables(verify_locals, 
self.dap_server.get_local_variables())
 
@@ -367,22 +369,22 @@ def do_test_scopes_variables_setVariable_evaluate(
         self.assertFalse(self.set_local("x2", 9)["success"])
         self.assertFalse(self.set_local("x @ main.cpp:0", 9)["success"])
 
-        self.assertTrue(self.set_local("x @ main.cpp:19", 19)["success"])
-        self.assertTrue(self.set_local("x @ main.cpp:21", 21)["success"])
-        self.assertTrue(self.set_local("x @ main.cpp:23", 23)["success"])
+        self.assertTrue(self.set_local("x @ main.cpp:23", 19)["success"])
+        self.assertTrue(self.set_local("x @ main.cpp:25", 21)["success"])
+        self.assertTrue(self.set_local("x @ main.cpp:27", 23)["success"])
 
         # The following should have no effect
-        self.assertFalse(self.set_local("x @ main.cpp:23", 
"invalid")["success"])
+        self.assertFalse(self.set_local("x @ main.cpp:27", 
"invalid")["success"])
 
-        verify_locals["x @ main.cpp:19"]["equals"]["value"] = "19"
-        verify_locals["x @ main.cpp:21"]["equals"]["value"] = "21"
-        verify_locals["x @ main.cpp:23"]["equals"]["value"] = "23"
+        verify_locals["x @ main.cpp:23"]["equals"]["value"] = "19"
+        verify_locals["x @ main.cpp:25"]["equals"]["value"] = "21"
+        verify_locals["x @ main.cpp:27"]["equals"]["value"] = "23"
 
         self.verify_variables(verify_locals, 
self.dap_server.get_local_variables())
 
         # The plain x variable shold refer to the innermost x
         self.assertTrue(self.set_local("x", 22)["success"])
-        verify_locals["x @ main.cpp:23"]["equals"]["value"] = "22"
+        verify_locals["x @ main.cpp:27"]["equals"]["value"] = "22"
 
         self.verify_variables(verify_locals, 
self.dap_server.get_local_variables())
 
@@ -399,9 +401,9 @@ def do_test_scopes_variables_setVariable_evaluate(
         names = [var["name"] for var in locals]
         # The first shadowed x shouldn't have a suffix anymore
         verify_locals["x"] = {"equals": {"type": "int", "value": "19"}}
-        self.assertNotIn("x @ main.cpp:19", names)
-        self.assertNotIn("x @ main.cpp:21", names)
         self.assertNotIn("x @ main.cpp:23", names)
+        self.assertNotIn("x @ main.cpp:25", names)
+        self.assertNotIn("x @ main.cpp:27", names)
 
         self.verify_variables(verify_locals, locals)
 
@@ -472,6 +474,22 @@ def do_test_scopes_and_evaluate_expansion(self, 
enableAutoVariableSummaries: boo
                 },
                 "readOnly": True,
             },
+            "valid_str": {
+                "equals": {
+                    "type": "const char *",
+                },
+                "matches": {
+                    "value": r'0x\w+ "𐌢𐌰L𐌾𐍈 CπˆπŒΌπŒ΄πƒ"',
+                },
+            },
+            "malformed_str": {
+                "equals": {
+                    "type": "const char *",
+                },
+                "matches": {
+                    "value": r'0x\w+ "lone trailing \\x81\\x82 bytes"',
+                },
+            },
             "x": {
                 "equals": {"type": "int"},
                 "missing": ["indexedVariables"],
@@ -712,6 +730,8 @@ def test_return_variables(self):
             "argc": {},
             "argv": {},
             "pt": {"readOnly": True},
+            "valid_str": {},
+            "malformed_str": {},
             "x": {},
             "return_result": {"equals": {"type": "int"}},
         }

diff  --git a/lldb/test/API/tools/lldb-dap/variables/main.cpp 
b/lldb/test/API/tools/lldb-dap/variables/main.cpp
index 0e363001f2f42..04fc62f02c22f 100644
--- a/lldb/test/API/tools/lldb-dap/variables/main.cpp
+++ b/lldb/test/API/tools/lldb-dap/variables/main.cpp
@@ -5,6 +5,7 @@ struct PointType {
   int y;
   int buffer[BUFFER_SIZE];
 };
+#include <cstdio>
 #include <vector>
 int g_global = 123;
 static int s_global = 234;
@@ -16,6 +17,9 @@ int main(int argc, char const *argv[]) {
   PointType pt = {11, 22, {0}};
   for (int i = 0; i < BUFFER_SIZE; ++i)
     pt.buffer[i] = i;
+  const char *valid_str = "𐌢𐌰L𐌾𐍈 CπˆπŒΌπŒ΄πƒ";
+  const char *malformed_str = "lone trailing \x81\x82 bytes";
+  printf("print malformed utf8 %s %s\n", valid_str, malformed_str);
   int x = s_global - g_global - pt.y; // breakpoint 1
   {
     int x = 42;

diff  --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 4d7fee5b1e848..8986d740d31aa 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -124,7 +124,7 @@ static std::string capitalize(llvm::StringRef str) {
 llvm::StringRef DAP::debug_adapter_path = "";
 
 DAP::DAP(Log &log, const ReplMode default_repl_mode,
-         std::vector<std::string> pre_init_commands, bool no_lldbinit,
+         const std::vector<String> &pre_init_commands, bool no_lldbinit,
          llvm::StringRef client_name, DAPTransport &transport, MainLoop &loop)
     : log(log), transport(transport), reference_storage(log),
       broadcaster("lldb-dap"),
@@ -132,7 +132,7 @@ DAP::DAP(Log &log, const ReplMode default_repl_mode,
           [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
       repl_mode(default_repl_mode), no_lldbinit(no_lldbinit),
       m_client_name(client_name), m_loop(loop) {
-  configuration.preInitCommands = std::move(pre_init_commands);
+  configuration.preInitCommands = pre_init_commands;
   RegisterRequests();
 }
 
@@ -413,9 +413,10 @@ void DAP::SendOutput(OutputType o, const llvm::StringRef 
output) {
     if (end == llvm::StringRef::npos)
       end = output.size() - 1;
     llvm::json::Object event(CreateEventObject("output"));
-    llvm::json::Object body;
-    body.try_emplace("category", category);
-    EmplaceSafeString(body, "output", output.slice(idx, end + 1).str());
+    llvm::json::Object body{
+        {"category", category},
+        {"output", protocol::String(output.slice(idx, end + 1))},
+    };
     event.try_emplace("body", std::move(body));
     SendJSON(llvm::json::Value(std::move(event)));
     idx = end + 1;
@@ -700,7 +701,7 @@ DAP::ResolveAssemblySource(lldb::SBAddress address) {
 }
 
 bool DAP::RunLLDBCommands(llvm::StringRef prefix,
-                          llvm::ArrayRef<std::string> commands) {
+                          llvm::ArrayRef<String> commands) {
   bool required_command_failed = false;
   std::string output = ::RunLLDBCommands(
       debugger, prefix, commands, required_command_failed,
@@ -719,15 +720,13 @@ static llvm::Error 
createRunLLDBCommandsErrorMessage(llvm::StringRef category) {
           .c_str());
 }
 
-llvm::Error
-DAP::RunAttachCommands(llvm::ArrayRef<std::string> attach_commands) {
+llvm::Error DAP::RunAttachCommands(llvm::ArrayRef<String> attach_commands) {
   if (!RunLLDBCommands("Running attachCommands:", attach_commands))
     return createRunLLDBCommandsErrorMessage("attach");
   return llvm::Error::success();
 }
 
-llvm::Error
-DAP::RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands) {
+llvm::Error DAP::RunLaunchCommands(llvm::ArrayRef<String> launch_commands) {
   if (!RunLLDBCommands("Running launchCommands:", launch_commands))
     return createRunLLDBCommandsErrorMessage("launch");
   return llvm::Error::success();
@@ -779,9 +778,9 @@ lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) {
   // omitted at all), so it is good to leave the user an opportunity to specify
   // those. Any of those three can be left empty.
   auto target = this->debugger.CreateTarget(
-      /*filename=*/configuration.program.data(),
-      /*target_triple=*/configuration.targetTriple.data(),
-      /*platform_name=*/configuration.platformName.data(),
+      /*filename=*/configuration.program.c_str(),
+      /*target_triple=*/configuration.targetTriple.c_str(),
+      /*platform_name=*/configuration.platformName.c_str(),
       /*add_dependent_modules=*/true, // Add dependent modules.
       error);
 
@@ -826,8 +825,7 @@ bool DAP::HandleObject(const Message &M) {
     });
 
     auto handler_pos = request_handlers.find(req->command);
-    dispatcher.Set("client_data",
-                   llvm::Twine("request_command:", req->command).str());
+    dispatcher.Set("client_data", "request_command:" + req->command);
     if (handler_pos != request_handlers.end()) {
       handler_pos->second->Run(*req);
     } else {
@@ -855,14 +853,13 @@ bool DAP::HandleObject(const Message &M) {
     // Result should be given, use null if not.
     if (resp->success) {
       (*response_handler)(resp->body);
-      dispatcher.Set("client_data",
-                     llvm::Twine("response_command:", resp->command).str());
+      dispatcher.Set("client_data", "response_command:" + resp->command);
     } else {
       llvm::StringRef message = "Unknown error, response failed";
       if (resp->message) {
         message =
             std::visit(llvm::makeVisitor(
-                           [](const std::string &message) -> llvm::StringRef {
+                           [](const String &message) -> llvm::StringRef {
                              return message;
                            },
                            [](const protocol::ResponseMessage &message)
@@ -946,7 +943,7 @@ void DAP::ClearCancelRequest(const CancelArguments &args) {
 
 template <typename T>
 static std::optional<T> getArgumentsIfRequest(const Request &req,
-                                              llvm::StringLiteral command) {
+                                              const protocol::String &command) 
{
   if (req.command != command)
     return std::nullopt;
 
@@ -1244,7 +1241,7 @@ protocol::Capabilities DAP::GetCapabilities() {
   capabilities.exceptionBreakpointFilters = std::move(filters);
 
   // FIXME: This should be registered based on the supported languages?
-  std::vector<std::string> completion_characters;
+  std::vector<String> completion_characters;
   completion_characters.emplace_back(".");
   // FIXME: I wonder if we should remove this key... its very aggressive
   // triggering and accepting completions.

diff  --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 3346be75fa001..51f652892f61f 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -192,7 +192,7 @@ struct DAP final : public DAPTransport::MessageHandler {
   /// \param[in] loop
   ///     Main loop associated with this instance.
   DAP(Log &log, const ReplMode default_repl_mode,
-      std::vector<std::string> pre_init_commands, bool no_lldbinit,
+      const std::vector<protocol::String> &pre_init_commands, bool no_lldbinit,
       llvm::StringRef client_name, DAPTransport &transport,
       lldb_private::MainLoop &loop);
 
@@ -305,10 +305,12 @@ struct DAP final : public DAPTransport::MessageHandler {
   ///   \b false if a fatal error was found while executing these commands,
   ///   according to the rules of \a LLDBUtils::RunLLDBCommands.
   bool RunLLDBCommands(llvm::StringRef prefix,
-                       llvm::ArrayRef<std::string> commands);
+                       llvm::ArrayRef<protocol::String> commands);
 
-  llvm::Error RunAttachCommands(llvm::ArrayRef<std::string> attach_commands);
-  llvm::Error RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands);
+  llvm::Error
+  RunAttachCommands(llvm::ArrayRef<protocol::String> attach_commands);
+  llvm::Error
+  RunLaunchCommands(llvm::ArrayRef<protocol::String> launch_commands);
   llvm::Error RunPreInitCommands();
   llvm::Error RunInitCommands();
   llvm::Error RunPreRunCommands();

diff  --git a/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp
index e1a3b15b4697b..d24072c8cc05d 100644
--- a/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp
@@ -30,7 +30,7 @@ llvm::Expected<CompileUnitsResponseBody> 
CompileUnitsRequestHandler::Run(
   int num_modules = dap.target.GetNumModules();
   for (int i = 0; i < num_modules; i++) {
     auto curr_module = dap.target.GetModuleAtIndex(i);
-    if (args->moduleId == llvm::StringRef(curr_module.GetUUIDString())) {
+    if (args->moduleId == curr_module.GetUUIDString()) {
       int num_units = curr_module.GetNumCompileUnits();
       for (int j = 0; j < num_units; j++) {
         auto curr_unit = curr_module.GetCompileUnitAtIndex(j);

diff  --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
index 0b959a5260d23..76177eb9b57cc 100644
--- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
@@ -94,7 +94,8 @@ DataBreakpointInfoRequestHandler::Run(
     size = llvm::utostr(args.bytes.value_or(dap.target.GetAddressByteSize()));
     lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
     if (llvm::StringRef(args.name).getAsInteger<lldb::addr_t>(0, load_addr))
-      return llvm::make_error<DAPError>(args.name + " is not a valid address",
+      return llvm::make_error<DAPError>(args.name.str() +
+                                            " is not a valid address",
                                         llvm::inconvertibleErrorCode(), false);
     addr = llvm::utohexstr(load_addr);
     if (!IsRW(dap, load_addr))

diff  --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index 8387f9ab5c387..9d470b493188f 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -101,7 +101,7 @@ static DisassembledInstruction 
ConvertSBInstructionToDisassembledInstruction(
 
   const char *m = inst.GetMnemonic(target);
   const char *o = inst.GetOperands(target);
-  std::string c = inst.GetComment(target);
+  std::string comment = inst.GetComment(target);
   auto d = inst.GetData(target);
 
   std::string bytes;
@@ -119,24 +119,22 @@ static DisassembledInstruction 
ConvertSBInstructionToDisassembledInstruction(
   if (!bytes.empty()) // remove last whitespace
     bytes.pop_back();
   disassembled_inst.instructionBytes = std::move(bytes);
-
-  llvm::raw_string_ostream si(disassembled_inst.instruction);
-  si << llvm::formatv("{0,-7} {1,-25}", m, o);
+  disassembled_inst.instruction = llvm::formatv("{0,-7} {1,-25}", m, o);
 
   // Only add the symbol on the first line of the function.
   // in the comment section
   if (lldb::SBSymbol symbol = addr.GetSymbol();
       symbol.GetStartAddress() == addr) {
     const llvm::StringRef sym_display_name = symbol.GetDisplayName();
-    c.append(" ");
-    c.append(sym_display_name);
+    comment.append(" ");
+    comment.append(sym_display_name);
 
     if (resolve_symbols)
       disassembled_inst.symbol = sym_display_name;
   }
 
-  if (!c.empty()) {
-    si << " ; " << c;
+  if (!comment.empty()) {
+    disassembled_inst.instruction += " ; " + comment;
   }
 
   std::optional<protocol::Source> source = dap.ResolveSource(addr);

diff  --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index 74ab9a2837034..c92a607d9b7b0 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -268,15 +268,18 @@ static std::optional<ExceptionDetails> 
FormatException(lldb::SBThread &thread) {
     return {};
 
   ExceptionDetails details;
-  raw_string_ostream OS(details.message);
 
   if (const char *name = exception.GetName())
     details.evaluateName = name;
   if (const char *typeName = exception.GetDisplayTypeName())
     details.typeName = typeName;
 
+  std::string message;
+  raw_string_ostream OS(message);
   OS << exception;
 
+  details.message = std::move(message);
+
   if (lldb::SBThread exception_backtrace =
           thread.GetCurrentExceptionBacktrace())
     details.stackTrace = FormatStackTrace(exception_backtrace);
@@ -316,22 +319,19 @@ ExceptionInfoRequestHandler::Run(const 
ExceptionInfoArguments &args) const {
   body.breakMode = eExceptionBreakModeAlways;
   body.exceptionId = FormatExceptionId(dap, thread);
   body.details = FormatException(thread);
-
-  raw_string_ostream OS(body.description);
-  OS << FormatStopDescription(thread);
+  body.description = FormatStopDescription(thread);
 
   if (std::string stop_info = FormatExtendedStopInfo(thread);
       !stop_info.empty())
-    OS << "\n\n" << stop_info;
+    body.description += formatv("\n\n{0}", stop_info);
 
   if (std::string crash_report = FormatCrashReport(thread);
       !crash_report.empty())
-    OS << "\n\n" << crash_report;
+    body.description += formatv("\n\n{0}", crash_report);
 
   lldb::SBProcess process = thread.GetProcess();
   for (uint32_t idx = 0; idx < lldb::eNumInstrumentationRuntimeTypes; idx++) {
-    lldb::InstrumentationRuntimeType type =
-        static_cast<lldb::InstrumentationRuntimeType>(idx);
+    auto type = static_cast<lldb::InstrumentationRuntimeType>(idx);
     if (!process.IsInstrumentationRuntimePresent(type))
       continue;
 

diff  --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 47ae9a7195a7d..5e8c2163c838f 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -37,8 +37,7 @@ using namespace lldb_dap::protocol;
 
 namespace lldb_dap {
 
-static std::vector<const char *>
-MakeArgv(const llvm::ArrayRef<std::string> &strs) {
+static std::vector<const char *> MakeArgv(const llvm::ArrayRef<String> &strs) {
   // Create and return an array of "const char *", one for each C string in
   // "strs" and terminate the list with a NULL. This can be used for argument
   // vectors (argv) or environment vectors (envp) like those passed to the
@@ -60,9 +59,8 @@ static uint32_t SetLaunchFlag(uint32_t flags, bool flag,
   return flags;
 }
 
-static void
-SetupIORedirection(const std::vector<std::optional<std::string>> &stdio,
-                   lldb::SBLaunchInfo &launch_info) {
+static void SetupIORedirection(const std::vector<std::optional<String>> &stdio,
+                               lldb::SBLaunchInfo &launch_info) {
   for (const auto &[idx, value_opt] : llvm::enumerate(stdio)) {
     if (!value_opt)
       continue;
@@ -191,7 +189,7 @@ void BaseRequestHandler::Run(const Request &request) {
 
 llvm::Error BaseRequestHandler::LaunchProcess(
     const protocol::LaunchRequestArguments &arguments) const {
-  const std::vector<std::string> &launchCommands = arguments.launchCommands;
+  const std::vector<String> &launchCommands = arguments.launchCommands;
 
   // Instantiate a launch info instance for the target.
   auto launch_info = dap.target.GetLaunchInfo();
@@ -340,8 +338,8 @@ void BaseRequestHandler::BuildErrorResponse(
         error_message.format = err.getMessage();
         error_message.showUser = err.getShowUser();
         error_message.id = err.convertToErrorCode().value();
-        error_message.url = err.getURL();
-        error_message.urlLabel = err.getURLLabel();
+        error_message.url = err.getURL().value_or("");
+        error_message.urlLabel = err.getURLLabel().value_or("");
         protocol::ErrorResponseBody body;
         body.error = error_message;
 

diff  --git a/lldb/tools/lldb-dap/JSONUtils.cpp 
b/lldb/tools/lldb-dap/JSONUtils.cpp
index d10212d22ab0d..d75b4e23d0e46 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -359,10 +359,10 @@ std::pair<int64_t, bool> UnpackLocation(int64_t 
location_id) {
 /// See
 /// 
https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal
 llvm::json::Object CreateRunInTerminalReverseRequest(
-    llvm::StringRef program, const std::vector<std::string> &args,
-    const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
+    llvm::StringRef program, const std::vector<protocol::String> &args,
+    const llvm::StringMap<protocol::String> &env, llvm::StringRef cwd,
     llvm::StringRef comm_file, lldb::pid_t debugger_pid,
-    const std::vector<std::optional<std::string>> &stdio, bool external) {
+    const std::vector<std::optional<protocol::String>> &stdio, bool external) {
   llvm::json::Object run_in_terminal_args;
   if (external) {
     // This indicates the IDE to open an external terminal window.
@@ -385,10 +385,10 @@ llvm::json::Object CreateRunInTerminalReverseRequest(
 
     std::stringstream ss;
     std::string_view delimiter;
-    for (const std::optional<std::string> &file : stdio) {
+    for (const std::optional<protocol::String> &file : stdio) {
       ss << std::exchange(delimiter, ":");
       if (file)
-        ss << *file;
+        ss << file->str();
     }
     req_args.push_back(ss.str());
   }

diff  --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index 662f20b3b2372..74a7e4bb5c983 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -193,10 +193,10 @@ std::pair<int64_t, bool> UnpackLocation(int64_t 
location_id);
 ///     A "runInTerminal" JSON object that follows the specification outlined 
by
 ///     Microsoft.
 llvm::json::Object CreateRunInTerminalReverseRequest(
-    llvm::StringRef program, const std::vector<std::string> &args,
-    const llvm::StringMap<std::string> &env, llvm::StringRef cwd,
+    llvm::StringRef program, const std::vector<protocol::String> &args,
+    const llvm::StringMap<protocol::String> &env, llvm::StringRef cwd,
     llvm::StringRef comm_file, lldb::pid_t debugger_pid,
-    const std::vector<std::optional<std::string>> &stdio, bool external);
+    const std::vector<std::optional<protocol::String>> &stdio, bool external);
 
 /// Create a "Terminated" JSON object that contains statistics
 ///

diff  --git a/lldb/tools/lldb-dap/LLDBUtils.cpp 
b/lldb/tools/lldb-dap/LLDBUtils.cpp
index d5e91e7e18170..95eb85b7f2226 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -32,7 +32,7 @@
 namespace lldb_dap {
 
 bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
-                     const llvm::ArrayRef<std::string> &commands,
+                     const llvm::ArrayRef<protocol::String> &commands,
                      llvm::raw_ostream &strm, bool parse_command_directives,
                      bool echo_commands) {
   if (commands.empty())
@@ -115,7 +115,7 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, 
llvm::StringRef prefix,
 }
 
 std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
-                            const llvm::ArrayRef<std::string> &commands,
+                            const llvm::ArrayRef<protocol::String> &commands,
                             bool &required_command_failed,
                             bool parse_command_directives, bool echo_commands) 
{
   required_command_failed = false;

diff  --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h
index daec8ca65a760..3565b398160e7 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.h
+++ b/lldb/tools/lldb-dap/LLDBUtils.h
@@ -10,6 +10,7 @@
 #define LLDB_TOOLS_LLDB_DAP_LLDBUTILS_H
 
 #include "DAPForward.h"
+#include "Protocol/ProtocolBase.h"
 #include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBEnvironment.h"
 #include "lldb/API/SBError.h"
@@ -63,7 +64,7 @@ namespace lldb_dap {
 ///     \b true, unless a command prefixed with \b ! fails and parsing of
 ///     command directives is enabled.
 bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
-                     const llvm::ArrayRef<std::string> &commands,
+                     const llvm::ArrayRef<protocol::String> &commands,
                      llvm::raw_ostream &strm, bool parse_command_directives,
                      bool echo_commands);
 
@@ -97,7 +98,7 @@ bool RunLLDBCommands(lldb::SBDebugger &debugger, 
llvm::StringRef prefix,
 ///     A std::string that contains the prefix and all commands and
 ///     command output.
 std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix,
-                            const llvm::ArrayRef<std::string> &commands,
+                            const llvm::ArrayRef<protocol::String> &commands,
                             bool &required_command_failed,
                             bool parse_command_directives = true,
                             bool echo_commands = false);

diff  --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.h 
b/lldb/tools/lldb-dap/Protocol/DAPTypes.h
index 4fc0c8db1acc8..5c5d279656d83 100644
--- a/lldb/tools/lldb-dap/Protocol/DAPTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.h
@@ -16,12 +16,12 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_DAP_TYPES_H
 #define LLDB_TOOLS_LLDB_DAP_PROTOCOL_DAP_TYPES_H
 
+#include "Protocol/ProtocolBase.h"
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-types.h"
 #include "llvm/Support/JSON.h"
 #include <cstdint>
 #include <optional>
-#include <string>
 
 namespace lldb_dap::protocol {
 
@@ -99,10 +99,10 @@ inline llvm::json::Value toJSON(const var_ref_t &var_ref) {
 /// breakpoints the path and line are the same For each session.
 struct PersistenceData {
   /// The source module path.
-  std::string module_path;
+  String module_path;
 
   /// The symbol name of the Source.
-  std::string symbol_name;
+  String symbol_name;
 };
 bool fromJSON(const llvm::json::Value &, PersistenceData &, llvm::json::Path);
 llvm::json::Value toJSON(const PersistenceData &);
@@ -145,7 +145,7 @@ struct Symbol {
   lldb::addr_t size = 0;
 
   /// The symbol name.
-  std::string name;
+  String name;
 };
 bool fromJSON(const llvm::json::Value &, Symbol &, llvm::json::Path);
 llvm::json::Value toJSON(const Symbol &);

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp 
b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
index 72359214c8537..9008719ba543d 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
@@ -57,6 +57,22 @@ bool fromJSON(const json::Value &Params, MessageType &M, 
json::Path P) {
   return true;
 }
 
+json::Value toJSON(const String &S) {
+  if (LLVM_LIKELY(llvm::json::isUTF8(std::string(S))))
+    return std::string(S);
+  return llvm::json::fixUTF8(std::string(S));
+}
+
+bool fromJSON(const llvm::json::Value &Param, String &Str,
+              llvm::json::Path Path) {
+  if (auto s = Param.getAsString()) {
+    Str = *std::move(s);
+    return true;
+  }
+  Path.report("expected string");
+  return false;
+}
+
 json::Value toJSON(const Request &R) {
   assert(R.seq != kCalculateSeq && "invalid seq");
 
@@ -124,8 +140,7 @@ json::Value toJSON(const Response &R) {
         Result.insert({"message", "notStopped"});
         break;
       }
-    } else if (const auto *messageString =
-                   std::get_if<std::string>(&*R.message)) {
+    } else if (const auto *messageString = std::get_if<String>(&*R.message)) {
       Result.insert({"message", *messageString});
     }
   }
@@ -137,8 +152,7 @@ json::Value toJSON(const Response &R) {
 }
 
 static bool fromJSON(json::Value const &Params,
-                     std::variant<ResponseMessage, std::string> &M,
-                     json::Path P) {
+                     std::variant<ResponseMessage, String> &M, json::Path P) {
   auto rawMessage = Params.getAsString();
   if (!rawMessage) {
     P.report("expected a string");
@@ -188,31 +202,46 @@ bool operator==(const Response &a, const Response &b) {
 json::Value toJSON(const ErrorMessage &EM) {
   json::Object Result{{"id", EM.id}, {"format", EM.format}};
 
-  if (EM.variables) {
+  if (!EM.variables.empty()) {
     json::Object variables;
-    for (auto &var : *EM.variables)
-      variables[var.first] = var.second;
+    for (auto &var : EM.variables)
+      variables[var.first.str()] = var.second;
     Result.insert({"variables", std::move(variables)});
   }
   if (EM.sendTelemetry)
     Result.insert({"sendTelemetry", EM.sendTelemetry});
   if (EM.showUser)
     Result.insert({"showUser", EM.showUser});
-  if (EM.url)
+  if (!EM.url.empty())
     Result.insert({"url", EM.url});
-  if (EM.urlLabel)
+  if (!EM.urlLabel.empty())
     Result.insert({"urlLabel", EM.urlLabel});
 
   return std::move(Result);
 }
 
+bool fromJSON(json::Value const &Params, std::map<String, String> &M,
+              json::Path P) {
+  const auto *const O = Params.getAsObject();
+  if (!O) {
+    P.report("expected object");
+    return false;
+  }
+  for (auto [k, v] : *O) {
+    auto str = v.getAsString();
+    if (str)
+      M[k.str()] = *std::move(str);
+  }
+  return true;
+}
+
 bool fromJSON(json::Value const &Params, ErrorMessage &EM, json::Path P) {
   json::ObjectMapper O(Params, P);
   return O && O.map("id", EM.id) && O.map("format", EM.format) &&
-         O.map("variables", EM.variables) &&
-         O.map("sendTelemetry", EM.sendTelemetry) &&
-         O.map("showUser", EM.showUser) && O.map("url", EM.url) &&
-         O.map("urlLabel", EM.urlLabel);
+         O.mapOptional("variables", EM.variables) &&
+         O.mapOptional("sendTelemetry", EM.sendTelemetry) &&
+         O.mapOptional("showUser", EM.showUser) &&
+         O.mapOptional("url", EM.url) && O.mapOptional("urlLabel", 
EM.urlLabel);
 }
 
 json::Value toJSON(const Event &E) {

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h 
b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
index 09ce6802b17c0..4f51d7785cf14 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
@@ -20,7 +20,10 @@
 #ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_BASE_H
 #define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_BASE_H
 
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/JSON.h"
+#include "llvm/Support/raw_ostream.h"
 #include <cstdint>
 #include <optional>
 #include <string>
@@ -37,10 +40,93 @@ using Id = uint64_t;
 /// the current session.
 static constexpr Id kCalculateSeq = UINT64_MAX;
 
+/// A wrapper around a 'std::string' to ensure the contents are valid utf8
+/// during serialization.
+class String {
+public:
+  String() = default;
+  String(const std::string &str) : m_str(str) {}
+  String(llvm::StringRef str) : m_str(str.str()) {}
+  String(const char *str) : m_str(str) {}
+  String(const llvm::formatv_object_base &payload) : m_str(payload.str()) {}
+  String(const String &) = default;
+  String(String &&str) : m_str(std::move(str.m_str)) {}
+  String(std::string &&str) : m_str(std::move(str)) {}
+
+  ~String() = default;
+
+  String &operator=(const String &) = default;
+  String &operator=(String &&Other) {
+    m_str = std::move(Other.m_str);
+    return *this;
+  }
+
+  /// Conversion Operators
+  /// @{
+  operator llvm::Twine() const { return m_str; }
+  operator std::string() const { return m_str; }
+  operator llvm::StringRef() const { return {m_str}; }
+  /// @}
+
+  void clear() { m_str.clear(); }
+  bool empty() const { return m_str.empty(); }
+  const char *c_str() const { return m_str.c_str(); }
+  const char *data() const { return m_str.data(); }
+  std::string str() const { return m_str; }
+
+  inline String &operator+=(const String &RHS) {
+    m_str += RHS.m_str;
+    return *this;
+  }
+
+  friend String operator+(const String &LHS, const String &RHS) {
+    return {LHS.m_str + RHS.m_str};
+  }
+
+  /// @name String Comparision Operators
+  /// @{
+
+  friend bool operator==(const String &LHS, const String &RHS) {
+    return llvm::StringRef(LHS) == llvm::StringRef(RHS);
+  }
+
+  friend bool operator!=(const String &LHS, const String &RHS) {
+    return !(LHS == RHS);
+  }
+
+  friend bool operator<(const String &LHS, const String &RHS) {
+    return llvm::StringRef(LHS) < llvm::StringRef(RHS);
+  }
+
+  friend bool operator<=(const String &LHS, const String &RHS) {
+    return llvm::StringRef(LHS) <= llvm::StringRef(RHS);
+  }
+
+  friend bool operator>(const String &LHS, const String &RHS) {
+    return llvm::StringRef(LHS) > llvm::StringRef(RHS);
+  }
+
+  friend bool operator>=(const String &LHS, const String &RHS) {
+    return llvm::StringRef(LHS) >= llvm::StringRef(RHS);
+  }
+
+  /// @}
+
+private:
+  std::string m_str;
+};
+llvm::json::Value toJSON(const String &s);
+bool fromJSON(const llvm::json::Value &, String &, llvm::json::Path);
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const String &S) {
+  OS << S.str();
+  return OS;
+}
+
 /// A client or debug adapter initiated request.
 struct Request {
   /// The command to execute.
-  std::string command;
+  String command;
 
   /// Object containing arguments for the command.
   ///
@@ -64,7 +150,7 @@ bool operator==(const Request &, const Request &);
 /// A debug adapter initiated event.
 struct Event {
   /// Type of event.
-  std::string event;
+  String event;
 
   /// Event-specific information.
   std::optional<llvm::json::Value> body = std::nullopt;
@@ -95,7 +181,7 @@ struct Response {
   Id request_seq = 0;
 
   /// The command requested.
-  std::string command;
+  String command;
 
   /// Outcome of the request. If true, the request was successful and the 
`body`
   /// attribute may contain the result of the request. If the value is false,
@@ -108,8 +194,7 @@ struct Response {
   /// Contains the raw error in short form if `success` is false. This raw 
error
   /// might be interpreted by the client and is not shown in the UI. Some
   /// predefined values exist.
-  std::optional<std::variant<ResponseMessage, std::string>> message =
-      std::nullopt;
+  std::optional<std::variant<ResponseMessage, String>> message = std::nullopt;
 
   /// Contains request result if success is true and error details if success 
is
   /// false.
@@ -144,11 +229,11 @@ struct ErrorMessage {
   /// `{name}`. If variable name starts with an underscore character, the
   /// variable does not contain user data (PII) and can be safely used for
   /// telemetry purposes.
-  std::string format;
+  String format;
 
   /// An object used as a dictionary for looking up the variables in the format
   /// string.
-  std::optional<std::map<std::string, std::string>> variables;
+  std::map<String, String> variables;
 
   /// If true send to telemetry.
   bool sendTelemetry = false;
@@ -157,10 +242,10 @@ struct ErrorMessage {
   bool showUser = false;
 
   /// A url where additional information about this message can be found.
-  std::optional<std::string> url;
+  String url;
 
   /// A label that is presented to the user as the UI for opening the url.
-  std::optional<std::string> urlLabel;
+  String urlLabel;
 };
 bool fromJSON(const llvm::json::Value &, ErrorMessage &, llvm::json::Path);
 llvm::json::Value toJSON(const ErrorMessage &);

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index faed1f8c4d574..f16d2ffcb7998 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -8,6 +8,7 @@
 
 #include "Protocol/ProtocolRequests.h"
 #include "JSONUtils.h"
+#include "Protocol/ProtocolBase.h"
 #include "Protocol/ProtocolTypes.h"
 #include "lldb/lldb-defines.h"
 #include "llvm/ADT/DenseMap.h"
@@ -21,8 +22,8 @@ using namespace llvm;
 
 // The 'env' field is either an object as a map of strings or as an array of
 // strings formatted like 'key=value'.
-static bool parseEnv(const json::Value &Params, StringMap<std::string> &env,
-                     json::Path P) {
+static bool parseEnv(const json::Value &Params,
+                     StringMap<lldb_dap::protocol::String> &env, json::Path P) 
{
   const json::Object *O = Params.getAsObject();
   if (!O) {
     P.report("expected object");
@@ -87,7 +88,8 @@ static bool parseTimeout(const json::Value &Params, 
std::chrono::seconds &S,
 
 static bool
 parseSourceMap(const json::Value &Params,
-               std::vector<std::pair<std::string, std::string>> &sourceMap,
+               std::vector<std::pair<lldb_dap::protocol::String,
+                                     lldb_dap::protocol::String>> &sourceMap,
                json::Path P) {
   const json::Object *O = Params.getAsObject();
   if (!O) {
@@ -311,7 +313,7 @@ bool fromJSON(const json::Value &Params, 
LaunchRequestArguments &LRA,
   if (!success)
     return false;
 
-  for (std::optional<std::string> &io_path : LRA.stdio) {
+  for (std::optional<String> &io_path : LRA.stdio) {
     // set empty paths to null.
     if (io_path && llvm::StringRef(*io_path).trim().empty())
       io_path.reset();

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index a8280bcdd9ee6..315f2d7b2f269 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -106,16 +106,16 @@ enum PathFormat : unsigned { ePatFormatPath, 
ePathFormatURI };
 /// Arguments for `initialize` request.
 struct InitializeRequestArguments {
   /// The ID of the debug adapter.
-  std::string adapterID;
+  String adapterID;
 
   /// The ID of the client using this adapter.
-  std::string clientID;
+  String clientID;
 
   /// The human-readable name of the client using this adapter.
-  std::string clientName;
+  String clientName;
 
   /// The ISO-639 locale of the client using this adapter, e.g. en-US or de-CH.
-  std::string locale;
+  String locale;
 
   /// Determines in what format paths are specified. The default is `path`,
   /// which is the native format.
@@ -153,7 +153,7 @@ struct Configuration {
   /// 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.
-  std::string debuggerRoot;
+  String debuggerRoot;
 
   /// Enable auto generated summaries for variables when no summaries exist for
   /// a given type. This feature can cause performance delays in large projects
@@ -180,7 +180,7 @@ struct Configuration {
   /// Console, instead of printing variables. Defaults to a backtick. If it's 
an
   /// empty string, then all expression in the Debug Console are treated as
   /// regular LLDB commands.
-  std::string commandEscapePrefix = "`";
+  String commandEscapePrefix = "`";
 
   /// If non-empty, stack frames will have descriptions generated based on the
   /// provided format. See https://lldb.llvm.org/use/formatting.html for an
@@ -189,58 +189,58 @@ struct Configuration {
   /// default frame names will be used. This might come with a performance cost
   /// because debug information might need to be processed to generate the
   /// description.
-  std::optional<std::string> customFrameFormat;
+  std::optional<String> customFrameFormat;
 
   /// Same as `customFrameFormat`, but for threads instead of stack frames.
-  std::optional<std::string> customThreadFormat;
+  std::optional<String> customThreadFormat;
 
   /// Specify a source path to remap "./" to allow full paths to be used when
   /// setting breakpoints in binaries that have relative source paths.
-  std::string sourcePath;
+  String sourcePath;
 
   /// Specify an array of path re-mappings. Each element in the array must be a
   /// two element array containing a source and destination pathname. Overrides
   /// sourcePath.
-  std::vector<std::pair<std::string, std::string>> sourceMap;
+  std::vector<std::pair<String, String>> sourceMap;
 
   /// LLDB commands executed upon debugger startup prior to creating the LLDB
   /// target.
-  std::vector<std::string> preInitCommands;
+  std::vector<String> preInitCommands;
 
   /// LLDB commands executed upon debugger startup prior to creating the LLDB
   /// target.
-  std::vector<std::string> initCommands;
+  std::vector<String> initCommands;
 
   /// LLDB commands executed just before launching/attaching, after the LLDB
   /// target has been created.
-  std::vector<std::string> preRunCommands;
+  std::vector<String> preRunCommands;
 
   /// LLDB commands executed just after launching/attaching, after the LLDB
   /// target has been created.
-  std::vector<std::string> postRunCommands;
+  std::vector<String> postRunCommands;
 
   /// LLDB commands executed just after each stop.
-  std::vector<std::string> stopCommands;
+  std::vector<String> stopCommands;
 
   /// LLDB commands executed when the program exits.
-  std::vector<std::string> exitCommands;
+  std::vector<String> exitCommands;
 
   /// LLDB commands executed when the debugging session ends.
-  std::vector<std::string> terminateCommands;
+  std::vector<String> terminateCommands;
 
   /// Path to the executable.
   ///
   /// *NOTE:* When launching, either `launchCommands` or `program` must be
   /// configured. If both are configured then `launchCommands` takes priority.
-  std::string program;
+  String program;
 
   /// Target triple for the program (arch-vendor-os). If not set, inferred from
   /// the binary.
-  std::string targetTriple;
+  String targetTriple;
 
   /// Specify name of the platform to use for this target, creating the 
platform
   /// if necessary.
-  std::string platformName;
+  String platformName;
 };
 
 enum Console : unsigned {
@@ -269,19 +269,19 @@ struct LaunchRequestArguments {
   /// *NOTE:* Either launchCommands or program must be configured.
   ///
   /// If set, takes priority over the 'program' when launching the target.
-  std::vector<std::string> launchCommands;
+  std::vector<String> launchCommands;
 
   /// The program working directory.
-  std::string cwd;
+  String cwd;
 
   /// An array of command line argument strings to be passed to the program
   /// being launched.
-  std::vector<std::string> args;
+  std::vector<String> args;
 
   /// Environment variables to set when launching the program. The format of
   /// each environment variable string is "VAR=VALUE" for environment variables
   /// with values or just "VAR" for environment variables with no values.
-  llvm::StringMap<std::string> env;
+  llvm::StringMap<String> env;
 
   /// If set, then the client stub should detach rather than killing the
   /// debuggee if it loses connection with lldb.
@@ -302,7 +302,7 @@ struct LaunchRequestArguments {
   Console console = eConsoleInternal;
 
   /// An array of file paths for redirecting the program's standard IO streams.
-  std::vector<std::optional<std::string>> stdio;
+  std::vector<std::optional<String>> stdio;
 
   /// @}
 };
@@ -341,7 +341,7 @@ struct AttachRequestArguments {
   /// to a process by name. These commands may optionally create a new target
   /// and must perform an attach. A valid process must exist after these
   /// commands complete or the `"attach"` will fail.
-  std::vector<std::string> attachCommands;
+  std::vector<String> attachCommands;
 
   /// System process ID to attach to.
   lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
@@ -355,10 +355,10 @@ struct AttachRequestArguments {
 
   /// The hostname to connect to a remote system. The default hostname being
   /// used `localhost`.
-  std::string gdbRemoteHostname = "localhost";
+  String gdbRemoteHostname = "localhost";
 
   /// Path to the core file to debug.
-  std::string coreFile;
+  String coreFile;
 
   /// An existing session that consist of a target and debugger.
   std::optional<DAPSession> session;
@@ -402,7 +402,7 @@ struct CompletionsArguments {
 
   /// One or more source lines. Typically this is the text users have typed 
into
   /// the debug console before they asked for completion.
-  std::string text;
+  String text;
 
   /// The position within `text` for which to determine the completion
   /// proposals. It is measured in UTF-16 code units and the client capability
@@ -438,10 +438,10 @@ struct SetVariableArguments {
   var_ref_t variablesReference{var_ref_t::k_invalid_var_ref};
 
   /// The name of the variable in the container.
-  std::string name;
+  String name;
 
   /// The value of the variable.
-  std::string value;
+  String value;
 
   /// Specifies details on how to format the response value.
   std::optional<ValueFormat> format;
@@ -452,11 +452,11 @@ bool fromJSON(const llvm::json::Value &, 
SetVariableArguments &,
 /// Response to `setVariable` request.
 struct SetVariableResponseBody {
   /// The new value of the variable.
-  std::string value;
+  String value;
 
   /// The type of the new value. Typically shown in the UI when hovering over
   /// the value.
-  std::string type;
+  String type;
 
   /// If `variablesReference` is > 0, the new value is structured and its
   /// children can be retrieved by passing `variablesReference` to the
@@ -527,10 +527,10 @@ bool fromJSON(const llvm::json::Value &, SourceArguments 
&, llvm::json::Path);
 /// Response to `source` request.
 struct SourceResponseBody {
   /// Content of the source reference.
-  std::string content;
+  String content;
 
   /// Content type (MIME type) of the source.
-  std::optional<std::string> mimeType;
+  std::optional<String> mimeType;
 };
 llvm::json::Value toJSON(const SourceResponseBody &);
 
@@ -732,7 +732,7 @@ struct DataBreakpointInfoArguments {
   /// The name of the variable's child to obtain data breakpoint information
   /// for. If `variablesReference` isn't specified, this can be an expression,
   /// or an address if `asAddress` is also true.
-  std::string name;
+  String name;
 
   /// When `name` is an expression, evaluate it in the scope of this stack
   /// frame. If not specified, the expression is evaluated in the global scope.
@@ -755,7 +755,7 @@ struct DataBreakpointInfoArguments {
 
   /// The mode of the desired breakpoint. If defined, this must be one of the
   /// `breakpointModes` the debug adapter advertised in its `Capabilities`.
-  std::optional<std::string> mode;
+  std::optional<String> mode;
 };
 bool fromJSON(const llvm::json::Value &, DataBreakpointInfoArguments &,
               llvm::json::Path);
@@ -770,11 +770,11 @@ struct DataBreakpointInfoResponseBody {
   /// for details. Breakpoints set using the `dataId` in the
   /// `setDataBreakpoints` request may outlive the lifetime of the associated
   /// `dataId`.
-  std::optional<std::string> dataId;
+  std::optional<String> dataId;
 
   /// UI string that describes on what data the breakpoint is set on or why a
   /// data breakpoint is not available.
-  std::string description;
+  String description;
 
   /// Attribute lists the available access types for a potential data
   /// breakpoint. A UI client could surface this information.
@@ -808,7 +808,7 @@ struct SetExceptionBreakpointsArguments {
   /// Set of exception filters specified by their ID. The set of all possible
   /// exception filters is defined by the `exceptionBreakpointFilters`
   /// capability. The `filter` and `filterOptions` sets are additive.
-  std::vector<std::string> filters;
+  std::vector<String> filters;
 
   /// Set of exception filters and their options. The set of all possible
   /// exception filters is defined by the `exceptionBreakpointFilters`
@@ -1015,7 +1015,7 @@ struct WriteMemoryArguments {
   bool allowPartial = false;
 
   /// Bytes to write, encoded using base64.
-  std::string data;
+  String data;
 };
 bool fromJSON(const llvm::json::Value &, WriteMemoryArguments &,
               llvm::json::Path);
@@ -1030,10 +1030,10 @@ llvm::json::Value toJSON(const WriteMemoryResponseBody 
&);
 
 struct ModuleSymbolsArguments {
   /// The module UUID for which to retrieve symbols.
-  std::string moduleId;
+  String moduleId;
 
   /// The module path.
-  std::string moduleName;
+  String moduleName;
 
   /// The index of the first symbol to return; if omitted, start at the
   /// beginning.
@@ -1061,10 +1061,10 @@ bool fromJSON(const llvm::json::Value &, 
ExceptionInfoArguments &,
 
 struct ExceptionInfoResponseBody {
   /// ID of the exception that was thrown.
-  std::string exceptionId;
+  String exceptionId;
 
   /// Descriptive text for the exception.
-  std::string description;
+  String description;
 
   /// Mode that caused the exception notification to be raised.
   ExceptionBreakMode breakMode = eExceptionBreakModeNever;
@@ -1097,7 +1097,7 @@ enum EvaluateContext : unsigned {
 /// Arguments for `evaluate` request.
 struct EvaluateArguments {
   /// The expression to evaluate.
-  std::string expression;
+  String expression;
 
   /// Evaluate the expression in the scope of this stack frame. If not
   /// specified, the expression is evaluated in the global scope.
@@ -1143,12 +1143,12 @@ bool fromJSON(const llvm::json::Value &, 
EvaluateArguments &, llvm::json::Path);
 /// Response to 'evaluate' request.
 struct EvaluateResponseBody {
   /// The result of the evaluate request.
-  std::string result;
+  String result;
 
   /// The type of the evaluate result.
   /// This attribute should only be returned by a debug adapter if the
   /// corresponding capability `supportsVariableType` is true.
-  std::string type;
+  String type;
 
   /// Properties of an evaluate result that can be used to determine how to
   /// render the result in the UI.
@@ -1177,7 +1177,7 @@ struct EvaluateResponseBody {
   /// memory address contained in the pointer.
   /// This attribute may be returned by a debug adapter if corresponding
   /// capability `supportsMemoryReferences` is true.
-  std::string memoryReference;
+  String memoryReference;
 
   /// A reference that allows the client to request the location where the
   /// returned value is declared. For example, if a function pointer is
@@ -1240,7 +1240,7 @@ llvm::json::Value toJSON(const LocationsResponseBody &);
 /// Arguments for `compileUnits` request.
 struct CompileUnitsArguments {
   /// The ID of the module.
-  std::string moduleId;
+  String moduleId;
 };
 bool fromJSON(const llvm::json::Value &, CompileUnitsArguments &,
               llvm::json::Path);

diff  --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h 
b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index 2a23871621cca..a50f4c85d4fff 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -21,13 +21,13 @@
 #define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_TYPES_H
 
 #include "Protocol/DAPTypes.h"
+#include "Protocol/ProtocolBase.h"
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-types.h"
 #include "llvm/ADT/DenseSet.h"
 #include "llvm/Support/JSON.h"
 #include <cstdint>
 #include <optional>
-#include <string>
 
 #define LLDB_DAP_INVALID_SRC_REF 0
 #define LLDB_DAP_INVALID_VALUE_LOC 0
@@ -40,14 +40,14 @@ namespace lldb_dap::protocol {
 struct ExceptionBreakpointsFilter {
   /// The internal ID of the filter option. This value is passed to the
   /// `setExceptionBreakpoints` request.
-  std::string filter;
+  String filter;
 
   /// The name of the filter option. This is shown in the UI.
-  std::string label;
+  String label;
 
   /// A help text providing additional information about the exception filter.
   /// This string is typically shown as a hover and can be translated.
-  std::string description;
+  String description;
 
   /// Initial value of the filter option. If not specified a value false is
   /// assumed.
@@ -59,7 +59,7 @@ struct ExceptionBreakpointsFilter {
 
   /// A help text providing information about the condition. This string is
   /// shown as the placeholder text for a text box and can be translated.
-  std::string conditionDescription;
+  String conditionDescription;
 };
 bool fromJSON(const llvm::json::Value &, ExceptionBreakpointsFilter &,
               llvm::json::Path);
@@ -81,14 +81,14 @@ llvm::json::Value toJSON(const ColumnType &);
 /// customization.
 struct ColumnDescriptor {
   /// Name of the attribute rendered in this column.
-  std::string attributeName;
+  String attributeName;
 
   /// Header UI label of column.
-  std::string label;
+  String label;
 
   /// Format to use for the rendered values in this column. TBD how the format
   /// strings looks like.
-  std::optional<std::string> format;
+  std::optional<String> format;
 
   /// Datatype of values in this column. Defaults to `string` if not specified.
   /// Values: 'string', 'number', 'boolean', 'unixTimestampUTC'.
@@ -143,19 +143,19 @@ llvm::json::Value toJSON(const CompletionItemType &);
 struct CompletionItem {
   /// The label of this completion item. By default this is also the text that
   /// is inserted when selecting this completion.
-  std::string label;
+  String label;
 
   /// If text is returned and not an empty string, then it is inserted instead
   /// of the label.
-  std::string text;
+  String text;
 
   /// A string that should be used when comparing this item with other items. 
If
   /// not returned or an empty string, the `label` is used instead.
-  std::string sortText;
+  String sortText;
 
   /// A human-readable string with additional information about this item, like
   /// type or symbol information.
-  std::string detail;
+  String detail;
 
   /// The item's type. Typically the client uses this information to render the
   /// item in the UI with an icon.
@@ -211,14 +211,14 @@ llvm::json::Value toJSON(const 
BreakpointModeApplicability &);
 struct BreakpointMode {
   /// The internal ID of the mode. This value is passed to the `setBreakpoints`
   /// request.
-  std::string mode;
+  String mode;
 
   /// The name of the breakpoint mode. This is shown in the UI.
-  std::string label;
+  String label;
 
   /// A help text providing additional information about the breakpoint mode.
   /// This string is typically shown as a hover and can be translated.
-  std::optional<std::string> description;
+  std::optional<String> description;
 
   /// Describes one or more type of breakpoint this mode applies to.
   std::vector<BreakpointModeApplicability> appliesTo;
@@ -342,7 +342,7 @@ struct Capabilities {
 
   /// The set of characters that should trigger completion in a REPL. If not
   /// specified, the UI should assume the `.` character.
-  std::vector<std::string> completionTriggerCharacters;
+  std::vector<String> completionTriggerCharacters;
 
   /// The set of additional module information exposed by the debug adapter.
   std::vector<ColumnDescriptor> additionalModuleColumns;
@@ -362,7 +362,7 @@ struct Capabilities {
   /// @{
 
   /// The version of the adapter.
-  std::string lldbExtVersion;
+  String lldbExtVersion;
 
   /// @}
 };
@@ -374,16 +374,16 @@ llvm::json::Value toJSON(const Capabilities &);
 struct ExceptionFilterOptions {
   /// ID of an exception filter returned by the `exceptionBreakpointFilters`
   /// capability.
-  std::string filterId;
+  String filterId;
 
   /// An expression for conditional exceptions.
   /// The exception breaks into the debugger if the result of the condition is
   /// true.
-  std::string condition;
+  String condition;
 
   /// The mode of this exception breakpoint. If defined, this must be one of 
the
   /// `breakpointModes` the debug adapter advertised in its `Capabilities`.
-  std::string mode;
+  String mode;
 };
 bool fromJSON(const llvm::json::Value &, ExceptionFilterOptions &,
               llvm::json::Path);
@@ -402,12 +402,12 @@ struct Source {
   /// The short name of the source. Every source returned from the debug 
adapter
   /// has a name. When sending a source to the debug adapter this name is
   /// optional.
-  std::optional<std::string> name;
+  std::optional<String> name;
 
   /// The path of the source to be shown in the UI. It is only used to locate
   /// and load the content of the source if no `sourceReference` is specified
   /// (or its value is 0).
-  std::optional<std::string> path;
+  std::optional<String> path;
 
   /// If the value > 0 the contents of the source must be retrieved through the
   /// `source` request (even if a path is specified). Since a `sourceReference`
@@ -445,7 +445,7 @@ struct Scope {
   /// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This
   /// string is shown in the UI as is and can be translated.
   ////
-  std::string name;
+  String name;
 
   /// A hint for how to present this scope in the UI. If this attribute is
   /// missing, the scope is shown with a generic UI.
@@ -530,7 +530,7 @@ struct StepInTarget {
   lldb::addr_t id = LLDB_INVALID_ADDRESS;
 
   /// The name of the step-in target (shown in the UI).
-  std::string label;
+  String label;
 
   /// The line of the step-in target.
   uint32_t line = LLDB_INVALID_LINE_NUMBER;
@@ -556,7 +556,7 @@ struct Thread {
   /// Unique identifier for the thread.
   lldb::tid_t id = LLDB_INVALID_THREAD_ID;
   /// The name of the thread.
-  std::string name;
+  String name;
 };
 bool fromJSON(const llvm::json::Value &, Thread &, llvm::json::Path);
 llvm::json::Value toJSON(const Thread &);
@@ -616,7 +616,7 @@ struct Breakpoint {
   /// A message about the state of the breakpoint.
   /// This is shown to the user and can be used to explain why a breakpoint
   /// could not be verified.
-  std::optional<std::string> message;
+  std::optional<String> message;
 
   /// The source where the breakpoint is located.
   std::optional<Source> source;
@@ -639,7 +639,7 @@ struct Breakpoint {
   std::optional<uint32_t> endColumn;
 
   /// A memory reference to where the breakpoint is set.
-  std::optional<std::string> instructionReference;
+  std::optional<String> instructionReference;
 
   /// The offset from the instruction reference.
   /// This can be negative.
@@ -667,7 +667,7 @@ struct SourceBreakpoint {
   /// The expression for conditional breakpoints.
   /// It is only honored by a debug adapter if the corresponding capability
   /// `supportsConditionalBreakpoints` is true.
-  std::optional<std::string> condition;
+  std::optional<String> condition;
 
   /// The expression that controls how many hits of the breakpoint are ignored.
   /// The debug adapter is expected to interpret the expression as needed.
@@ -676,7 +676,7 @@ struct SourceBreakpoint {
   /// If both this property and `condition` are specified, `hitCondition` 
should
   /// be evaluated only if the `condition` is met, and the debug adapter should
   /// stop only if both conditions are met.
-  std::optional<std::string> hitCondition;
+  std::optional<String> hitCondition;
 
   /// If this attribute exists and is non-empty, the debug adapter must not
   /// 'break' (stop)
@@ -685,11 +685,11 @@ struct SourceBreakpoint {
   /// capability `supportsLogPoints` is true.
   /// If either `hitCondition` or `condition` is specified, then the message
   /// should only be logged if those conditions are met.
-  std::optional<std::string> logMessage;
+  std::optional<String> logMessage;
 
   /// The mode of this breakpoint. If defined, this must be one of the
   /// `breakpointModes` the debug adapter advertised in its `Capabilities`.
-  std::optional<std::string> mode;
+  std::optional<String> mode;
 };
 bool fromJSON(const llvm::json::Value &, SourceBreakpoint &, llvm::json::Path);
 llvm::json::Value toJSON(const SourceBreakpoint &);
@@ -697,18 +697,18 @@ llvm::json::Value toJSON(const SourceBreakpoint &);
 /// Properties of a breakpoint passed to the `setFunctionBreakpoints` request.
 struct FunctionBreakpoint {
   /// The name of the function.
-  std::string name;
+  String name;
 
   /// An expression for conditional breakpoints.
   /// It is only honored by a debug adapter if the corresponding capability
   /// `supportsConditionalBreakpoints` is true.
-  std::optional<std::string> condition;
+  std::optional<String> condition;
 
   /// An expression that controls how many hits of the breakpoint are ignored.
   /// The debug adapter is expected to interpret the expression as needed.
   /// The attribute is only honored by a debug adapter if the corresponding
   /// capability `supportsHitConditionalBreakpoints` is true.
-  std::optional<std::string> hitCondition;
+  std::optional<String> hitCondition;
 };
 bool fromJSON(const llvm::json::Value &, FunctionBreakpoint &,
               llvm::json::Path);
@@ -729,17 +729,17 @@ llvm::json::Value toJSON(const DataBreakpointAccessType 
&);
 struct DataBreakpoint {
   /// An id representing the data. This id is returned from the
   /// `dataBreakpointInfo` request.
-  std::string dataId;
+  String dataId;
 
   /// The access type of the data.
   std::optional<DataBreakpointAccessType> accessType;
 
   /// An expression for conditional breakpoints.
-  std::optional<std::string> condition;
+  std::optional<String> condition;
 
   /// An expression that controls how many hits of the breakpoint are ignored.
   /// The debug adapter is expected to interpret the expression as needed.
-  std::optional<std::string> hitCondition;
+  std::optional<String> hitCondition;
 };
 bool fromJSON(const llvm::json::Value &, DataBreakpoint &, llvm::json::Path);
 llvm::json::Value toJSON(const DataBreakpoint &);
@@ -750,7 +750,7 @@ struct InstructionBreakpoint {
   /// This should be a memory or instruction pointer reference from an
   /// `EvaluateResponse`, `Variable`, `StackFrame`, `GotoTarget`, or
   /// `Breakpoint`.
-  std::string instructionReference;
+  String instructionReference;
 
   /// The offset from the instruction reference in bytes.
   /// This can be negative.
@@ -759,17 +759,17 @@ struct InstructionBreakpoint {
   /// An expression for conditional breakpoints.
   /// It is only honored by a debug adapter if the corresponding capability
   /// `supportsConditionalBreakpoints` is true.
-  std::optional<std::string> condition;
+  std::optional<String> condition;
 
   /// An expression that controls how many hits of the breakpoint are ignored.
   /// The debug adapter is expected to interpret the expression as needed.
   /// The attribute is only honored by a debug adapter if the corresponding
   /// capability `supportsHitConditionalBreakpoints` is true.
-  std::optional<std::string> hitCondition;
+  std::optional<String> hitCondition;
 
   /// The mode of this breakpoint. If defined, this must be one of the
   /// `breakpointModes` the debug adapter advertised in its `Capabilities`.
-  std::optional<std::string> mode;
+  std::optional<String> mode;
 };
 bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &,
               llvm::json::Path);
@@ -788,15 +788,15 @@ struct DisassembledInstruction {
 
   /// Raw bytes representing the instruction and its operands, in an
   /// implementation-defined format.
-  std::optional<std::string> instructionBytes;
+  std::optional<String> instructionBytes;
 
   /// Text representing the instruction and its operands, in an
   /// implementation-defined format.
-  std::string instruction;
+  String instruction;
 
   /// Name of the symbol that corresponds with the location of this 
instruction,
   /// if any.
-  std::optional<std::string> symbol;
+  std::optional<String> symbol;
 
   /// Source location that corresponds to this instruction, if any.
   /// Should always be set (if available) on the first instruction returned,
@@ -834,15 +834,15 @@ llvm::json::Value toJSON(const DisassembledInstruction &);
 
 struct Module {
   /// Unique identifier for the module.
-  std::string id;
+  String id;
 
   /// A name of the module.
-  std::string name;
+  String name;
 
   /// Logical full path to the module. The exact definition is implementation
   /// defined, but usually this would be a full path to the on-disk file for 
the
   /// module.
-  std::string path;
+  String path;
 
   /// True if the module is optimized.
   bool isOptimized = false;
@@ -852,21 +852,21 @@ struct Module {
   bool isUserCode = false;
 
   /// Version of Module.
-  std::string version;
+  String version;
 
   /// User-understandable description of if symbols were found for the module
   /// (ex: 'Symbols Loaded', 'Symbols not found', etc.)
-  std::string symbolStatus;
+  String symbolStatus;
 
   /// Logical full path to the symbol file. The exact definition is
   /// implementation defined.
-  std::string symbolFilePath;
+  String symbolFilePath;
 
   /// Module created or modified, encoded as an RFC 3339 timestamp.
-  std::string dateTimeStamp;
+  String dateTimeStamp;
 
   /// Address range covered by this module.
-  std::string addressRange;
+  String addressRange;
 
   /// Custom fields
   /// @{
@@ -883,15 +883,15 @@ llvm::json::Value toJSON(const Module &);
 struct VariablePresentationHint {
   /// The kind of variable. Before introducing additional values, try to use 
the
   /// listed values.
-  std::string kind;
+  String kind;
 
   /// Set of attributes represented as an array of strings. Before introducing
   /// additional values, try to use the listed values.
-  std::vector<std::string> attributes;
+  std::vector<String> attributes;
 
   /// Visibility of variable. Before introducing additional values, try to use
   /// the listed values.
-  std::string visibility;
+  String visibility;
 
   /// If true, clients can present the variable with a UI that supports a
   /// specific gesture to trigger its evaluation.
@@ -929,7 +929,7 @@ bool fromJSON(const llvm::json::Value &, 
VariablePresentationHint &,
 /// and fetch them in chunks.
 struct Variable {
   /// The variable's name.
-  std::string name;
+  String name;
 
   /// The variable's value.
   ///
@@ -941,14 +941,14 @@ struct Variable {
   /// its children are not yet visible.
   ///
   /// An empty string can be used if no value should be shown in the UI.
-  std::string value;
+  String value;
 
   /// The type of the variable's value. Typically shown in the UI when hovering
   /// over the value.
   ///
   /// This attribute should only be returned by a debug adapter if the
   /// corresponding capability `supportsVariableType` is true.
-  std::string type;
+  String type;
 
   /// Properties of a variable that can be used to determine how to render the
   /// variable in the UI.
@@ -956,7 +956,7 @@ struct Variable {
 
   /// The evaluatable name of this variable which can be passed to the
   /// `evaluate` request to fetch the variable's value.
-  std::string evaluateName;
+  String evaluateName;
 
   /// If `variablesReference` is > 0, the variable is structured and its
   /// children can be retrieved by passing `variablesReference` to the
@@ -1019,20 +1019,20 @@ llvm::json::Value toJSON(ExceptionBreakMode);
 
 struct ExceptionDetails {
   /// Message contained in the exception.
-  std::string message;
+  String message;
 
   /// Short type name of the exception object.
-  std::string typeName;
+  String typeName;
 
   /// Fully-qualified type name of the exception object.
-  std::string fullTypeName;
+  String fullTypeName;
 
   /// An expression that can be evaluated in the current scope to obtain the
   /// exception object.
-  std::string evaluateName;
+  String evaluateName;
 
   /// Stack trace at the time the exception was thrown.
-  std::string stackTrace;
+  String stackTrace;
 
   /// Details of the exception contained by this exception, if any.
   std::vector<ExceptionDetails> innerException;
@@ -1041,7 +1041,7 @@ llvm::json::Value toJSON(const ExceptionDetails &);
 
 struct CompileUnit {
   /// Path of compile unit.
-  std::string compileUnitPath;
+  String compileUnitPath;
 };
 llvm::json::Value toJSON(const CompileUnit &);
 
@@ -1086,7 +1086,7 @@ struct StackFrame {
   lldb::tid_t id = LLDB_DAP_INVALID_STACK_FRAME_ID;
 
   /// The name of the stack frame, typically a method name.
-  std::string name;
+  String name;
 
   /// The source of the frame.
   std::optional<Source> source;
@@ -1120,7 +1120,7 @@ struct StackFrame {
   lldb::addr_t instructionPointerReference = LLDB_INVALID_ADDRESS;
 
   /// The module associated with this frame, if any.
-  std::optional<std::string> moduleId;
+  std::optional<String> moduleId;
 
   /// A hint for how to present this frame in the UI. A value of `label` can be
   /// used to indicate that the frame is an artificial frame that is used as a

diff  --git a/lldb/tools/lldb-dap/ProtocolUtils.cpp 
b/lldb/tools/lldb-dap/ProtocolUtils.cpp
index d18c040b119da..99bd5abf0b756 100644
--- a/lldb/tools/lldb-dap/ProtocolUtils.cpp
+++ b/lldb/tools/lldb-dap/ProtocolUtils.cpp
@@ -203,10 +203,9 @@ protocol::Thread CreateThread(lldb::SBThread &thread, 
lldb::SBFormat &format) {
         queue_kind_label = " (concurrent)";
 
       name = llvm::formatv("Thread {0} Queue: {1}{2}", thread.GetIndexID(),
-                           queue_name, queue_kind_label)
-                 .str();
+                           queue_name, queue_kind_label);
     } else {
-      name = llvm::formatv("Thread {0}", thread.GetIndexID()).str();
+      name = llvm::formatv("Thread {0}", thread.GetIndexID());
     }
   }
   return protocol::Thread{thread.GetThreadID(), name};

diff  --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp 
b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index af5c743a5edf1..afbc2c7f4c28c 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -411,7 +411,7 @@ validateConnection(llvm::StringRef conn) {
 static llvm::Error serveConnection(
     const Socket::SocketProtocol &protocol, llvm::StringRef name, Log &log,
     const ReplMode default_repl_mode,
-    const std::vector<std::string> &pre_init_commands, bool no_lldbinit,
+    const std::vector<protocol::String> &pre_init_commands, bool no_lldbinit,
     std::optional<std::chrono::seconds> connection_timeout_seconds) {
   Status status;
   static std::unique_ptr<Socket> listener = Socket::Create(protocol, status);
@@ -705,7 +705,7 @@ int main(int argc, char *argv[]) {
     lldb::SBDebugger::Terminate();
   });
 
-  std::vector<std::string> pre_init_commands;
+  std::vector<protocol::String> pre_init_commands;
   for (const std::string &arg :
        input_args.getAllArgValues(OPT_pre_init_command)) {
     pre_init_commands.push_back(arg);

diff  --git a/lldb/unittests/DAP/CMakeLists.txt 
b/lldb/unittests/DAP/CMakeLists.txt
index 97f9cad7477ed..53e0fde5687ec 100644
--- a/lldb/unittests/DAP/CMakeLists.txt
+++ b/lldb/unittests/DAP/CMakeLists.txt
@@ -10,6 +10,7 @@ add_lldb_unittest(DAPTests
   Handler/ContinueTest.cpp
   JSONUtilsTest.cpp
   LLDBUtilsTest.cpp
+  ProtocolBaseTest.cpp
   ProtocolEventsTest.cpp
   ProtocolRequestsTest.cpp
   ProtocolTypesTest.cpp

diff  --git a/lldb/unittests/DAP/ProtocolBaseTest.cpp 
b/lldb/unittests/DAP/ProtocolBaseTest.cpp
new file mode 100644
index 0000000000000..b22ef916bc00a
--- /dev/null
+++ b/lldb/unittests/DAP/ProtocolBaseTest.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Protocol/ProtocolBase.h"
+#include "TestingSupport/TestUtilities.h"
+#include "llvm/Testing/Support/Error.h"
+#include <gtest/gtest.h>
+
+using namespace llvm;
+using namespace lldb_dap::protocol;
+using lldb_private::PrettyPrint;
+using llvm::json::parse;
+using llvm::json::Value;
+
+TEST(ProtocolBaseTest, SanitizedString) {
+  for (auto [input, json] : std::vector<std::pair<const char *, const char *>>{
+           {"valid str", R"("valid str")"},
+           {"lone trailing \x81\x82 bytes", R"("lone trailing οΏ½οΏ½ bytes")"}}) {
+    String str = input;
+    Expected<Value> expected_str = parse(json);
+    ASSERT_THAT_EXPECTED(expected_str, llvm::Succeeded());
+    EXPECT_EQ(PrettyPrint(*expected_str), PrettyPrint(str));
+  }
+}

diff  --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp 
b/lldb/unittests/DAP/ProtocolTypesTest.cpp
index 863fd3c4fe3a3..56ef6cdbb813f 100644
--- a/lldb/unittests/DAP/ProtocolTypesTest.cpp
+++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp
@@ -707,7 +707,7 @@ TEST(ProtocolTypesTest, SetExceptionBreakpointsArguments) {
                                   /*filterOptions=*/testing::IsEmpty())));
   EXPECT_THAT_EXPECTED(
       parse<SetExceptionBreakpointsArguments>(R"({"filters":["abc"]})"),
-      HasValue(testing::FieldsAre(/*filters=*/std::vector<std::string>{"abc"},
+      HasValue(testing::FieldsAre(/*filters=*/std::vector<String>{"abc"},
                                   /*filterOptions=*/testing::IsEmpty())));
   EXPECT_THAT_EXPECTED(
       parse<SetExceptionBreakpointsArguments>(

diff  --git a/lldb/unittests/DAP/TestBase.cpp b/lldb/unittests/DAP/TestBase.cpp
index 1afac18833a03..39634593779ad 100644
--- a/lldb/unittests/DAP/TestBase.cpp
+++ b/lldb/unittests/DAP/TestBase.cpp
@@ -41,7 +41,7 @@ void TransportBase::SetUp() {
   dap = std::make_unique<DAP>(
       /*log=*/*log,
       /*default_repl_mode=*/ReplMode::Auto,
-      /*pre_init_commands=*/std::vector<std::string>(),
+      /*pre_init_commands=*/std::vector<String>(),
       /*no_lldbinit=*/false,
       /*client_name=*/"test_client",
       /*transport=*/*to_client, /*loop=*/loop);

diff  --git a/lldb/unittests/DAP/VariablesTest.cpp 
b/lldb/unittests/DAP/VariablesTest.cpp
index 10dd567a4ecca..8a1c9ce2c502f 100644
--- a/lldb/unittests/DAP/VariablesTest.cpp
+++ b/lldb/unittests/DAP/VariablesTest.cpp
@@ -29,7 +29,8 @@ class VariablesTest : public ::testing::Test {
   VariableReferenceStorage vars;
 
   static const protocol::Scope *
-  FindScope(const std::vector<protocol::Scope> &scopes, llvm::StringRef name) {
+  FindScope(const std::vector<protocol::Scope> &scopes,
+            const protocol::String &name) {
     for (const auto &scope : scopes) {
       if (scope.name == name)
         return &scope;


        
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to