Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lldb/tools/lldb-dap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@ add_lldb_tool(lldb-dap
Breakpoint.cpp
BreakpointBase.cpp
DAP.cpp
DAPLog.cpp
EventHelper.cpp
ExceptionBreakpoint.cpp
FifoFiles.cpp
FunctionBreakpoint.cpp
InstructionBreakpoint.cpp
IOStream.cpp
JSONUtils.cpp
LLDBUtils.cpp
OutputRedirector.cpp
ProgressEvent.cpp
RunInTerminal.cpp
SourceBreakpoint.cpp
Transport.cpp
Protocol.cpp
Watchpoint.cpp

Handler/ResponseHandler.cpp
Expand Down
135 changes: 32 additions & 103 deletions lldb/tools/lldb-dap/DAP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
//===----------------------------------------------------------------------===//

#include "DAP.h"
#include "DAPLog.h"
#include "Handler/ResponseHandler.h"
#include "JSONUtils.h"
#include "LLDBUtils.h"
#include "OutputRedirector.h"
#include "Protocol.h"
#include "lldb/API/SBBreakpoint.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBCommandReturnObject.h"
Expand All @@ -29,6 +31,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
Expand All @@ -50,6 +53,7 @@
#endif

using namespace lldb_dap;
using namespace lldb_private;

namespace {
#ifdef _WIN32
Expand All @@ -61,11 +65,11 @@ const char DEV_NULL[] = "/dev/null";

namespace lldb_dap {

DAP::DAP(std::string name, llvm::StringRef path, std::ofstream *log,
DAP::DAP(llvm::StringRef name, llvm::StringRef path, std::ofstream *log,
lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode,
std::vector<std::string> pre_init_commands)
: name(std::move(name)), debug_adaptor_path(path), log(log),
input(std::move(input)), output(std::move(output)),
: name(name), debug_adaptor_path(path), log(log),
transport(name, std::move(input), std::move(output)),
broadcaster("lldb-dap"), exception_breakpoints(),
pre_init_commands(std::move(pre_init_commands)),
focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false),
Expand Down Expand Up @@ -237,65 +241,22 @@ void DAP::StopEventHandlers() {
}
}

// Send the JSON in "json_str" to the "out" stream. Correctly send the
// "Content-Length:" field followed by the length, followed by the raw
// JSON bytes.
void DAP::SendJSON(const std::string &json_str) {
output.write_full("Content-Length: ");
output.write_full(llvm::utostr(json_str.size()));
output.write_full("\r\n\r\n");
output.write_full(json_str);
}

// Serialize the JSON value into a string and send the JSON packet to
// the "out" stream.
void DAP::SendJSON(const llvm::json::Value &json) {
std::string json_str;
llvm::raw_string_ostream strm(json_str);
strm << json;
static std::mutex mutex;
std::lock_guard<std::mutex> locker(mutex);
SendJSON(json_str);

if (log) {
auto now = std::chrono::duration<double>(
std::chrono::system_clock::now().time_since_epoch());
*log << llvm::formatv("{0:f9} {1} <-- ", now.count(), name).str()
<< std::endl
<< "Content-Length: " << json_str.size() << "\r\n\r\n"
<< llvm::formatv("{0:2}", json).str() << std::endl;
}
}

// Read a JSON packet from the "in" stream.
std::string DAP::ReadJSON() {
std::string length_str;
std::string json_str;
int length;

if (!input.read_expected(log, "Content-Length: "))
return json_str;

if (!input.read_line(log, length_str))
return json_str;

if (!llvm::to_integer(length_str, length))
return json_str;

if (!input.read_expected(log, "\r\n"))
return json_str;

if (!input.read_full(log, length, json_str))
return json_str;

if (log) {
auto now = std::chrono::duration<double>(
std::chrono::system_clock::now().time_since_epoch());
*log << llvm::formatv("{0:f9} {1} --> ", now.count(), name).str()
<< std::endl
<< "Content-Length: " << length << "\r\n\r\n";
protocol::ProtocolMessage M;
llvm::json::Path::Root root;
if (!protocol::fromJSON(json, M, root)) {
if (log) {
std::string error;
llvm::raw_string_ostream OS(error);
root.printErrorContext(json, OS);
*log << "encoding failure: " << error << "\n";
}
}
return json_str;
auto status = transport.Write(M);
if (status.Fail() && log)
*log << "transport failure: " << status.AsCString() << "\n";
}

// "OutputEvent": {
Expand Down Expand Up @@ -720,40 +681,13 @@ void DAP::SetTarget(const lldb::SBTarget target) {
}
}

PacketStatus DAP::GetNextObject(llvm::json::Object &object) {
std::string json = ReadJSON();
if (json.empty())
return PacketStatus::EndOfFile;

llvm::StringRef json_sref(json);
llvm::Expected<llvm::json::Value> json_value = llvm::json::parse(json_sref);
if (!json_value) {
auto error = json_value.takeError();
if (log) {
std::string error_str;
llvm::raw_string_ostream strm(error_str);
strm << error;
*log << "error: failed to parse JSON: " << error_str << std::endl
<< json << std::endl;
}
return PacketStatus::JSONMalformed;
}

if (log) {
*log << llvm::formatv("{0:2}", *json_value).str() << std::endl;
}

llvm::json::Object *object_ptr = json_value->getAsObject();
if (!object_ptr) {
if (log)
*log << "error: json packet isn't a object" << std::endl;
return PacketStatus::JSONNotObject;
}
object = *object_ptr;
return PacketStatus::Success;
llvm::Expected<protocol::ProtocolMessage> DAP::GetNextObject() {
return transport.Read();
}

bool DAP::HandleObject(const llvm::json::Object &object) {
bool DAP::HandleObject(const protocol::ProtocolMessage &M) {
llvm::json::Value v = toJSON(M);
llvm::json::Object object = *v.getAsObject();
const auto packet_type = GetString(object, "type");
if (packet_type == "request") {
const auto command = GetString(object, "command");
Expand All @@ -764,9 +698,8 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
return true; // Success
}

if (log)
*log << "error: unhandled command \"" << command.data() << "\""
<< std::endl;
LLDB_LOG(GetLog(DAPLog::Protocol), "Unhandled command {0}", command);

return false; // Fail
}

Expand Down Expand Up @@ -805,6 +738,8 @@ bool DAP::HandleObject(const llvm::json::Object &object) {
return true;
}

LLDB_LOG(GetLog(DAPLog::Protocol), "Unsupported protocol message");

return false;
}

Expand Down Expand Up @@ -858,19 +793,13 @@ lldb::SBError DAP::Disconnect(bool terminateDebuggee) {
llvm::Error DAP::Loop() {
auto cleanup = llvm::make_scope_exit([this]() { StopEventHandlers(); });
while (!disconnecting) {
llvm::json::Object object;
lldb_dap::PacketStatus status = GetNextObject(object);

if (status == lldb_dap::PacketStatus::EndOfFile) {
break;
}
auto next = GetNextObject();

if (status != lldb_dap::PacketStatus::Success) {
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"failed to send packet");
if (!next) {
return next.takeError();
}

if (!HandleObject(object)) {
if (!HandleObject(*next)) {
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"unhandled packet");
}
Expand Down
17 changes: 8 additions & 9 deletions lldb/tools/lldb-dap/DAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
#include "FunctionBreakpoint.h"
#include "Handler/RequestHandler.h"
#include "Handler/ResponseHandler.h"
#include "IOStream.h"
#include "InstructionBreakpoint.h"
#include "OutputRedirector.h"
#include "ProgressEvent.h"
#include "Protocol.h"
#include "SourceBreakpoint.h"
#include "Transport.h"
#include "lldb/API/SBBroadcaster.h"
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBDebugger.h"
Expand All @@ -39,6 +40,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Threading.h"
#include <fstream>
#include <map>
#include <memory>
#include <mutex>
Expand Down Expand Up @@ -145,11 +147,10 @@ struct SendEventRequestHandler : public lldb::SBCommandPluginInterface {
};

struct DAP {
std::string name;
llvm::StringRef name;
llvm::StringRef debug_adaptor_path;
std::ofstream *log;
InputStream input;
OutputStream output;
Transport transport;
lldb::SBFile in;
OutputRedirector out;
OutputRedirector err;
Expand Down Expand Up @@ -210,7 +211,7 @@ struct DAP {
// will contain that expression.
std::string last_nonempty_var_expression;

DAP(std::string name, llvm::StringRef path, std::ofstream *log,
DAP(llvm::StringRef name, llvm::StringRef path, std::ofstream *log,
lldb::IOObjectSP input, lldb::IOObjectSP output, ReplMode repl_mode,
std::vector<std::string> pre_init_commands);
~DAP();
Expand All @@ -233,8 +234,6 @@ struct DAP {
// the "out" stream.
void SendJSON(const llvm::json::Value &json);

std::string ReadJSON();

void SendOutput(OutputType o, const llvm::StringRef output);

void SendProgressEvent(uint64_t progress_id, const char *message,
Expand Down Expand Up @@ -307,8 +306,8 @@ struct DAP {
/// listeing for its breakpoint events.
void SetTarget(const lldb::SBTarget target);

PacketStatus GetNextObject(llvm::json::Object &object);
bool HandleObject(const llvm::json::Object &object);
llvm::Expected<protocol::ProtocolMessage> GetNextObject();
bool HandleObject(const protocol::ProtocolMessage &);

/// Disconnect the DAP session.
lldb::SBError Disconnect();
Expand Down
20 changes: 20 additions & 0 deletions lldb/tools/lldb-dap/DAPLog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#include "DAPLog.h"

using namespace lldb_private;
using namespace lldb_dap;

static constexpr Log::Category g_categories[] = {
{{"transport"}, {"log DAP transport"}, DAPLog::Transport},
{{"protocol"}, {"log protocol handling"}, DAPLog::Protocol},
};

static Log::Channel g_log_channel(g_categories,
DAPLog::Transport | DAPLog::Protocol);

template <> Log::Channel &lldb_private::LogChannelFor<DAPLog>() {
return g_log_channel;
}

void lldb_dap::InitializeDAPChannel() {
Log::Register("lldb-dap", g_log_channel);
}
33 changes: 33 additions & 0 deletions lldb/tools/lldb-dap/DAPLog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//===-- DAPLog.h ------------------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_UTILITY_LLDBLOG_H
#define LLDB_UTILITY_LLDBLOG_H

#include "lldb/Utility/Log.h"
#include "llvm/ADT/BitmaskEnum.h"

namespace lldb_dap {

enum class DAPLog : lldb_private::Log::MaskType {
Transport = lldb_private::Log::ChannelFlag<0>,
Protocol = lldb_private::Log::ChannelFlag<1>,
LLVM_MARK_AS_BITMASK_ENUM(Protocol),
};

LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();

void InitializeDAPChannel();

} // end namespace lldb_dap

namespace lldb_private {
template <> lldb_private::Log::Channel &LogChannelFor<lldb_dap::DAPLog>();
} // namespace lldb_private

#endif
Loading