blob: 60d2f36e06e06872736dcf9946cfe003107806cc [file] [log] [blame]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_MLIR_EDGE_IREE_VM_DEBUG_DEBUG_CLIENT_H_
#define THIRD_PARTY_MLIR_EDGE_IREE_VM_DEBUG_DEBUG_CLIENT_H_
#include <functional>
#include <memory>
#include "third_party/absl/container/flat_hash_map.h"
#include "third_party/absl/strings/string_view.h"
#include "third_party/absl/types/optional.h"
#include "third_party/absl/types/span.h"
#include "third_party/mlir_edge/iree/base/status.h"
#include "third_party/mlir_edge/iree/schemas/debug_service_generated.h"
namespace iree {
namespace vm {
namespace debug {
// Remote breakpoint currently active on the server.
class RemoteBreakpoint {
public:
enum class Type {
kBytecodeFunction = 0,
kNativeFunction = 1,
};
virtual ~RemoteBreakpoint() = default;
int id() const { return id_; }
Type type() const { return type_; }
virtual const std::string& module_name() const = 0;
virtual const std::string& function_name() const = 0;
virtual int function_ordinal() const = 0;
virtual int bytecode_offset() const = 0;
protected:
explicit RemoteBreakpoint(int id, Type type) : id_(id), type_(type) {}
private:
int id_;
Type type_;
};
class RemoteModule;
class RemoteFunction {
public:
virtual ~RemoteFunction() = default;
RemoteModule* module() const { return module_; }
int ordinal() const { return function_ordinal_; }
virtual const std::string& name() const = 0;
virtual const FunctionDef& def() = 0;
virtual bool is_loaded() const = 0;
virtual bool CheckLoadedOrRequest() = 0;
using LoadCallback = std::function<void(StatusOr<RemoteFunction*>)>;
virtual void WhenLoaded(LoadCallback callback) = 0;
virtual const BytecodeDef* bytecode() = 0;
protected:
RemoteFunction(RemoteModule* module, int function_ordinal)
: module_(module), function_ordinal_(function_ordinal) {}
RemoteModule* module_;
int function_ordinal_;
};
class RemoteModule {
public:
virtual ~RemoteModule() = default;
int context_id() const { return context_id_; }
const std::string& name() const { return name_; }
virtual const ModuleDef& def() = 0;
virtual bool is_loaded() const = 0;
virtual bool CheckLoadedOrRequest() = 0;
using LoadCallback = std::function<void(StatusOr<RemoteModule*>)>;
virtual void WhenLoaded(LoadCallback callback) = 0;
virtual absl::Span<RemoteFunction*> functions() = 0;
protected:
RemoteModule(int context_id, std::string name)
: context_id_(context_id), name_(std::move(name)) {}
private:
int context_id_;
std::string name_;
};
class RemoteContext {
public:
virtual ~RemoteContext() = default;
int id() const { return id_; }
virtual absl::Span<RemoteModule* const> modules() const = 0;
protected:
explicit RemoteContext(int id) : id_(id) {}
private:
int id_;
};
class RemoteFiberState {
public:
virtual ~RemoteFiberState() = default;
int id() const { return id_; }
const std::string& name() const { return name_; }
virtual const rpc::FiberStateDefT& def() const = 0;
protected:
explicit RemoteFiberState(int id)
: id_(id), name_(absl::StrCat("Fiber ", id)) {}
private:
int id_;
std::string name_;
};
// Debugger RPC server client.
// Statefully tracks a DebugServer to provide common client operations and
// memoized queries.
//
// Thread-compatible. Do not use the client from multiple threads concurrently.
// All remote updates of local state are performed by the Poll function. See
// Poll for more details.
class DebugClient {
public:
// Debug event listener interface.
// Event methods will be called from within Poll calls (so on that thread).
//
// When the server posts an event it will mark the client as unready and
// suspend execution of all fibers until MakeReady is used to indicate that
// the client is ready for the server to resume. Each event needs a matching
// MakeReady ack.
//
// Listeners can defer acking if they need to perform additional queries or
// state changes to the server or wait for user interaction. Multiple events
// may come in while unready if there was a series of events pending on the
// server.
class Listener {
public:
virtual ~Listener() = default;
// Signals that a context has been registered on the server.
virtual Status OnContextRegistered(const RemoteContext& context) = 0;
virtual Status OnContextUnregistered(const RemoteContext& context) = 0;
// Signals that a module has been loaded into a context on the server.
virtual Status OnModuleLoaded(const RemoteContext& context,
const RemoteModule& module) = 0;
// Signals that a fiber has been registered on the server.
virtual Status OnFiberRegistered(const RemoteFiberState& fiber_state) = 0;
virtual Status OnFiberUnregistered(const RemoteFiberState& fiber_state) = 0;
// Signals that a breakpoint has been hit by a fiber on the server.
virtual Status OnBreakpointHit(const RemoteBreakpoint& breakpoint,
const RemoteFiberState& fiber_state) = 0;
};
// Connects to a remote debug service at the provided IP:port.
// The specified |listener| will receive async event notifications.
static StatusOr<std::unique_ptr<DebugClient>> Connect(
absl::string_view service_address, Listener* listener);
virtual ~DebugClient() = default;
// Returns true if the client is connected to a service.
// virtual bool is_connected() const = 0;
// A list of all contexts registered with the server.
virtual absl::Span<RemoteContext* const> contexts() const = 0;
// A list of all fibers registered with the server.
virtual absl::Span<RemoteFiberState* const> fiber_states() const = 0;
// A list of all breakpoints registered with the server.
virtual absl::Span<RemoteBreakpoint* const> breakpoints() const = 0;
// Resolves a function to a module ordinal.
// This will occur asynchronously and the |callback| will be issued on the
// polling thread.
virtual Status ResolveFunction(
std::string module_name, std::string function_name,
std::function<void(StatusOr<int> function_ordinal)> callback) = 0;
// Gets a function body instance.
// The provided |callback| will be issued on the polling thread when the
// function is available.
virtual Status GetFunction(
std::string module_name, int function_ordinal,
std::function<void(StatusOr<RemoteFunction*> function)> callback) = 0;
Status GetFunction(
std::string module_name, std::string function_name,
std::function<void(StatusOr<RemoteFunction*> function)> callback);
// Adds a breakpoint for the given module:function:offset.
// The breakpoint will apply to all contexts with the module loaded.
virtual Status AddFunctionBreakpoint(
std::string module_name, std::string function_name, int offset,
std::function<void(const RemoteBreakpoint& breakpoint)> callback =
nullptr) = 0;
// Removes a breakpoint from the server.
virtual Status RemoveBreakpoint(const RemoteBreakpoint& breakpoint) = 0;
// Notifies the server that the debug session is ready to continue.
// This must be called once on connection to and in acknowledgement to any
// events posted by the server (read: any call to the Listener::On* methods).
virtual Status MakeReady() = 0;
// Suspends all fibers running on the server.
virtual Status SuspendAllFibers() = 0;
// Resumes all fibers running on the server.
virtual Status ResumeAllFibers() = 0;
// Suspends a list of fibers running on the server. Fibers not in the provided
// list will not be suspended, such as new fibers created while the request
// is pending.
virtual Status SuspendFibers(absl::Span<RemoteFiberState*> fibers) = 0;
// Resumes a list of fibers running on the server.
virtual Status ResumeFibers(absl::Span<RemoteFiberState*> fibers) = 0;
// Steps a fiber one bytecode operation.
virtual Status StepFiber(const RemoteFiberState& fiber_state,
std::function<void()> callback) = 0;
// Steps a fiber over one bytecode operation, not stopping until it completes.
Status StepFiberOver(const RemoteFiberState& fiber_state,
std::function<void()> callback);
// Steps a fiber out of the current block.
Status StepFiberOut(const RemoteFiberState& fiber_state,
std::function<void()> callback);
// Steps a fiber to a specific bytecode offset within the current function.
virtual Status StepFiberToOffset(const RemoteFiberState& fiber_state,
int bytecode_offset,
std::function<void()> callback) = 0;
// TODO(benvanik): profiling modes.
// Polls for the current state of the debug service and processes incoming
// responses. Must be called as frequently as the UI is desired to update.
// Returns CancelledError when the service is being shutdown/disconnected.
//
// Events on the Listener will be called from within this method.
virtual Status Poll() = 0;
};
} // namespace debug
} // namespace vm
} // namespace iree
#endif // THIRD_PARTY_MLIR_EDGE_IREE_VM_DEBUG_DEBUG_CLIENT_H_