diff --git a/lldb/source/Plugins/Platform/OHOS/HdcClient.cpp b/lldb/source/Plugins/Platform/OHOS/HdcClient.cpp index eef720eaf78bc0527e5170fda08403647d132c3c..679b821f2d0826276ff1e1f217c2566faf3ef84e 100644 --- a/lldb/source/Plugins/Platform/OHOS/HdcClient.cpp +++ b/lldb/source/Plugins/Platform/OHOS/HdcClient.cpp @@ -8,14 +8,17 @@ #include "HdcClient.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/PosixApi.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataEncoder.h" @@ -34,9 +37,13 @@ #include #include +#include #include #include +#include +#include #include +#include // On Windows, transitive dependencies pull in , which defines a // macro that clashes with a method name. @@ -121,11 +128,13 @@ Status HdcClient::CreateByDeviceID(const std::string &device_id, return error; } -HdcClient::HdcClient() {} +HdcClient::HdcClient(const std::string &connect_addr, + const std::string &device_id) + : m_connect_addr(connect_addr), m_device_id(device_id) {} -HdcClient::HdcClient(const std::string &device_id) : m_device_id(device_id) {} +HdcClient::HdcClient(HdcClient &&) = default; -HdcClient::~HdcClient() {} +HdcClient::~HdcClient() = default; void HdcClient::SetDeviceID(const std::string &device_id) { m_device_id = device_id; @@ -133,6 +142,10 @@ void HdcClient::SetDeviceID(const std::string &device_id) { const std::string &HdcClient::GetDeviceID() const { return m_device_id; } +bool HdcClient::IsServerLocal() { + return m_connect_addr == "localhost"; +} + namespace { typedef unsigned msg_len_t; struct ChannelHandShake { @@ -163,8 +176,9 @@ Status HdcClient::Connect() { return Status("invalid port specification: %s. $OHOS_HDC_SERVER_PORT must be a positive number in (0,65535]", env_port); } } - - std::string uri = "connect://localhost:" + port; + + // Support remote HDC server by providing connection address explicitly + std::string uri = "connect://" + m_connect_addr + ":" + port; m_conn->Connect(uri.c_str(), &error); ConnectionStatus status = eConnectionStatusError; if (error.Success()) { @@ -265,8 +279,8 @@ Status HdcClient::DeletePortForwarding(const uint16_t local_port, return ReadResponseStatus("Remove forward ruler success"); } -Status HdcClient::TransferFile(const char *direction, const FileSpec &src, - const FileSpec &dst) { +Status HdcClient::LocalTransferFile(const char *direction, const FileSpec &src, + const FileSpec &dst) { LLDB_MODULE_TIMER(LLDBPerformanceTagName::TAG_HDC); // OHOS_LOCAL llvm::SmallVector cwd; std::error_code ec = llvm::sys::fs::current_path(cwd); @@ -284,12 +298,459 @@ Status HdcClient::TransferFile(const char *direction, const FileSpec &src, return ReadResponseStatus("FileTransfer finish"); } +Status HdcClient::ExpectCommandMessagePrefix(uint16_t expected_command, + std::vector &message, + size_t prefix_size) { + uint16_t command; + Status error = ReadCommandMessagePrefix(command, message, prefix_size); + if (error.Fail()) + return error; + if (command != expected_command) + return Status("Unexpected HDC server command: %d, expected %d", command, + expected_command); + + return error; +} + +Status HdcClient::ExpectCommandMessage(uint16_t expected_command, + std::vector &message) { + return ExpectCommandMessagePrefix(expected_command, message, + std::numeric_limits::max()); +} + +template struct HdcIO; + +struct HdcTagIO { + enum class WireType : uint32_t { VARINT = 0, LENGTH_DELIMETED = 2 }; + + template + static llvm::Optional> ParseTag(InItT &InBegin, + InItT InEnd) { + llvm::Optional Tag = HdcIO::Parse(InBegin, InEnd); + return Tag.map([](U Val) { + return std::make_pair(static_cast(Val >> 3), + static_cast(Val & 0x7)); + }); + } + + template + static void SerializeTag(size_t Idx, WireType Type, OutItT &OutIt) { + HdcIO::Serialize( + static_cast(Type) | (static_cast(Idx) << 3), OutIt); + } +}; + +template +struct HdcIOBase { + using ValueT = T; + + static HdcTagIO::WireType GetWireType() { return TheType; } + + template + static llvm::Optional ParseTagged(size_t Idx, InItT &InBegin, + InItT InEnd) { + if (!HdcTagIO::ParseTag(InBegin, InEnd) + .map([Idx](auto P) { + return P.first == Idx && P.second == TheType; + }) + .value_or(false)) + return {}; + return DerivedT::Parse(InBegin, InEnd); + } + + template + static void SerializeTagged(size_t Idx, T Value, OutItT &OutIt) { + HdcTagIO::SerializeTag(Idx, TheType, OutIt); + DerivedT::Serialize(Value, OutIt); + } +}; + +template +struct HdcIO : HdcIOBase> { + static_assert(std::is_integral::value, "Don't know how to parse T"); + + template + static llvm::Optional Parse(InItT &InBegin, InItT InEnd) { + constexpr size_t NBytes = (sizeof(T) * 8 + 6) / 7; + T value = 0; + for (size_t c = 0; c < NBytes; ++c) { + uint8_t x; + if (InBegin == InEnd) + return {}; + x = *InBegin++; + value |= static_cast(x & 0x7Fu) << 7 * c; + if (!(x & 0x80)) + return value; + } + return {}; + } + + template static void Serialize(T value, OutItT &OutIt) { + constexpr size_t NBytes = (sizeof(T) * 8 + 6) / 7; + uint8_t b[NBytes]; + for (size_t i = 0; i < NBytes; ++i) { + b[i] = value & 0b0111'1111; + value >>= 7; + if (value) { + b[i] |= 0b1000'0000; + } else { + OutIt = std::copy_n(std::begin(b), i + 1, OutIt); + return; + } + } + } +}; + +template <> +struct HdcIO : HdcIOBase> { + template + static llvm::Optional Parse(InItT &InBegin, InItT InEnd) { + auto MaybeLen = HdcIO::Parse(InBegin, InEnd); + if (!MaybeLen) + return llvm::None; + size_t Len = *MaybeLen; + std::string Res; + Res.reserve(Len); + while (Res.size() < Len && InBegin != InEnd) + Res.push_back(*InBegin++); + if (Res.size() < Len) + return {}; + return Res; + } + + template + static void Serialize(const std::string &value, OutItT &OutIt) { + HdcIO::Serialize(value.size(), OutIt); + OutIt = std::copy_n(value.begin(), value.size(), OutIt); + } +}; + +template struct HdcTaggedIOHelper { + template + static llvm::Optional> Parse(InItT &InBegin, InItT InEnd) { + return std::tuple<>{}; + } + + template static void Serialize(OutItT &OutIt) {} +}; + +template +struct HdcTaggedIOHelper { + using ResT = llvm::Optional>; + + template static ResT Parse(InItT &InBegin, InItT InEnd) { + return HdcIO::ParseTagged(StartIdx, InBegin, InEnd) + .map([&](auto &&LHS) { + return HdcTaggedIOHelper::Parse(InBegin, InEnd) + .map([LHS = std::move(LHS)](auto &&RHS) { + return std::tuple_cat(std::make_tuple(std::move(LHS)), + std::move(RHS)); + }); + }) + .value_or(ResT(llvm::None)); + } + + template static ResT ParseOnce(InItT InBegin, InItT InEnd) { + return Parse(InBegin, InEnd); + } + + template + static void Serialize(const T &Arg, const Ts &...Args, OutItT &OutIt) { + HdcIO::SerializeTagged(StartIdx, std::move(Arg), OutIt); + HdcTaggedIOHelper::Serialize(std::move(Args)..., + OutIt); + } + + template + static void SerializeOnce(const T &Arg, const Ts &...Args, OutItT OutIt) { + return Serialize(Arg, Args..., OutIt); + } +}; + +template struct HdcTaggedIO : HdcTaggedIOHelper<1, Ts...> {}; + +template struct HdcTaggedIOTuple; + +template +struct HdcTaggedIOTuple> : HdcTaggedIO {}; + +using HdcTransferConfig = std::tuple; + +using HdcTransferPayload = std::tuple; + +using HdcFileMode = std::tuple; // fullName + +enum HdcCommand : uint16_t { + CMD_KERNEL_WAKEUP_SLAVETASK = 12, + CMD_FILE_INIT = 3000, + CMD_FILE_CHECK, + CMD_FILE_BEGIN, + CMD_FILE_DATA, + CMD_FILE_FINISH, + CMD_FILE_MODE = 3006 +}; + +static constexpr size_t HdcTransferPayloadPrefixReserve = 64; +static constexpr size_t HdcTransferPayloadMaxChunkSize = 49152; + +Status HdcClient::FileCheck(int FD, size_t &file_size) { + std::vector msg; + Status error = ExpectCommandMessage(HdcCommand::CMD_FILE_MODE, msg); + if (error.Fail()) + return error; + + auto maybe_file_mode = HdcTaggedIOTuple::ParseOnce(msg.cbegin(), msg.cend()); + if (!maybe_file_mode) + return Status("Could not parse HDC server FileMode"); + + auto &file_mode = *maybe_file_mode; + + uint32_t perms = static_cast(std::get<0>(file_mode)); + auto EC = llvm::sys::fs::setPermissions( + FD, static_cast(perms) & llvm::sys::fs::all_perms); + if (EC) + return Status(EC); + + error = SendCommandMessage(HdcCommand::CMD_FILE_MODE, {}); + if (error.Fail()) + return error; + + error = ExpectCommandMessage(HdcCommand::CMD_FILE_CHECK, msg); + if (error.Fail()) + return error; + + auto transfer_config = + HdcTaggedIOTuple::ParseOnce(msg.cbegin(), msg.cend()); + if (!transfer_config.has_value()) + return Status("Could not parse HDC server TransferConfig"); + + if (auto compress_type = std::get<7>(*transfer_config)) + return Status("Compression is not supported"); + + file_size = std::get<0>(*transfer_config); + + return SendCommandMessage(HdcCommand::CMD_FILE_BEGIN, {}); +} + +Status HdcClient::PullFileChunk(std::vector &buffer) { + buffer.clear(); + + std::vector msg; + Status error = ExpectCommandMessagePrefix(HdcCommand::CMD_FILE_DATA, msg, + HdcTransferPayloadPrefixReserve); + if (error.Fail()) + return error; + + auto transfer_payload = + HdcTaggedIOTuple::ParseOnce(msg.cbegin(), msg.cend()); + if (!transfer_payload.has_value()) + return Status("Could not parse HDC server TransferPayload"); + + if (auto compress_type = std::get<1>(*transfer_payload)) + return Status("Compression is not supported"); + + uint32_t read_bytes = std::get<3>(*transfer_payload); + buffer.resize(read_bytes, 0); + error = ReadAllBytes(buffer.data(), buffer.size()); + if (error.Fail()) + buffer.clear(); + + return error; +} + Status HdcClient::RecvFile(const FileSpec &src, const FileSpec &dst) { - return TransferFile("recv", src, dst); + if (IsServerLocal()) + return LocalTransferFile("recv", src, dst); + + const auto local_file_path = dst.GetPath(); + llvm::FileRemover local_file_remover(local_file_path); + + int dst_file_fd; + auto EC = llvm::sys::fs::openFileForWrite(local_file_path, dst_file_fd); + if (EC) + return Status("Unable to open local file %s", local_file_path.c_str()); + + std::stringstream cmd; + cmd << "file recv remote -m"; + cmd << " " << src.GetPath() << " " << dst.GetPath(); + Status error = SendMessage(cmd.str()); + if (error.Fail()) + return error; + + size_t cur_size = 0, all_size = 0; + error = FileCheck(dst_file_fd, all_size); + if (error.Fail()) + return error; + + llvm::raw_fd_ostream dst_file(dst_file_fd, true); + + std::vector buf; + while (cur_size < all_size) { + error = PullFileChunk(buf); + if (error.Fail()) + return error; + dst_file.write(buf.data(), buf.size()); + cur_size += buf.size(); + } + + error = SendCommandMessage(HdcCommand::CMD_FILE_FINISH, {}); + if (error.Fail()) + return error; + error = ReadResponseStatus("FileTransfer finish"); + if (error.Fail()) + return error; + + dst_file.close(); + if (dst_file.has_error()) + return Status("Failed to write file %s", local_file_path.c_str()); + + local_file_remover.releaseFile(); + return error; +} + +Status HdcClient::FileInit(size_t file_size, uint32_t perm, uint32_t u_id, + uint32_t g_id, const std::string &remote_path) { + std::vector msg; + Status error = ExpectCommandMessage(HdcCommand::CMD_FILE_INIT, msg); + if (error.Fail()) + return error; + + error = SendCommandMessage(HdcCommand::CMD_KERNEL_WAKEUP_SLAVETASK, {}); + if (error.Fail()) + return error; + + constexpr uint64_t IFREG_MASK = 0100000; + msg.clear(); + HdcTaggedIOTuple::SerializeOnce(perm | IFREG_MASK, // perm + u_id, // u_id + g_id, // g_id + "", // context + "", // fullName + std::back_inserter(msg)); + error = SendCommandMessage(HdcCommand::CMD_FILE_MODE, msg); + if (error.Fail()) + return error; + + error = ExpectCommandMessage(HdcCommand::CMD_FILE_MODE, msg); + if (error.Fail()) + return error; + + msg.clear(); + HdcTaggedIOTuple::SerializeOnce(file_size, // fileSize + 0, // atime + 0, // mtime + "", // options + remote_path, // path + "", // optionalName + false, // updateIfNew + 0, // compressType + false, // holdTimestamp + "", // funcName + "", // clientCwd + "", // reserve1 + "", // reserve2 + std::back_inserter(msg)); + error = SendCommandMessage(HdcCommand::CMD_FILE_CHECK, msg); + if (error.Fail()) + return error; + + return ExpectCommandMessage(HdcCommand::CMD_FILE_BEGIN, msg); +} + +Status HdcClient::PushFileChunk(std::vector &buffer, size_t chunk_size, + size_t index) { + std::fill_n(buffer.begin(), HdcTransferPayloadPrefixReserve, 0); + HdcTaggedIOTuple::SerializeOnce( + index, // index + 0, // compressType + chunk_size, // compressSize + chunk_size, // uncompressSize + buffer.begin()); + return SendCommandMessage(CMD_FILE_DATA, buffer); } Status HdcClient::SendFile(const FileSpec &src, const FileSpec &dst) { - return TransferFile("send", src, dst); + if (IsServerLocal()) + return LocalTransferFile("send", src, dst); + + const auto local_file_path = src.GetPath(); + std::ifstream src_file(local_file_path.c_str(), std::ios::in | std::ios::binary); + if (!src_file.is_open()) + return Status("Unable to open local file %s", local_file_path.c_str()); + + std::stringstream cmd; + cmd << "file send remote -m " << src.GetPath() << " " << dst.GetPath(); + Status error = SendMessage(cmd.str()); + if (error.Fail()) + return error; + + llvm::sys::fs::file_status status; + auto EC = llvm::sys::fs::status(local_file_path, status); + if (EC) + return Status(EC); + + error = FileInit(status.getSize(), status.permissions(), status.getUser(), + status.getGroup(), dst.GetPath()); + if (error.Fail()) + return error; + + std::vector buffer; + size_t sent_bytes = 0; + while (!src_file.eof()) { + buffer.resize(HdcTransferPayloadPrefixReserve + + HdcTransferPayloadMaxChunkSize); + if (src_file + .read(buffer.data() + HdcTransferPayloadPrefixReserve, + HdcTransferPayloadMaxChunkSize) + .bad()) + break; + size_t chunk_size = src_file.gcount(); + buffer.resize(HdcTransferPayloadPrefixReserve + chunk_size); + error = PushFileChunk(buffer, chunk_size, sent_bytes); + if (error.Fail()) + return error; + sent_bytes += chunk_size; + } + + if (src_file.bad()) + return Status("Failed read on %s", local_file_path.c_str()); + if (sent_bytes < status.getSize()) { + m_conn.reset(); + return Status("Failed to read all of the bytes from %s: read %zu/%zu", + local_file_path.c_str(), sent_bytes, status.getSize()); + } + + error = ExpectCommandMessage(HdcCommand::CMD_FILE_FINISH, buffer); + if (error.Fail()) + return error; + + error = SendCommandMessage(HdcCommand::CMD_FILE_FINISH, {}); + if (error.Fail()) + return error; + + return ReadResponseStatus("FileTransfer finish"); } Status HdcClient::SendMessage(llvm::StringRef packet, const bool reconnect) { @@ -314,6 +775,13 @@ Status HdcClient::SendMessage(llvm::StringRef packet, const bool reconnect) { return error; } +Status HdcClient::SendCommandMessage(uint16_t command, llvm::ArrayRef packet) { + llvm::SmallVector buf(sizeof(command) + packet.size()); + std::copy_n(reinterpret_cast(&command), sizeof(command), buf.begin()); + std::copy_n(packet.begin(), packet.size(), buf.begin() + sizeof(command)); + return SendMessage(llvm::StringRef(buf.data(), buf.size()), false); +} + Status HdcClient::ReadMessage(std::vector &message) { message.clear(); @@ -331,6 +799,40 @@ Status HdcClient::ReadMessage(std::vector &message) { return error; } +Status HdcClient::ReadCommandMessagePrefix(uint16_t &command, std::vector &message, size_t prefix_size) { + message.clear(); + + msg_len_t packet_len; + auto error = ReadAllBytes(&packet_len, sizeof(packet_len)); + if (error.Fail()) + return error; + + packet_len = htonl(packet_len); + if (packet_len < sizeof(command)) + return Status("Message too small to contain a command"); + + error = ReadAllBytes(&command, sizeof(command)); + if (error.Fail()) { + command = 0; + return error; + } + + message.resize(std::min(packet_len - sizeof(command), prefix_size), 0); + error = ReadAllBytes(&message[0], message.size()); + if (error.Fail()) { + command = 0; + message.clear(); + } + + return error; +} + +Status HdcClient::ReadCommandMessage(uint16_t &command, + std::vector &message) { + return ReadCommandMessagePrefix(command, message, + std::numeric_limits::max()); +} + Status HdcClient::ReadMessageStream(std::vector &message, milliseconds timeout) { auto start = steady_clock::now(); diff --git a/lldb/source/Plugins/Platform/OHOS/HdcClient.h b/lldb/source/Plugins/Platform/OHOS/HdcClient.h index 39b6569b447a38007e48a2fee784855f82ff6603..5e17b0d8f8ef465a494022eda3bb498057298560 100644 --- a/lldb/source/Plugins/Platform/OHOS/HdcClient.h +++ b/lldb/source/Plugins/Platform/OHOS/HdcClient.h @@ -34,8 +34,10 @@ public: static Status CreateByDeviceID(const std::string &device_id, HdcClient &hdc); - HdcClient(); - explicit HdcClient(const std::string &device_id); + explicit HdcClient(const std::string &connect_addr, + const std::string &device_id = ""); + + HdcClient(HdcClient &&); ~HdcClient(); @@ -63,19 +65,38 @@ public: std::string *output); private: + bool IsServerLocal(); Status Connect(); - Status TransferFile(const char *direction, const FileSpec &src, - const FileSpec &dst); + Status LocalTransferFile(const char *direction, const FileSpec &src, + const FileSpec &dst); + + Status FileCheck(int FD, size_t &file_size); + Status PullFileChunk(std::vector &buffer); + + Status FileInit(size_t file_size, uint32_t perm, uint32_t u_id, uint32_t g_id, + const std::string &remote_path); + Status PushFileChunk(std::vector &buffer, size_t chunk_size, + size_t index); void SetDeviceID(const std::string &device_id); Status SendMessage(llvm::StringRef packet, const bool reconnect = true); - Status SendDeviceMessage(const std::string &packet); - Status ReadMessage(std::vector &message); + Status SendCommandMessage(uint16_t command, llvm::ArrayRef packet); + + Status ReadCommandMessagePrefix(uint16_t &command, std::vector &message, + size_t prefix_size); + Status ReadCommandMessage(uint16_t &command, std::vector &message); + + Status ExpectCommandMessage(uint16_t expected_command, + std::vector &message); + Status ExpectCommandMessagePrefix(uint16_t expected_command, + std::vector &message, + size_t prefix_size); + Status ReadMessageStream(std::vector &message, std::chrono::milliseconds timeout); @@ -83,6 +104,7 @@ private: Status ReadAllBytes(void *buffer, size_t size); + std::string m_connect_addr; std::string m_device_id; std::unique_ptr m_conn; }; diff --git a/lldb/source/Plugins/Platform/OHOS/PlatformOHOS.cpp b/lldb/source/Plugins/Platform/OHOS/PlatformOHOS.cpp index 5193e17edbd151174d7ab600ae12af2224dcff18..6a1bb9044646224eb8febcf7ada75bda17210cbf 100644 --- a/lldb/source/Plugins/Platform/OHOS/PlatformOHOS.cpp +++ b/lldb/source/Plugins/Platform/OHOS/PlatformOHOS.cpp @@ -129,8 +129,13 @@ llvm::StringRef PlatformOHOS::GetPluginName() { return GetPluginNameStatic(IsHost()); } +HdcClient PlatformOHOS::CreateHdcClient() { + return HdcClient(m_connect_addr, m_device_id); +} + Status PlatformOHOS::ConnectRemote(Args &args) { m_device_id.clear(); + m_connect_addr = "localhost"; if (IsHost()) { return Status("can't connect to the host platform '%s', always connected", @@ -146,17 +151,26 @@ Status PlatformOHOS::ConnectRemote(Args &args) { llvm::Optional uri = URI::Parse(url); if (!uri) return Status("Invalid URL: %s", url); - if (uri->hostname != "localhost") - m_device_id = static_cast(uri->hostname); + + Log *log = GetLog(LLDBLog::Platform); + if (PlatformOHOSRemoteGDBServer::IsHostnameDeviceID( + uri->hostname)) { // accepts no (empty) hostname too + m_device_id = uri->hostname.str(); + LLDB_LOG(log, "Treating hostname as device id: \"{0}\"", m_device_id); + } else { + m_connect_addr = uri->hostname.str(); + LLDB_LOG(log, "Treating hostname as remote HDC server address: \"{0}\"", + m_connect_addr); + } auto error = PlatformLinux::ConnectRemote(args); if (error.Success()) { - HdcClient adb; - error = HdcClient::CreateByDeviceID(m_device_id, adb); + HdcClient hdc(m_connect_addr); + error = HdcClient::CreateByDeviceID(m_device_id, hdc); if (error.Fail()) return error; - m_device_id = adb.GetDeviceID(); + m_device_id = hdc.GetDeviceID(); } return error; } @@ -171,7 +185,7 @@ Status PlatformOHOS::GetFile(const FileSpec &source, source_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent( source_spec.GetCString(false)); - HdcClient hdc(m_device_id); + HdcClient hdc = CreateHdcClient(); Status error = hdc.RecvFile(source_spec, destination); return error; } @@ -188,7 +202,7 @@ Status PlatformOHOS::PutFile(const FileSpec &source, destination_spec.GetCString(false)); // TODO: Set correct uid and gid on remote file. - HdcClient hdc(m_device_id); + HdcClient hdc = CreateHdcClient(); Status error = hdc.SendFile(source, destination_spec); return error; } @@ -209,6 +223,7 @@ Status PlatformOHOS::DisconnectRemote() { Status error = PlatformLinux::DisconnectRemote(); if (error.Success()) { m_device_id.clear(); + m_connect_addr.clear(); m_sdk_version = 0; m_remote_platform_sp.reset(); } @@ -227,7 +242,7 @@ uint32_t PlatformOHOS::GetSdkVersion() { return m_sdk_version; std::string version_string; - HdcClient hdc(m_device_id); + HdcClient hdc = CreateHdcClient(); Status error = hdc.Shell("param get const.ohos.apiversion", seconds(5), &version_string); version_string = llvm::StringRef(version_string).trim().str(); diff --git a/lldb/source/Plugins/Platform/OHOS/PlatformOHOS.h b/lldb/source/Plugins/Platform/OHOS/PlatformOHOS.h index 83645ff209a5e29124838f9e7e2089ce3f90c6d2..fdbd1d42535ace58eb6dfceb906c9a600dbb1f4b 100644 --- a/lldb/source/Plugins/Platform/OHOS/PlatformOHOS.h +++ b/lldb/source/Plugins/Platform/OHOS/PlatformOHOS.h @@ -66,7 +66,10 @@ protected: llvm::StringRef GetLibdlFunctionDeclarations(lldb_private::Process *process) override; + HdcClient CreateHdcClient(); + private: + std::string m_connect_addr; std::string m_device_id; uint32_t m_sdk_version; diff --git a/lldb/source/Plugins/Platform/OHOS/PlatformOHOSRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/OHOS/PlatformOHOSRemoteGDBServer.cpp index 28f996a6cdb7c915ada3cb82cca88f3f518406af..0a6a7b208f404077663ba924762c22de4a8c1934 100644 --- a/lldb/source/Plugins/Platform/OHOS/PlatformOHOSRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/OHOS/PlatformOHOSRemoteGDBServer.cpp @@ -26,13 +26,13 @@ static const lldb::pid_t g_remote_platform_pid = static uint16_t g_hdc_forward_port_offset = 0; static Status ForwardPortWithHdc( - const uint16_t local_port, const uint16_t remote_port, - llvm::StringRef remote_socket_name, + const std::string &connect_addr, const uint16_t local_port, + const uint16_t remote_port, llvm::StringRef remote_socket_name, const llvm::Optional &socket_namespace, std::string &device_id) { Log *log = GetLog(LLDBLog::Platform); - HdcClient hdc; + HdcClient hdc(connect_addr); auto error = HdcClient::CreateByDeviceID(device_id, hdc); if (error.Fail()) return error; @@ -56,19 +56,22 @@ static Status ForwardPortWithHdc( *socket_namespace); } -static Status DeleteForwardPortWithHdc(std::pair ports, +static Status DeleteForwardPortWithHdc(const std::string &connect_addr, + std::pair ports, const std::string &device_id) { Log *log = GetLog(LLDBLog::Platform); LLDB_LOGF(log, "Delete port forwarding %d -> %d, device=%s", ports.first, ports.second, device_id.c_str()); - HdcClient hdc(device_id); + HdcClient hdc(connect_addr, device_id); return hdc.DeletePortForwarding(ports); } -static Status DeleteForwardPortWithHdc(std::pair remote_socket, - const llvm::Optional &socket_namespace, - const std::string &device_id) { +static Status DeleteForwardPortWithHdc( + const std::string &connect_addr, + std::pair remote_socket, + const llvm::Optional &socket_namespace, + const std::string &device_id) { Log *log = GetLog(LLDBLog::Platform); uint16_t local_port = remote_socket.first; @@ -78,7 +81,7 @@ static Status DeleteForwardPortWithHdc(std::pair remote_s if (!socket_namespace) return Status("Invalid socket namespace"); - HdcClient hdc(device_id); + HdcClient hdc(connect_addr, device_id); return hdc.DeletePortForwarding(local_port, remote_socket_name, *socket_namespace); } @@ -102,14 +105,14 @@ static Status FindUnusedPort(uint16_t &port) { return error; } -PlatformOHOSRemoteGDBServer::PlatformOHOSRemoteGDBServer() {} +PlatformOHOSRemoteGDBServer::PlatformOHOSRemoteGDBServer() = default; PlatformOHOSRemoteGDBServer::~PlatformOHOSRemoteGDBServer() { for (const auto &it : m_port_forwards) { - DeleteForwardPortWithHdc(it.second, m_device_id); + DeleteForwardPortWithHdc(m_connect_addr, it.second, m_device_id); } for (const auto &it_socket : m_remote_socket_name) { - DeleteForwardPortWithHdc(it_socket.second, m_socket_namespace, m_device_id); + DeleteForwardPortWithHdc(m_connect_addr, it_socket.second, m_socket_namespace, m_device_id); } } @@ -135,8 +138,14 @@ bool PlatformOHOSRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) { return m_gdb_client_up->KillSpawnedProcess(pid); } +bool PlatformOHOSRemoteGDBServer::IsHostnameDeviceID(llvm::StringRef hostname) { + return hostname != "localhost" && !hostname.contains(':') && + !hostname.contains('.'); +} + Status PlatformOHOSRemoteGDBServer::ConnectRemote(Args &args) { m_device_id.clear(); + m_connect_addr = "localhost"; if (args.GetArgumentCount() != 1) return Status( @@ -149,8 +158,16 @@ Status PlatformOHOSRemoteGDBServer::ConnectRemote(Args &args) { uri = URI::Parse(url); if (!uri) return Status("Invalid URL: %s", url); - if (uri->hostname != "localhost") - m_device_id = static_cast(uri->hostname); + + Log *log = GetLog(LLDBLog::Platform); + if (IsHostnameDeviceID(uri->hostname)) { // accepts no (empty) hostname too + m_device_id = uri->hostname.str(); + LLDB_LOG(log, "Treating hostname as device id: \"{0}\"", m_device_id); + } else { + m_connect_addr = uri->hostname.str(); + LLDB_LOG(log, "Treating hostname as remote HDC server address: \"{0}\"", + m_connect_addr); + } m_socket_namespace.reset(); if (uri->scheme == "unix-connect") @@ -168,7 +185,6 @@ Status PlatformOHOSRemoteGDBServer::ConnectRemote(Args &args) { args.ReplaceArgumentAtIndex(0, connect_url); - Log *log = GetLog(LLDBLog::Platform); LLDB_LOGF(log, "Rewritten platform connect URL: %s", connect_url.c_str()); error = PlatformRemoteGDBServer::ConnectRemote(args); if (error.Fail()) @@ -180,6 +196,7 @@ Status PlatformOHOSRemoteGDBServer::ConnectRemote(Args &args) { Status PlatformOHOSRemoteGDBServer::DisconnectRemote() { DeleteForwardPort(g_remote_platform_pid); g_hdc_forward_port_offset = 0; + m_connect_addr.clear(); return PlatformRemoteGDBServer::DisconnectRemote(); } @@ -189,7 +206,8 @@ void PlatformOHOSRemoteGDBServer::DeleteForwardPort(lldb::pid_t pid) { auto it = m_port_forwards.find(pid); auto it_socket = m_remote_socket_name.find(pid); if (it != m_port_forwards.end() && it->second.second != 0) { - const auto error = DeleteForwardPortWithHdc(it->second, m_device_id); + const auto error = + DeleteForwardPortWithHdc(m_connect_addr, it->second, m_device_id); if (error.Fail()) { LLDB_LOGF(log, "Failed to delete port forwarding (pid=%" PRIu64 ", fwd=(%d -> %d), device=%s): %s", @@ -200,7 +218,8 @@ void PlatformOHOSRemoteGDBServer::DeleteForwardPort(lldb::pid_t pid) { } if(it_socket != m_remote_socket_name.end()) { - const auto error_Socket = DeleteForwardPortWithHdc(it_socket->second, m_socket_namespace, m_device_id); + const auto error_Socket = DeleteForwardPortWithHdc( + m_connect_addr, it_socket->second, m_socket_namespace, m_device_id); if (error_Socket.Fail()) { LLDB_LOGF(log, "Failed to delete port forwarding (pid=%" PRIu64 ", fwd=(%d->%s)device=%s): %s", pid, it_socket->second.first, it_socket->second.second.c_str(), m_device_id.c_str(),error_Socket.AsCString()); @@ -226,8 +245,9 @@ Status PlatformOHOSRemoteGDBServer::MakeConnectURL( if (error.Fail()) return error; - error = ForwardPortWithHdc(local_port, remote_port, remote_socket_name, - m_socket_namespace, m_device_id); + error = + ForwardPortWithHdc(m_connect_addr, local_port, remote_port, + remote_socket_name, m_socket_namespace, m_device_id); if (error.Success()) { if (remote_port != 0){ m_port_forwards[pid] = {local_port, remote_port}; @@ -235,8 +255,10 @@ Status PlatformOHOSRemoteGDBServer::MakeConnectURL( else{ m_remote_socket_name[pid] ={local_port, remote_socket_name.str()}; } + // Connect to local_port on a potentially remote machine with running HDC + // server std::ostringstream url_str; - url_str << "connect://localhost:" << local_port; + url_str << "connect://" << m_connect_addr << ":" << local_port; connect_url = url_str.str(); break; } @@ -262,6 +284,8 @@ lldb::ProcessSP PlatformOHOSRemoteGDBServer::ConnectProcess( return nullptr; } + // If m_connect_addr is remote, this connects to a remote HDC server, assuming + // that all of the needed ports are open std::string new_connect_url; error = MakeConnectURL(s_remote_gdbserver_fake_pid--, (*uri->port) ? (*uri->port) : 0, uri->path, diff --git a/lldb/source/Plugins/Platform/OHOS/PlatformOHOSRemoteGDBServer.h b/lldb/source/Plugins/Platform/OHOS/PlatformOHOSRemoteGDBServer.h index 680ddc1e733c182c1cdbb64e45b802c8e6580103..cb130574d3f66f22a610c9dc7a4a3839dba2dbff 100644 --- a/lldb/source/Plugins/Platform/OHOS/PlatformOHOSRemoteGDBServer.h +++ b/lldb/source/Plugins/Platform/OHOS/PlatformOHOSRemoteGDBServer.h @@ -38,7 +38,10 @@ public: lldb_private::Target *target, lldb_private::Status &error) override; + static bool IsHostnameDeviceID(llvm::StringRef hostname); + protected: + std::string m_connect_addr; std::string m_device_id; std::map> m_port_forwards; std::map> m_remote_socket_name;