// Jackson Coxson #pragma once #include #include #include #include #include #include // Bring in the global C ABI (all C structs/functions are global) #include #include #include namespace IdeviceFFI { class DebugProxy { public: DebugProxy() = default; DebugProxy(const DebugProxy&) = delete; DebugProxy& operator=(const DebugProxy&) = delete; DebugProxy(DebugProxy&& other) noexcept : handle_(other.handle_) { other.handle_ = nullptr; } DebugProxy& operator=(DebugProxy&& other) noexcept { if (this != &other) { reset(); handle_ = other.handle_; other.handle_ = nullptr; } return *this; } ~DebugProxy() { reset(); } // Factory: connect over RSD (borrows adapter & handshake; does not consume them) static std::optional connect_rsd(Adapter& adapter, RsdHandshake& rsd, FfiError& err); // Factory: consume a ReadWrite stream (fat pointer) static std::optional from_readwrite_ptr(::ReadWriteOpaque* consumed, FfiError& err); // Convenience: consume a C++ ReadWrite wrapper by releasing it into the ABI static std::optional from_readwrite(ReadWrite&& rw, FfiError& err); // API std::optional send_command(const std::string& name, const std::vector& argv, FfiError& err); std::optional read_response(FfiError& err); bool send_raw(const std::vector& data, FfiError& err); // Reads up to `len` bytes; ABI returns a heap C string (we treat as bytes → string) std::optional read(std::size_t len, FfiError& err); // Sets argv, returns textual reply (OK/echo/etc) std::optional set_argv(const std::vector& argv, FfiError& err); bool send_ack(FfiError& err); bool send_nack(FfiError& err); // No error object in ABI; immediate effect void set_ack_mode(bool enabled) { ::debug_proxy_set_ack_mode(handle_, enabled ? 1 : 0); } ::DebugProxyHandle* raw() const { return handle_; } private: explicit DebugProxy(::DebugProxyHandle* h) : handle_(h) {} void reset() { if (handle_) { ::debug_proxy_free(handle_); handle_ = nullptr; } } ::DebugProxyHandle* handle_ = nullptr; }; // Small helper that owns a DebugserverCommandHandle class DebugCommand { public: DebugCommand() = default; DebugCommand(const DebugCommand&) = delete; DebugCommand& operator=(const DebugCommand&) = delete; DebugCommand(DebugCommand&& other) noexcept : handle_(other.handle_) { other.handle_ = nullptr; } DebugCommand& operator=(DebugCommand&& other) noexcept { if (this != &other) { reset(); handle_ = other.handle_; other.handle_ = nullptr; } return *this; } ~DebugCommand() { reset(); } static std::optional make(const std::string& name, const std::vector& argv); ::DebugserverCommandHandle* raw() const { return handle_; } private: explicit DebugCommand(::DebugserverCommandHandle* h) : handle_(h) {} void reset() { if (handle_) { ::debugserver_command_free(handle_); handle_ = nullptr; } } ::DebugserverCommandHandle* handle_ = nullptr; }; } // namespace IdeviceFFI