|
11 | 11 | #include "JSONUtils.h" |
12 | 12 | #include "LLDBUtils.h" |
13 | 13 | #include "OutputRedirector.h" |
| 14 | +#include "Transport.h" |
14 | 15 | #include "lldb/API/SBBreakpoint.h" |
15 | 16 | #include "lldb/API/SBCommandInterpreter.h" |
16 | 17 | #include "lldb/API/SBCommandReturnObject.h" |
@@ -64,8 +65,8 @@ namespace lldb_dap { |
64 | 65 | DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log, |
65 | 66 | lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode, |
66 | 67 | std::vector<std::string> pre_init_commands) |
67 | | - : name(std::move(name)), debug_adapter_path(path), log(log), |
68 | | - input(std::move(input)), output(std::move(output)), |
| 68 | + : client_name(std::move(name)), debug_adapter_path(path), log(log), |
| 69 | + transport(client_name, std::move(input), std::move(output)), |
69 | 70 | broadcaster("lldb-dap"), exception_breakpoints(), |
70 | 71 | pre_init_commands(std::move(pre_init_commands)), |
71 | 72 | focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), |
@@ -219,65 +220,27 @@ void DAP::StopEventHandlers() { |
219 | 220 | } |
220 | 221 | } |
221 | 222 |
|
222 | | -// Send the JSON in "json_str" to the "out" stream. Correctly send the |
223 | | -// "Content-Length:" field followed by the length, followed by the raw |
224 | | -// JSON bytes. |
225 | | -void DAP::SendJSON(const std::string &json_str) { |
226 | | - output.write_full("Content-Length: "); |
227 | | - output.write_full(llvm::utostr(json_str.size())); |
228 | | - output.write_full("\r\n\r\n"); |
229 | | - output.write_full(json_str); |
230 | | -} |
231 | | - |
232 | 223 | // Serialize the JSON value into a string and send the JSON packet to |
233 | 224 | // the "out" stream. |
234 | 225 | void DAP::SendJSON(const llvm::json::Value &json) { |
235 | | - std::string json_str; |
236 | | - llvm::raw_string_ostream strm(json_str); |
237 | | - strm << json; |
238 | | - static std::mutex mutex; |
239 | | - std::lock_guard<std::mutex> locker(mutex); |
240 | | - SendJSON(json_str); |
241 | | - |
242 | | - if (log) { |
243 | | - auto now = std::chrono::duration<double>( |
244 | | - std::chrono::system_clock::now().time_since_epoch()); |
245 | | - *log << llvm::formatv("{0:f9} {1} <-- ", now.count(), name).str() |
246 | | - << std::endl |
247 | | - << "Content-Length: " << json_str.size() << "\r\n\r\n" |
248 | | - << llvm::formatv("{0:2}", json).str() << std::endl; |
249 | | - } |
250 | | -} |
251 | | - |
252 | | -// Read a JSON packet from the "in" stream. |
253 | | -std::string DAP::ReadJSON() { |
254 | | - std::string length_str; |
255 | | - std::string json_str; |
256 | | - int length; |
257 | | - |
258 | | - if (!input.read_expected(log, "Content-Length: ")) |
259 | | - return json_str; |
260 | | - |
261 | | - if (!input.read_line(log, length_str)) |
262 | | - return json_str; |
263 | | - |
264 | | - if (!llvm::to_integer(length_str, length)) |
265 | | - return json_str; |
266 | | - |
267 | | - if (!input.read_expected(log, "\r\n")) |
268 | | - return json_str; |
269 | | - |
270 | | - if (!input.read_full(log, length, json_str)) |
271 | | - return json_str; |
272 | | - |
273 | | - if (log) { |
274 | | - auto now = std::chrono::duration<double>( |
275 | | - std::chrono::system_clock::now().time_since_epoch()); |
276 | | - *log << llvm::formatv("{0:f9} {1} --> ", now.count(), name).str() |
277 | | - << std::endl |
278 | | - << "Content-Length: " << length << "\r\n\r\n"; |
| 226 | + // FIXME: Instead of parsing the output message from JSON, pass the `Message` |
| 227 | + // as parameter to `SendJSON`. |
| 228 | + protocol::Message M; |
| 229 | + llvm::json::Path::Root root; |
| 230 | + if (!protocol::fromJSON(json, M, root)) { |
| 231 | + if (log) { |
| 232 | + std::string error; |
| 233 | + llvm::raw_string_ostream OS(error); |
| 234 | + root.printErrorContext(json, OS); |
| 235 | + *log << "encoding failure: " << error << "\n"; |
| 236 | + } |
| 237 | + return; |
279 | 238 | } |
280 | | - return json_str; |
| 239 | + auto status = transport.Write(log, M); |
| 240 | + if (status.Fail() && log) |
| 241 | + *log << llvm::formatv("failed to send {0}: {1}\n", llvm::json::Value(M), |
| 242 | + status.AsCString()) |
| 243 | + .str(); |
281 | 244 | } |
282 | 245 |
|
283 | 246 | // "OutputEvent": { |
@@ -704,36 +667,10 @@ void DAP::SetTarget(const lldb::SBTarget target) { |
704 | 667 | } |
705 | 668 | } |
706 | 669 |
|
707 | | -PacketStatus DAP::GetNextObject(llvm::json::Object &object) { |
708 | | - std::string json = ReadJSON(); |
709 | | - if (json.empty()) |
710 | | - return PacketStatus::EndOfFile; |
711 | | - |
712 | | - llvm::StringRef json_sref(json); |
713 | | - llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref); |
714 | | - if (auto error = json_value.takeError()) { |
715 | | - std::string error_str = llvm::toString(std::move(error)); |
716 | | - if (log) |
717 | | - *log << "error: failed to parse JSON: " << error_str << std::endl |
718 | | - << json << std::endl; |
719 | | - return PacketStatus::JSONMalformed; |
720 | | - } |
721 | | - |
722 | | - if (log) { |
723 | | - *log << llvm::formatv("{0:2}", *json_value).str() << std::endl; |
724 | | - } |
725 | | - |
726 | | - llvm::json::Object *object_ptr = json_value->getAsObject(); |
727 | | - if (!object_ptr) { |
728 | | - if (log) |
729 | | - *log << "error: json packet isn't a object" << std::endl; |
730 | | - return PacketStatus::JSONNotObject; |
731 | | - } |
732 | | - object = *object_ptr; |
733 | | - return PacketStatus::Success; |
734 | | -} |
735 | | - |
736 | | -bool DAP::HandleObject(const llvm::json::Object &object) { |
| 670 | +bool DAP::HandleObject(const protocol::Message &M) { |
| 671 | + // FIXME: Directly handle `Message` instead of serializing to JSON. |
| 672 | + llvm::json::Value v = toJSON(M); |
| 673 | + llvm::json::Object object = *v.getAsObject(); |
737 | 674 | const auto packet_type = GetString(object, "type"); |
738 | 675 | if (packet_type == "request") { |
739 | 676 | const auto command = GetString(object, "command"); |
@@ -838,19 +775,16 @@ llvm::Error DAP::Loop() { |
838 | 775 | StopEventHandlers(); |
839 | 776 | }); |
840 | 777 | while (!disconnecting) { |
841 | | - llvm::json::Object object; |
842 | | - lldb_dap::PacketStatus status = GetNextObject(object); |
843 | | - |
844 | | - if (status == lldb_dap::PacketStatus::EndOfFile) { |
845 | | - break; |
846 | | - } |
847 | | - |
848 | | - if (status != lldb_dap::PacketStatus::Success) { |
849 | | - return llvm::createStringError(llvm::inconvertibleErrorCode(), |
850 | | - "failed to send packet"); |
| 778 | + auto next = transport.Read(log); |
| 779 | + if (auto Err = next.takeError()) { |
| 780 | + // On EOF, simply break out of the loop. |
| 781 | + std::error_code ec = llvm::errorToErrorCode(std::move(Err)); |
| 782 | + if (ec == Transport::kEOF) |
| 783 | + break; |
| 784 | + return llvm::errorCodeToError(ec); |
851 | 785 | } |
852 | 786 |
|
853 | | - if (!HandleObject(object)) { |
| 787 | + if (!HandleObject(*next)) { |
854 | 788 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
855 | 789 | "unhandled packet"); |
856 | 790 | } |
|
0 commit comments