blob: 432f128ba5331a565356f4d9547459db8fcfad03 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_DEBUG_ADAPTER_CONTEXT_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_DEBUG_ADAPTER_CONTEXT_H_
#include <cstdint>
#include <utility>
#include <dap/protocol.h>
#include <dap/session.h>
#include "src/developer/debug/shared/stream_buffer.h"
#include "src/developer/debug/zxdb/client/frame.h"
#include "src/developer/debug/zxdb/client/process_observer.h"
#include "src/developer/debug/zxdb/client/session.h"
#include "src/developer/debug/zxdb/client/thread_observer.h"
#include "src/developer/debug/zxdb/common/err.h"
#include "src/developer/debug/zxdb/expr/format_node.h"
#include "src/lib/fxl/memory/weak_ptr.h"
namespace zxdb {
class Session;
class Breakpoint;
class DebugAdapterServer;
class DebugAdapterReader;
class DebugAdapterWriter;
// Types of variables reported in variables request.
enum class VariablesType {
kLocal = 0,
kArguments,
kRegister,
kChildVariable,
kVariablesTypeCount, // Keep this in the end always
};
struct VariablesRecord {
int64_t frame_id;
VariablesType type = VariablesType::kVariablesTypeCount;
// Fields to store children information corresponding to the record so that subsequent variables
// request can be processed. Store the format node in `parent` if children exist. If `parent`'s
// child has children, store a weak pointer to it in `child`.
std::unique_ptr<FormatNode> parent;
fxl::WeakPtr<FormatNode> child;
};
// Handles processing requests from debug adapter client with help from zxdb client session and dap
// library.
// Note: All methods in this class need to be executed on main thread to avoid concurrency bugs.
class DebugAdapterContext : public ThreadObserver, ProcessObserver {
public:
using DestroyConnectionCallback = std::function<void()>;
explicit DebugAdapterContext(Session* session, debug::StreamBuffer* stream);
virtual ~DebugAdapterContext();
Session* session() { return session_; }
dap::Session& dap() { return *dap_; }
bool supports_run_in_terminal() { return supports_run_in_terminal_; }
// Notification about the stream.
void OnStreamReadable();
// Callback to delete the connection and hence this context. This callback will be posted on
// message loop.
void set_destroy_connection_callback(DestroyConnectionCallback cb) {
destroy_connection_cb_ = std::move(cb);
}
// ThreadObserver implementation:
void DidCreateThread(Thread* thread) override;
void WillDestroyThread(Thread* thread) override;
void OnThreadStopped(Thread* thread, const StopInfo& info) override;
void OnThreadFramesInvalidated(Thread* thread) override;
// ProcessObserver implementation:
void DidCreateProcess(Process* process, bool autoattached_to_new_process,
uint64_t timestamp) override;
void WillDestroyProcess(Process* process, DestroyReason reason, int exit_code,
uint64_t timestamp) override;
Thread* GetThread(uint64_t koid);
// Checks if thread is in stopped state; returns error if not stopped.
// `thread` can be nullptr, in which case an error is returned.
Err CheckStoppedThread(Thread* thread);
// Helper methods to get/set frame to ID mapping
int64_t IdForFrame(Frame* frame, int stack_index);
Frame* FrameforId(int64_t id);
void DeleteFrameIdsForThread(Thread* thread);
// Helper methods to get/set variables references
int64_t IdForVariables(int64_t frame_id, VariablesType type,
std::unique_ptr<FormatNode> parent = nullptr,
fxl::WeakPtr<FormatNode> child = nullptr);
VariablesRecord* VariablesRecordForID(int64_t id);
void DeleteVariablesIdsForFrameId(int64_t id);
// Helper methods to get/set breakpoint to source file mapping.
void StoreBreakpointForSource(const std::string& source, Breakpoint* bp);
std::vector<fxl::WeakPtr<Breakpoint>>* GetBreakpointsForSource(const std::string& source);
// TODO(fxbug.dev/69392): These 2 method deletes all breakpoints added by the debug adapter.
// Breakpoints added from console are not deleted.
void DeleteBreakpointsForSource(const std::string& source);
void DeleteAllBreakpoints();
private:
Session* const session_;
const std::unique_ptr<dap::Session> dap_;
std::shared_ptr<DebugAdapterReader> reader_;
std::shared_ptr<DebugAdapterWriter> writer_;
bool supports_run_in_terminal_ = false;
bool supports_invalidate_event_ = false;
bool init_done_ = false;
struct FrameRecord {
uint64_t thread_koid = 0;
int stack_index = 0;
};
std::map<int64_t, FrameRecord> id_to_frame_;
int64_t next_frame_id_ = 1;
std::map<int64_t, VariablesRecord> id_to_variables_;
int64_t next_variables_id_ = 1;
DestroyConnectionCallback destroy_connection_cb_;
// This mapping is temporarily added to store all breakpoints added by debug adapter client. Once
// http://fxbug.dev/69392 is fixed, this can removed in favor of using System::GetBreakpoints API
// i.e. with breakpoint event, debug adapter client can be made aware of additional breakpoints
// (from say zxdb console) and hence breakpoint list maintained by system will be identical to
// this map in terms of the entries. One could traverse the entire system breakpoint list to get
// breakpoints related to a source file instead of having to maintain a separate map.
std::map<std::string, std::vector<fxl::WeakPtr<Breakpoint>>> source_to_bp_;
void Init();
};
class DebugAdapterReader : public dap::Reader {
public:
explicit DebugAdapterReader(debug::StreamBuffer* stream) : stream_(stream) {}
size_t read(void* buffer, size_t n) override {
if (!stream_) {
return 0;
}
auto ret = stream_->Read(static_cast<char*>(buffer), n);
return ret;
}
bool isOpen() override { return !!stream_; }
void close() override { stream_ = nullptr; }
private:
debug::StreamBuffer* stream_ = nullptr;
};
class DebugAdapterWriter : public dap::Writer {
public:
explicit DebugAdapterWriter(debug::StreamBuffer* stream) : stream_(stream) {}
bool write(const void* buffer, size_t n) override {
if (!stream_) {
return false;
}
stream_->Write(
std::vector<char>(static_cast<const char*>(buffer), static_cast<const char*>(buffer) + n));
return true;
}
bool isOpen() override { return !!stream_; }
void close() override { stream_ = nullptr; }
private:
debug::StreamBuffer* stream_ = nullptr;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_DEBUG_ADAPTER_CONTEXT_H_