diff --git a/lldb/include/lldb/Interpreter/OptionGroupPlatform.h b/lldb/include/lldb/Interpreter/OptionGroupPlatform.h index 99945e5246fde7207026376782b0d4a5d9f9aeeb..c873cf307d1ea0276bcfe0b4321e3b2dba520ffb 100644 --- a/lldb/include/lldb/Interpreter/OptionGroupPlatform.h +++ b/lldb/include/lldb/Interpreter/OptionGroupPlatform.h @@ -58,12 +58,17 @@ public: void SetSDKBuild(ConstString sdk_build) { m_sdk_build = sdk_build; } + bool GetContainer() const { return m_container; } + + void SetContainer(bool b_container) { m_container = b_container; } + bool PlatformMatches(const lldb::PlatformSP &platform_sp) const; protected: std::string m_platform_name; ConstString m_sdk_sysroot; ConstString m_sdk_build; + bool m_container; llvm::VersionTuple m_os_version; bool m_include_platform_option; }; diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index d83f54ca62bcaa3dd45f7547217766249adf8de7..eb1a40db5316ece45e2148d24d3304b10befc236 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -477,6 +477,10 @@ public: void SetSDKBuild(ConstString sdk_build) { m_sdk_build = sdk_build; } + void SetContainer(bool b_container) { m_container = b_container; } + + bool GetContainer() const { return m_container; } + // Override this to return true if your platform supports Clang modules. You // may also need to override AddClangModuleCompilationOptions to pass the // right Clang flags for your platform. @@ -884,6 +888,7 @@ protected: ConstString m_sdk_sysroot; // the root location of where the SDK files are all located ConstString m_sdk_build; + bool m_container; FileSpec m_working_dir; // The working directory which is used when installing // modules that have no install path set std::string m_remote_url; diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp index f306da3c8543e54ebaf40840739c584738ca5499..33b8528522ae0856980e7a39b84500d9a8260ad2 100644 --- a/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/lldb/source/Commands/CommandObjectPlatform.cpp @@ -164,11 +164,16 @@ public: protected: bool DoExecute(Args &args, CommandReturnObject &result) override { - if (args.GetArgumentCount() == 1) { + if (args.GetArgumentCount() >= 1) { const char *platform_name = args.GetArgumentAtIndex(0); if (platform_name && platform_name[0]) { const bool select = true; m_platform_options.SetPlatformName(platform_name); + if (args.GetArgumentCount() == 2) { + std::string inner(args.GetArgumentAtIndex(1)); + if (inner == "inner") + m_platform_options.SetContainer(true); + } Status error; ArchSpec platform_arch; PlatformSP platform_sp(m_platform_options.CreatePlatformWithOptions( diff --git a/lldb/source/Interpreter/OptionGroupPlatform.cpp b/lldb/source/Interpreter/OptionGroupPlatform.cpp index 4242e010fa64e632d99b97ab074eb6d44d67aa85..ebe3b895c78d19fb2774bef915f8be4a9998120e 100644 --- a/lldb/source/Interpreter/OptionGroupPlatform.cpp +++ b/lldb/source/Interpreter/OptionGroupPlatform.cpp @@ -19,10 +19,16 @@ PlatformSP OptionGroupPlatform::CreatePlatformWithOptions( CommandInterpreter &interpreter, const ArchSpec &arch, bool make_selected, Status &error, ArchSpec &platform_arch) const { PlatformSP platform_sp; - + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMANDS)); if (!m_platform_name.empty()) { platform_sp = Platform::Create(ConstString(m_platform_name.c_str()), error); if (platform_sp) { + if (GetContainer()) { + if (log) { + LLDB_LOGF(log, "Platform is created inside container."); + } + platform_sp->SetContainer(true); + } if (platform_arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) { error.SetErrorStringWithFormat("platform '%s' doesn't support '%s'", @@ -58,6 +64,7 @@ void OptionGroupPlatform::OptionParsingStarting( m_sdk_sysroot.Clear(); m_sdk_build.Clear(); m_os_version = llvm::VersionTuple(); + m_container = false; } static constexpr OptionDefinition g_option_table[] = { @@ -92,7 +99,6 @@ OptionGroupPlatform::SetOptionValue(uint32_t option_idx, ++option_idx; const int short_option = g_option_table[option_idx].short_option; - switch (short_option) { case 'p': m_platform_name.assign(std::string(option_arg)); @@ -134,6 +140,10 @@ bool OptionGroupPlatform::PlatformMatches( if (!m_os_version.empty() && m_os_version != platform_sp->GetOSVersion()) return false; + + if (m_container != platform_sp->GetContainer()) + return false; + return true; } return false; diff --git a/lldb/source/Plugins/Platform/Android/AdbClient.cpp b/lldb/source/Plugins/Platform/Android/AdbClient.cpp index 50a4a07a9bab429fe4dcb6c6059d279aced2894a..ffccd6d628aade32c5a8e394e4f816c40ed2bffa 100644 --- a/lldb/source/Plugins/Platform/Android/AdbClient.cpp +++ b/lldb/source/Plugins/Platform/Android/AdbClient.cpp @@ -134,7 +134,7 @@ Status AdbClient::Connect() { Status error; m_conn = std::make_unique(); std::string port = "5037"; - if (const char *env_port = std::getenv("HDC_SERVER_PORT")) { + if (const char *env_port = std::getenv("ANDROID_ADB_SERVER_PORT")) { port = env_port; } std::string uri = "connect://127.0.0.1:" + port; diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt index 8c532955a9ddc2272f2232792f2695914b8853f0..c312beb80b7cd6db8ec32a83d90fab33de1d457c 100644 --- a/lldb/source/Plugins/Platform/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/CMakeLists.txt @@ -15,4 +15,5 @@ add_subdirectory(POSIX) add_subdirectory(gdb-server) add_subdirectory(Android) +add_subdirectory(HOS) add_subdirectory(OHOS) diff --git a/lldb/source/Plugins/Platform/HOS/CMakeLists.txt b/lldb/source/Plugins/Platform/HOS/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ec9e85def9f55c498fd48d6d61191a39646e86c4 --- /dev/null +++ b/lldb/source/Plugins/Platform/HOS/CMakeLists.txt @@ -0,0 +1,4 @@ +add_lldb_library(lldbPluginPlatformHOS PLUGIN HdcClient.cpp PlatformHOS.cpp + PlatformHOSRemoteGDBServer.cpp LINK_LIBS lldbCore + lldbHost lldbPluginPlatformLinux lldbPluginPlatformGDB + LINK_COMPONENTS Support) diff --git a/lldb/source/Plugins/Platform/HOS/HdcClient.cpp b/lldb/source/Plugins/Platform/HOS/HdcClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..609673b19b2c14566d28366e2fab3f2333e368b9 --- /dev/null +++ b/lldb/source/Plugins/Platform/HOS/HdcClient.cpp @@ -0,0 +1,808 @@ +//===-- HdcClient.cpp -------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "HdcClient.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileUtilities.h" + +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/PosixApi.h" +#include "lldb/Utility/DataBuffer.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataEncoder.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/Timeout.h" + +#include + +#include +#include +#include +#include + +// On Windows, transitive dependencies pull in , which defines a +// macro that clashes with a method name. +#ifdef SendMessage +#undef SendMessage +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_hos; +using namespace std::chrono; + +namespace { + +const seconds kReadTimeout(20); +const char *kOKAY = "OKAY"; +const char *kFAIL = "FAIL"; +const char *kDATA = "DATA"; +const char *kDONE = "DONE"; + +const char *kSEND = "SEND"; +const char *kRECV = "RECV"; +const char *kSTAT = "STAT"; + +const size_t kSyncPacketLen = 8; +// Maximum size of a filesync DATA packet. +const size_t kMaxPushData = 2 * 1024; +// Default mode for pushed files. +const uint32_t kDefaultMode = 0100770; // S_IFREG | S_IRWXU | S_IRWXG + +const char *kSocketNamespaceAbstract = "localabstract"; +const char *kSocketNamespaceFileSystem = "localfilesystem"; + +Status ReadAllBytes(Connection &conn, void *buffer, size_t size) { + + Status error; + ConnectionStatus status; + char *read_buffer = static_cast(buffer); + + auto now = steady_clock::now(); + const auto deadline = now + kReadTimeout; + size_t total_read_bytes = 0; + while (total_read_bytes < size && now < deadline) { + auto read_bytes = + conn.Read(read_buffer + total_read_bytes, size - total_read_bytes, + duration_cast(deadline - now), status, &error); + if (error.Fail()) + return error; + total_read_bytes += read_bytes; + if (status != eConnectionStatusSuccess) + break; + now = steady_clock::now(); + } + if (total_read_bytes < size) + error = Status( + "Unable to read requested number of bytes. Connection status: %d.", + status); + return error; +} + +} // namespace + +Status HdcClient::CreateByDeviceID(const std::string &device_id, + HdcClient &hdc) { + DeviceIDList connect_devices; + auto error = hdc.GetDevices(connect_devices); + if (error.Fail()) + return error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s device_id(%s)", __FILE__, + __LINE__, __FUNCTION__, device_id.c_str()); + } + std::string android_serial; + if (!device_id.empty()) + android_serial = device_id; + else if (const char *env_serial = std::getenv("ANDROID_SERIAL")) + android_serial = env_serial; + + if (android_serial.empty()) { + if (connect_devices.size() != 1) + return Status("Expected a single connected device, got instead %zu - try " + "setting 'ANDROID_SERIAL'", + connect_devices.size()); + hdc.SetDeviceID(connect_devices.front()); + } else { + auto find_it = std::find(connect_devices.begin(), connect_devices.end(), + android_serial); + if (find_it == connect_devices.end()) + return Status("Device \"%s\" not found", android_serial.c_str()); + + hdc.SetDeviceID(*find_it); + } + return error; +} + +HdcClient::HdcClient() {} + +HdcClient::HdcClient(const std::string &device_id) : m_device_id(device_id) {} + +HdcClient::~HdcClient() {} + +void HdcClient::SetDeviceID(const std::string &device_id) { + m_device_id = device_id; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s m_device_id(%s)", __FILE__, + __LINE__, __FUNCTION__, m_device_id.c_str()); + } +} + +const std::string &HdcClient::GetDeviceID() const { return m_device_id; } + +Status HdcClient::Connect() { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s new ConnectionFileDescriptor", + __FILE__, __LINE__, __FUNCTION__); + } + Status error; + m_conn.reset(new ConnectionFileDescriptor); + std::string port = "5037"; + + const char *env_port = std::getenv("HDC_SERVER_PORT"); + if ((env_port != NULL) && (atoi(env_port) > 0)) { + port = env_port; + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s env_port(%s) port(%s)", + __FILE__, __LINE__, __FUNCTION__, env_port, port.c_str()); + } + } + + std::string uri = "connect://127.0.0.1:" + port; + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s uri(%s)", __FILE__, __LINE__, + __FUNCTION__, uri.c_str()); + } + m_conn->Connect(uri.c_str(), &error); + + return error; +} + +Status HdcClient::GetDevices(DeviceIDList &device_list) { + device_list.clear(); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s call", __FILE__, __LINE__, + __FUNCTION__); + } + auto error = SendMessage("host:devices"); + if (error.Fail()) + return error; + + error = ReadResponseStatus(); + if (error.Fail()) + return error; + + std::vector in_buffer; + error = ReadMessage(in_buffer); + + llvm::StringRef response(&in_buffer[0], in_buffer.size()); + llvm::SmallVector devices; + response.split(devices, "\n", -1, false); + + for (const auto &device : devices) + device_list.push_back(device.split('\t').first.str()); + + // Force disconnect since hdc closes connection after host:devices response + // is sent. + m_conn.reset(); + return error; +} + +Status HdcClient::SetPortForwarding(const uint16_t local_port, + const uint16_t remote_port) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s local_port(%d) remote_port(%d)", + __FILE__, __LINE__, __FUNCTION__, local_port, remote_port); + } + char message[48]; + snprintf(message, sizeof(message), "forward:tcp:%d;tcp:%d", local_port, + remote_port); + + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s message(%s)", __FILE__, __LINE__, + __FUNCTION__, message); + } + const auto error = SendDeviceMessage(message); + if (error.Fail()) + return error; + + return ReadResponseStatus(); +} + +Status +HdcClient::SetPortForwarding(const uint16_t local_port, + llvm::StringRef remote_socket_name, + const UnixSocketNamespace socket_namespace) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s local_port(%d)", __FILE__, + __LINE__, __FUNCTION__, local_port); + } + char message[PATH_MAX]; + const char *sock_namespace_str = + (socket_namespace == UnixSocketNamespaceAbstract) + ? kSocketNamespaceAbstract + : kSocketNamespaceFileSystem; + snprintf(message, sizeof(message), "forward:tcp:%d;%s:%s", local_port, + sock_namespace_str, remote_socket_name.str().c_str()); + + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s message(%s)", __FILE__, __LINE__, + __FUNCTION__, message); + } + const auto error = SendDeviceMessage(message); + if (error.Fail()) + return error; + + return ReadResponseStatus(); +} + +Status HdcClient::DeletePortForwarding(const uint16_t local_port) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s local_port(%d)", __FILE__, + __LINE__, __FUNCTION__, local_port); + } + char message[32]; + snprintf(message, sizeof(message), "killforward:tcp:%d", local_port); + + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s message(%s)", __FILE__, __LINE__, + __FUNCTION__, message); + } + const auto error = SendDeviceMessage(message); + if (error.Fail()) + return error; + + return ReadResponseStatus(); +} + +Status HdcClient::SendMessage(const std::string &packet, const bool reconnect) { + Status error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s packet(%s) reconnect(%d)", + __FILE__, __LINE__, __FUNCTION__, packet.c_str(), reconnect); + } + if (!m_conn || reconnect) { + error = Connect(); + if (error.Fail()) + return error; + } + + char length_buffer[5]; + snprintf(length_buffer, sizeof(length_buffer), "%04x", + static_cast(packet.size())); + + ConnectionStatus status; + + m_conn->Write(length_buffer, 4, status, &error); + if (error.Fail()) + return error; + + m_conn->Write(packet.c_str(), packet.size(), status, &error); + return error; +} + +Status HdcClient::SendDeviceMessage(const std::string &packet) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s packet(%s) ", __FILE__, __LINE__, + __FUNCTION__, packet.c_str()); + } + std::ostringstream msg; + msg << "host-serial:" << m_device_id << ":" << packet; + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s msg(%s) ", __FILE__, __LINE__, + __FUNCTION__, msg.str().c_str()); + } + return SendMessage(msg.str()); +} + +Status HdcClient::ReadMessage(std::vector &message) { + message.clear(); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s call ", __FILE__, __LINE__, + __FUNCTION__); + } + char buffer[5]; + buffer[4] = 0; + + auto error = ReadAllBytes(buffer, 4); + if (error.Fail()) + return error; + + unsigned int packet_len = 0; + sscanf(buffer, "%x", &packet_len); + + message.resize(packet_len, 0); + error = ReadAllBytes(&message[0], packet_len); + if (error.Fail()) + message.clear(); + + return error; +} + +Status HdcClient::ReadMessageStream(std::vector &message, + milliseconds timeout) { + auto start = steady_clock::now(); + message.clear(); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s call ", __FILE__, __LINE__, + __FUNCTION__); + } + Status error; + lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess; + char buffer[1024]; + while (error.Success() && status == lldb::eConnectionStatusSuccess) { + auto end = steady_clock::now(); + auto elapsed = end - start; + if (elapsed >= timeout) + return Status("Timed out"); + + size_t n = m_conn->Read(buffer, sizeof(buffer), + duration_cast(timeout - elapsed), + status, &error); + if (n > 0) + message.insert(message.end(), &buffer[0], &buffer[n]); + } + return error; +} + +Status HdcClient::ReadResponseStatus() { + char response_id[5]; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + static const size_t packet_len = 4; + response_id[packet_len] = 0; + + auto error = ReadAllBytes(response_id, packet_len); + if (error.Fail()) + return error; + + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s response_id(%s) ", __FILE__, + __LINE__, __FUNCTION__, response_id); + } + if (strncmp(response_id, kOKAY, packet_len) != 0) + return GetResponseError(response_id); + + return error; +} + +Status HdcClient::GetResponseError(const char *response_id) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (strcmp(response_id, kFAIL) != 0) + return Status("Got unexpected response id from hdc: \"%s\"", response_id); + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s response_id(%s) ", __FILE__, + __LINE__, __FUNCTION__, response_id); + } + std::vector error_message; + auto error = ReadMessage(error_message); + if (error.Success()) + error.SetErrorString( + std::string(&error_message[0], error_message.size()).c_str()); + + return error; +} + +Status HdcClient::SwitchDeviceTransport() { + std::ostringstream msg; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + msg << "host:transport:" << m_device_id; + + auto error = SendMessage(msg.str()); + if (error.Fail()) + return error; + if (log) { + log->Printf("Hsu file(%s):%d HdcClient::%s m_device_id(%s) msg(%s)", + __FILE__, __LINE__, __FUNCTION__, m_device_id.c_str(), + msg.str().c_str()); + } + return ReadResponseStatus(); +} + +Status HdcClient::StartSync() { + auto error = SwitchDeviceTransport(); + if (error.Fail()) + return Status("Failed to switch to device transport: %s", + error.AsCString()); + + error = Sync(); + if (error.Fail()) + return Status("Sync failed: %s", error.AsCString()); + + return error; +} + +Status HdcClient::Sync() { + auto error = SendMessage("sync:", false); + if (error.Fail()) + return error; + + return ReadResponseStatus(); +} + +Status HdcClient::ReadAllBytes(void *buffer, size_t size) { + return ::ReadAllBytes(*m_conn, buffer, size); +} + +Status HdcClient::internalShell(const char *command, milliseconds timeout, + std::vector &output_buf) { + output_buf.clear(); + + auto error = SwitchDeviceTransport(); + if (error.Fail()) + return Status("Failed to switch to device transport: %s", + error.AsCString()); + + StreamString hdc_command; + hdc_command.Printf("shell:%s", command); + error = SendMessage(hdc_command.GetString().str(), false); + if (error.Fail()) + return error; + + error = ReadResponseStatus(); + if (error.Fail()) + return error; + + error = ReadMessageStream(output_buf, timeout); + if (error.Fail()) + return error; + + // HDC doesn't propagate return code of shell execution - if + // output starts with /system/bin/sh: most likely command failed. + static const char *kShellPrefix = "/system/bin/sh:"; + if (output_buf.size() > strlen(kShellPrefix)) { + if (!memcmp(&output_buf[0], kShellPrefix, strlen(kShellPrefix))) + return Status("Shell command %s failed: %s", command, + std::string(output_buf.begin(), output_buf.end()).c_str()); + } + + return Status(); +} + +Status HdcClient::Shell(const char *command, milliseconds timeout, + std::string *output) { + std::vector output_buffer; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s command(%s)", __FILE__, + __LINE__, __FUNCTION__, command); + } + auto error = internalShell(command, timeout, output_buffer); + if (error.Fail()) + return error; + + if (output) + output->assign(output_buffer.begin(), output_buffer.end()); + return error; +} + +Status HdcClient::ShellToFile(const char *command, milliseconds timeout, + const FileSpec &output_file_spec) { + std::vector output_buffer; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s command(%s)", __FILE__, + __LINE__, __FUNCTION__, command); + } + auto error = internalShell(command, timeout, output_buffer); + if (error.Fail()) + return error; + + const auto output_filename = output_file_spec.GetPath(); + std::error_code EC; + llvm::raw_fd_ostream dst(output_filename, EC, llvm::sys::fs::OF_None); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s output_filename(%s)", + __FILE__, __LINE__, __FUNCTION__, output_filename.c_str()); + } + if (EC) + return Status("Unable to open local file %s", output_filename.c_str()); + + dst.write(&output_buffer[0], output_buffer.size()); + dst.close(); + if (dst.has_error()) + return Status("Failed to write file %s", output_filename.c_str()); + return Status(); +} + +std::unique_ptr +HdcClient::GetSyncService(Status &error) { + std::unique_ptr sync_service; + error = StartSync(); + if (error.Success()) + sync_service.reset(new SyncService(std::move(m_conn))); + + return sync_service; +} + +Status HdcClient::SyncService::internalPullFile(const FileSpec &remote_file, + const FileSpec &local_file) { + const auto local_file_path = local_file.GetPath(); + llvm::FileRemover local_file_remover(local_file_path); + + std::error_code EC; + llvm::raw_fd_ostream dst(local_file_path, EC, llvm::sys::fs::OF_None); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s local_file_path(%s)", + __FILE__, __LINE__, __FUNCTION__, local_file_path.c_str()); + } + if (EC) + return Status("Unable to open local file %s", local_file_path.c_str()); + + const auto remote_file_path = remote_file.GetPath(false); + auto error = SendSyncRequest(kRECV, remote_file_path.length(), + remote_file_path.c_str()); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s remote_file_path(%s)", + __FILE__, __LINE__, __FUNCTION__, remote_file_path.c_str()); + } + if (error.Fail()) + return error; + + std::vector chunk; + bool eof = false; + while (!eof) { + error = PullFileChunk(chunk, eof); + if (error.Fail()) + return error; + if (!eof) + dst.write(&chunk[0], chunk.size()); + } + dst.close(); + if (dst.has_error()) + return Status("Failed to write file %s", local_file_path.c_str()); + + local_file_remover.releaseFile(); + return error; +} + +Status HdcClient::SyncService::internalPushFile(const FileSpec &local_file, + const FileSpec &remote_file) { + const auto local_file_path(local_file.GetPath()); + std::ifstream src(local_file_path.c_str(), std::ios::in | std::ios::binary); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s local_file_path(%s)", + __FILE__, __LINE__, __FUNCTION__, local_file_path.c_str()); + } + if (!src.is_open()) + return Status("Unable to open local file %s", local_file_path.c_str()); + + std::stringstream file_description; + file_description << remote_file.GetPath(false).c_str() << "," << kDefaultMode; + std::string file_description_str = file_description.str(); + auto error = SendSyncRequest(kSEND, file_description_str.length(), + file_description_str.c_str()); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s file_description_str(%s)", + __FILE__, __LINE__, __FUNCTION__, file_description_str.c_str()); + } + if (error.Fail()) + return error; + + char chunk[kMaxPushData]; + while (!src.eof() && !src.read(chunk, kMaxPushData).bad()) { + size_t chunk_size = src.gcount(); + error = SendSyncRequest(kDATA, chunk_size, chunk); + if (error.Fail()) + return Status("Failed to send file chunk: %s", error.AsCString()); + } + error = SendSyncRequest( + kDONE, + llvm::sys::toTimeT( + FileSystem::Instance().GetModificationTime(local_file)), + nullptr); + if (error.Fail()) + return error; + + std::string response_id; + uint32_t data_len; + error = ReadSyncHeader(response_id, data_len); + if (error.Fail()) + return Status("Failed to read DONE response: %s", error.AsCString()); + if (response_id == kFAIL) { + std::string error_message(data_len, 0); + error = ReadAllBytes(&error_message[0], data_len); + if (error.Fail()) + return Status("Failed to read DONE error message: %s", error.AsCString()); + return Status("Failed to push file: %s", error_message.c_str()); + } else if (response_id != kOKAY) + return Status("Got unexpected DONE response: %s", response_id.c_str()); + + // If there was an error reading the source file, finish the hdc file + // transfer first so that hdc isn't expecting any more data. + if (src.bad()) + return Status("Failed read on %s", local_file_path.c_str()); + return error; +} + +Status HdcClient::SyncService::internalStat(const FileSpec &remote_file, + uint32_t &mode, uint32_t &size, + uint32_t &mtime) { + const std::string remote_file_path(remote_file.GetPath(false)); + auto error = SendSyncRequest(kSTAT, remote_file_path.length(), + remote_file_path.c_str()); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s remote_file_path(%s)", + __FILE__, __LINE__, __FUNCTION__, remote_file_path.c_str()); + } + if (error.Fail()) + return Status("Failed to send request: %s", error.AsCString()); + + static const size_t stat_len = strlen(kSTAT); + static const size_t response_len = stat_len + (sizeof(uint32_t) * 3); + + std::vector buffer(response_len); + error = ReadAllBytes(&buffer[0], buffer.size()); + if (error.Fail()) + return Status("Failed to read response: %s", error.AsCString()); + + DataExtractor extractor(&buffer[0], buffer.size(), eByteOrderLittle, + sizeof(void *)); + offset_t offset = 0; + + const void *command = extractor.GetData(&offset, stat_len); + if (!command) + return Status("Failed to get response command"); + const char *command_str = static_cast(command); + if (strncmp(command_str, kSTAT, stat_len)) + return Status("Got invalid stat command: %s", command_str); + + mode = extractor.GetU32(&offset); + size = extractor.GetU32(&offset); + mtime = extractor.GetU32(&offset); + return Status(); +} + +Status HdcClient::SyncService::PullFile(const FileSpec &remote_file, + const FileSpec &local_file) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, + "Hsu file(%s):%d HdcClient::%s remote_file(%s) local_file(%s)", + __FILE__, __LINE__, __FUNCTION__, remote_file.GetPath().c_str(), + local_file.GetPath().c_str()); + } + return executeCommand([this, &remote_file, &local_file]() { + return internalPullFile(remote_file, local_file); + }); +} + +Status HdcClient::SyncService::PushFile(const FileSpec &local_file, + const FileSpec &remote_file) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, + "Hsu file(%s):%d HdcClient::%s remote_file(%s) local_file(%s)", + __FILE__, __LINE__, __FUNCTION__, remote_file.GetPath().c_str(), + local_file.GetPath().c_str()); + } + return executeCommand([this, &local_file, &remote_file]() { + return internalPushFile(local_file, remote_file); + }); +} + +Status HdcClient::SyncService::Stat(const FileSpec &remote_file, uint32_t &mode, + uint32_t &size, uint32_t &mtime) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d HdcClient::%s remote_file(%s) mode(%d)", + __FILE__, __LINE__, __FUNCTION__, remote_file.GetPath().c_str(), + mode); + } + return executeCommand([this, &remote_file, &mode, &size, &mtime]() { + return internalStat(remote_file, mode, size, mtime); + }); +} + +bool HdcClient::SyncService::IsConnected() const { + return m_conn && m_conn->IsConnected(); +} + +HdcClient::SyncService::SyncService(std::unique_ptr &&conn) + : m_conn(std::move(conn)) {} + +Status +HdcClient::SyncService::executeCommand(const std::function &cmd) { + if (!m_conn) + return Status("SyncService is disconnected"); + + const auto error = cmd(); + if (error.Fail()) + m_conn.reset(); + + return error; +} + +HdcClient::SyncService::~SyncService() {} + +Status HdcClient::SyncService::SendSyncRequest(const char *request_id, + const uint32_t data_len, + const void *data) { + const DataBufferSP data_sp(new DataBufferHeap(kSyncPacketLen, 0)); + DataEncoder encoder(data_sp, eByteOrderLittle, sizeof(void *)); + auto offset = encoder.PutData(0, request_id, strlen(request_id)); + encoder.PutUnsigned(offset, 4, data_len); + + Status error; + ConnectionStatus status; + m_conn->Write(data_sp->GetBytes(), kSyncPacketLen, status, &error); + if (error.Fail()) + return error; + + if (data) + m_conn->Write(data, data_len, status, &error); + return error; +} + +Status HdcClient::SyncService::ReadSyncHeader(std::string &response_id, + uint32_t &data_len) { + char buffer[kSyncPacketLen]; + + auto error = ReadAllBytes(buffer, kSyncPacketLen); + if (error.Success()) { + response_id.assign(&buffer[0], 4); + DataExtractor extractor(&buffer[4], 4, eByteOrderLittle, sizeof(void *)); + offset_t offset = 0; + data_len = extractor.GetU32(&offset); + } + + return error; +} + +Status HdcClient::SyncService::PullFileChunk(std::vector &buffer, + bool &eof) { + buffer.clear(); + + std::string response_id; + uint32_t data_len; + auto error = ReadSyncHeader(response_id, data_len); + if (error.Fail()) + return error; + + if (response_id == kDATA) { + buffer.resize(data_len, 0); + error = ReadAllBytes(&buffer[0], data_len); + if (error.Fail()) + buffer.clear(); + } else if (response_id == kDONE) { + eof = true; + } else if (response_id == kFAIL) { + std::string error_message(data_len, 0); + error = ReadAllBytes(&error_message[0], data_len); + if (error.Fail()) + return Status("Failed to read pull error message: %s", error.AsCString()); + return Status("Failed to pull file: %s", error_message.c_str()); + } else + return Status("Pull failed with unknown response: %s", response_id.c_str()); + + return Status(); +} + +Status HdcClient::SyncService::ReadAllBytes(void *buffer, size_t size) { + return ::ReadAllBytes(*m_conn, buffer, size); +} diff --git a/lldb/source/Plugins/Platform/HOS/HdcClient.h b/lldb/source/Plugins/Platform/HOS/HdcClient.h new file mode 100644 index 0000000000000000000000000000000000000000..33d4370c9d020ef969c09475ab5fcb32a1d81914 --- /dev/null +++ b/lldb/source/Plugins/Platform/HOS/HdcClient.h @@ -0,0 +1,138 @@ +//===-- HdcClient.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 liblldb_HdcClient_h_ +#define liblldb_HdcClient_h_ + +#include "lldb/Utility/Status.h" +#include +#include +#include +#include +#include +#include + +namespace lldb_private { + +class FileSpec; + +namespace platform_hos { + +class HdcClient { +public: + enum UnixSocketNamespace { + UnixSocketNamespaceAbstract, + UnixSocketNamespaceFileSystem, + }; + + using DeviceIDList = std::list; + + class SyncService { + friend class HdcClient; + + public: + ~SyncService(); + + Status PullFile(const FileSpec &remote_file, const FileSpec &local_file); + + Status PushFile(const FileSpec &local_file, const FileSpec &remote_file); + + Status Stat(const FileSpec &remote_file, uint32_t &mode, uint32_t &size, + uint32_t &mtime); + + bool IsConnected() const; + + private: + explicit SyncService(std::unique_ptr &&conn); + + Status SendSyncRequest(const char *request_id, const uint32_t data_len, + const void *data); + + Status ReadSyncHeader(std::string &response_id, uint32_t &data_len); + + Status PullFileChunk(std::vector &buffer, bool &eof); + + Status ReadAllBytes(void *buffer, size_t size); + + Status internalPullFile(const FileSpec &remote_file, + const FileSpec &local_file); + + Status internalPushFile(const FileSpec &local_file, + const FileSpec &remote_file); + + Status internalStat(const FileSpec &remote_file, uint32_t &mode, + uint32_t &size, uint32_t &mtime); + + Status executeCommand(const std::function &cmd); + + std::unique_ptr m_conn; + }; + + static Status CreateByDeviceID(const std::string &device_id, HdcClient &hdc); + HdcClient(); + explicit HdcClient(const std::string &device_id); + + ~HdcClient(); + const std::string &GetDeviceID() const; + + Status GetDevices(DeviceIDList &device_list); + + Status SetPortForwarding(const uint16_t local_port, + const uint16_t remote_port); + + Status SetPortForwarding(const uint16_t local_port, + llvm::StringRef remote_socket_name, + const UnixSocketNamespace socket_namespace); + + Status DeletePortForwarding(const uint16_t local_port); + + Status Shell(const char *command, std::chrono::milliseconds timeout, + std::string *output); + + Status ShellToFile(const char *command, std::chrono::milliseconds timeout, + const FileSpec &output_file_spec); + + std::unique_ptr GetSyncService(Status &error); + + Status SwitchDeviceTransport(); + +private: + Status Connect(); + + void SetDeviceID(const std::string &device_id); + + Status SendMessage(const std::string &packet, const bool reconnect = true); + + Status SendDeviceMessage(const std::string &packet); + + Status ReadMessage(std::vector &message); + + Status ReadMessageStream(std::vector &message, + std::chrono::milliseconds timeout); + + Status GetResponseError(const char *response_id); + + Status ReadResponseStatus(); + + Status Sync(); + + Status StartSync(); + + Status internalShell(const char *command, std::chrono::milliseconds timeout, + std::vector &output_buf); + + Status ReadAllBytes(void *buffer, size_t size); + + std::string m_device_id; + std::unique_ptr m_conn; +}; + +} // namespace platform_hos +} // namespace lldb_private + +#endif // liblldb_HdcClient_h_ diff --git a/lldb/source/Plugins/Platform/HOS/PlatformHOS.cpp b/lldb/source/Plugins/Platform/HOS/PlatformHOS.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5be96da944af50b7df96914eeda64a8e48af695 --- /dev/null +++ b/lldb/source/Plugins/Platform/HOS/PlatformHOS.cpp @@ -0,0 +1,466 @@ +//===-- PlatformHOS.cpp -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/StringConvert.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Scalar.h" +#include "lldb/Utility/UriParser.h" +#include "llvm/Config/config.h" + +#include "HdcClient.h" +#include "PlatformHOS.h" +#include "PlatformHOSRemoteGDBServer.h" +#if defined __MINGW32__ +// SetEnvironmentVariableA +#include +#endif + +using namespace lldb; +using namespace lldb_private; +// using namespace lldb_private::platform_android; +using namespace lldb_private::platform_hos; +using namespace std::chrono; +static uint32_t g_initialize_count = 0; +static const unsigned int g_hos_default_cache_size = 2048; +LLDB_PLUGIN_DEFINE(PlatformHOS) + +static void platform_setenv(const char *env, const char *val) { +#if HAVE_SETENV || _MSC_VER + setenv(env, val, true); +#elif defined(__MINGW32__) + SetEnvironmentVariableA(env, val); +#else +#error "setenv not found" +#endif +} + +void PlatformHOS::Initialize() { + PlatformLinux::Initialize(); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (g_initialize_count++ == 0) { +#if defined(__HOS__) + PlatformSP default_platform_sp(new PlatformHOS(true)); + default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); + Platform::SetHostPlatform(default_platform_sp); + if (log) { + LLDB_LOGF(log, "Hsu file(%s)%d PlatformHOS::%s new PlatformHOS(true)", + __FILE__, __LINE__, __FUNCTION__); + } +#endif + PluginManager::RegisterPlugin( + PlatformHOS::GetPluginNameStatic(false), + PlatformHOS::GetPluginDescriptionStatic(false), + PlatformHOS::CreateInstance); + } +} + +void PlatformHOS::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(PlatformHOS::CreateInstance); + } + } + PlatformLinux::Terminate(); +} + +PlatformSP PlatformHOS::CreateInstance(bool force, const ArchSpec *arch) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + const char *triple_cstr = + arch ? arch->GetTriple().getTriple().c_str() : ""; + + LLDB_LOGF(log, "PlatformHOS::%s(force=%s, triple=%s)", __FUNCTION__, + force ? "true" : "false", triple_cstr); + } + + bool create = force; + if (!create && arch && arch->IsValid()) { + const llvm::Triple &triple = arch->GetTriple(); + + switch (triple.getVendor()) { + case llvm::Triple::PC: + create = true; + break; + + default: + create = triple.isOpenHOS(); + break; + } + } + + if (create) { + if (const char *env = std::getenv("HDC_UTID")) + platform_setenv("ANDROID_SERIAL", env); + + LLDB_LOGF(log, "PlatformHOS::%s() creating remote-hos platform", + __FUNCTION__); + return PlatformSP(new PlatformHOS(false)); + } + + LLDB_LOGF(log, "PlatformHOS::%s() aborting creation of remote-hos platform", + __FUNCTION__); + + return PlatformSP(); +} + +PlatformHOS::PlatformHOS(bool is_host) + : PlatformLinux(is_host), m_sdk_version(0) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d PlatformHOS::%s is_host(%d)", __FILE__, + __LINE__, __FUNCTION__, is_host); + } +} + +PlatformHOS::~PlatformHOS() {} + +ConstString PlatformHOS::GetPluginNameStatic(bool is_host) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu %s:%d PlatformHOS::GetPluginNameStatic is_host(%d)", + __FILE__, __LINE__, is_host); + } + if (is_host) { + static ConstString g_host_name(Platform::GetHostPlatformName()); + if (log) { + LLDB_LOGF(log, "Hsu %s:%d PlatformHOS::GetPluginNameStatic g_host_name", + __FILE__, __LINE__); + } + return g_host_name; + } else { + static ConstString g_remote_name("remote-hos"); + if (log) { + LLDB_LOGF(log, "Hsu %s:%d PlatformHOS::GetPluginNameStatic g_remote_name", + __FILE__, __LINE__); + } + return g_remote_name; + } +} + +const char *PlatformHOS::GetPluginDescriptionStatic(bool is_host) { + if (is_host) + return "Local HarmonyOS user platform plug-in."; + else + return "Remote HarmonyOS user platform plug-in."; +} +Status PlatformHOS::ConnectRemote(Args &args) { + m_device_id.clear(); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + LLDB_LOGF(log, "Hsu %s:%d PlatformHOS::ConnectRemote call", __FILE__, + __LINE__); + } + + if (IsHost()) { + return Status("can't connect to the host platform '%s', always connected", + GetPluginName().GetCString()); + } + + if (!m_remote_platform_sp) { + if (log) { + LLDB_LOGF(log, + "Hsu %s:%d PlatformHOS::ConnectRemote new " + "PlatformHOSRemoteGDBServer()", + __FILE__, __LINE__); + } + m_remote_platform_sp = PlatformSP(new PlatformHOSRemoteGDBServer()); + } + + int port; + llvm::StringRef scheme, host, path; + const char *url = args.GetArgumentAtIndex(0); + if (!url) + return Status("URL is null."); + if (!UriParser::Parse(url, scheme, host, port, path)) + return Status("Invalid URL: %s", url); + if (host != "localhost") + m_device_id = static_cast(host); + + auto error = PlatformLinux::ConnectRemote(args); + if (error.Success()) { + HdcClient hdc; + if (log) { + LLDB_LOGF(log, + "Hsu file(%s):%d PlatformHOS::ConnectRemote m_device_id(%s)", + __FILE__, __LINE__, m_device_id.c_str()); + } + error = HdcClient::CreateByDeviceID(m_device_id, hdc); + if (error.Fail()) + return error; + + m_device_id = hdc.GetDeviceID(); + if (log) { + LLDB_LOGF(log, + "Hsu file(%s):%d PlatformHOS::ConnectRemote m_device_id(%s)", + __FILE__, __LINE__, m_device_id.c_str()); + } + } + return error; +} + +Status PlatformHOS::GetFile(const FileSpec &source, + const FileSpec &destination) { + if (IsHost() || !m_remote_platform_sp) + return PlatformLinux::GetFile(source, destination); + + FileSpec source_spec(source.GetPath(false), FileSpec::Style::posix); + if (source_spec.IsRelative()) + source_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent( + source_spec.GetCString(false)); + + Status error; + auto sync_service = GetSyncService(error); + if (error.Fail()) + return error; + + uint32_t mode = 0, size = 0, mtime = 0; + error = sync_service->Stat(source_spec, mode, size, mtime); + if (error.Fail()) + return error; + + if (mode != 0) + return sync_service->PullFile(source_spec, destination); + + auto source_file = source_spec.GetCString(false); + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + LLDB_LOGF(log, "Got mode == 0 on '%s': try to get file via 'shell cat'", + source_file); + + if (strchr(source_file, '\'') != nullptr) + return Status("Doesn't support single-quotes in filenames"); + + // mode == 0 can signify that adbd cannot access the file due security + // constraints - try "cat ..." as a fallback. + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d PlatformHOS::%s source_file(%s)", __FILE__, + __LINE__, __FUNCTION__, source_file); + } + HdcClient hdc(m_device_id); + + char cmd[PATH_MAX]; + int len = strlen(source_file); + std::string tempFile(source_file); + if (m_container) { + /* + /data /data/ohos_data + /vendor /sytem/ohos/vendor + /system /system/ohos/system + */ + const std::string str_data = "/data"; + const std::string str_vendor = "/vendor"; + const std::string str_system = "/system"; + const std::string str_data_append = "/data/ohos_data"; + const std::string str_vendor_append = "/vendor/ohos/vendor"; + const std::string str_system_append = "/system/ohos/system"; + if (!strncmp(source_file, str_data.c_str(), strlen(str_data.c_str()))) { + tempFile = str_data_append + tempFile.substr(strlen(str_data.c_str())); + snprintf(cmd, sizeof(cmd), "cat '%s'", tempFile.c_str()); + return hdc.ShellToFile(cmd, minutes(1), destination); + } + if (!strncmp(source_file, str_vendor.c_str(), strlen(str_vendor.c_str()))) { + tempFile = + str_vendor_append + tempFile.substr(strlen(str_vendor.c_str())); + snprintf(cmd, sizeof(cmd), "cat '%s'", tempFile.c_str()); + return hdc.ShellToFile(cmd, minutes(1), destination); + } + + if (!strncmp(source_file, str_system.c_str(), strlen(str_system.c_str()))) { + tempFile = + str_system_append + tempFile.substr(strlen(str_system.c_str())); + snprintf(cmd, sizeof(cmd), "cat '%s'", tempFile.c_str()); + return hdc.ShellToFile(cmd, minutes(1), destination); + } + return error; + } else { + snprintf(cmd, sizeof(cmd), "cat '%s'", source_file); + } + + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d PlatformHOS::%s source_file(%s)", __FILE__, + __LINE__, __FUNCTION__, source_file); + } + return hdc.ShellToFile(cmd, minutes(1), destination); +} + +Status PlatformHOS::PutFile(const FileSpec &source, const FileSpec &destination, + uint32_t uid, uint32_t gid) { + if (IsHost() || !m_remote_platform_sp) + return PlatformLinux::PutFile(source, destination, uid, gid); + + FileSpec destination_spec(destination.GetPath(false), FileSpec::Style::posix); + if (destination_spec.IsRelative()) + destination_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent( + destination_spec.GetCString(false)); + + // TODO: Set correct uid and gid on remote file. + Status error; + auto sync_service = GetSyncService(error); + if (error.Fail()) + return error; + return sync_service->PushFile(source, destination_spec); +} + +const char *PlatformHOS::GetCacheHostname() { return m_device_id.c_str(); } + +Status PlatformHOS::DownloadModuleSlice(const FileSpec &src_file_spec, + const uint64_t src_offset, + const uint64_t src_size, + const FileSpec &dst_file_spec) { + if (src_offset != 0) + return Status("Invalid offset - %" PRIu64, src_offset); + + return GetFile(src_file_spec, dst_file_spec); +} + +Status PlatformHOS::DisconnectRemote() { + Status error = PlatformLinux::DisconnectRemote(); + if (error.Success()) { + m_device_id.clear(); + m_sdk_version = 0; + } + return error; +} + +uint32_t PlatformHOS::GetDefaultMemoryCacheLineSize() { + return g_hos_default_cache_size; +} + +uint32_t PlatformHOS::GetSdkVersion() { + if (!IsConnected()) + return 0; + + if (m_sdk_version != 0) + return m_sdk_version; + + std::string version_string; + HdcClient hdc(m_device_id); + Status error = + hdc.Shell("getprop ro.build.version.sdk", seconds(5), &version_string); + version_string = llvm::StringRef(version_string).trim().str(); + + if (error.Fail() || version_string.empty()) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM); + LLDB_LOGF(log, "Get SDK version failed. (error: %s, output: %s)", + error.AsCString(), version_string.c_str()); + return 0; + } + + m_sdk_version = StringConvert::ToUInt32(version_string.c_str()); + return m_sdk_version; +} + +Status PlatformHOS::DownloadSymbolFile(const lldb::ModuleSP &module_sp, + const FileSpec &dst_file_spec) { + // For oat file we can try to fetch additional debug info from the device + ConstString extension = module_sp->GetFileSpec().GetFileNameExtension(); + if (extension != ".oat" && extension != ".odex") + return Status( + "Symbol file downloading only supported for oat and odex files"); + + // If we have no information about the platform file we can't execute oatdump + if (!module_sp->GetPlatformFileSpec()) + return Status("No platform file specified"); + + // Symbolizer isn't available before SDK version 23 + if (GetSdkVersion() < 23) + return Status("Symbol file generation only supported on SDK 23+"); + + // If we already have symtab then we don't have to try and generate one + if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) != + nullptr) + return Status("Symtab already available in the module"); + + HdcClient hdc(m_device_id); + std::string tmpdir; + Status error; + if (m_container) { + error = hdc.Shell("mktemp --directory --tmpdir /data/ohos_data/local/tmp", + seconds(5), &tmpdir); + } else { + error = hdc.Shell("mktemp --directory --tmpdir /data/local/tmp", seconds(5), + &tmpdir); + } + if (error.Fail() || tmpdir.empty()) + return Status("Failed to generate temporary directory on the device (%s)", + error.AsCString()); + tmpdir = llvm::StringRef(tmpdir).trim().str(); + + // Create file remover for the temporary directory created on the device + std::unique_ptr> + tmpdir_remover(&tmpdir, [&hdc](std::string *s) { + StreamString command; + command.Printf("rm -rf %s", s->c_str()); + Status error = hdc.Shell(command.GetData(), seconds(5), nullptr); + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log && error.Fail()) + LLDB_LOGF(log, "Failed to remove temp directory: %s", + error.AsCString()); + }); + + FileSpec symfile_platform_filespec(tmpdir); + symfile_platform_filespec.AppendPathComponent("symbolized.oat"); + + // Execute oatdump on the remote device to generate a file with symtab + StreamString command; + command.Printf("oatdump --symbolize=%s --output=%s", + module_sp->GetPlatformFileSpec().GetCString(false), + symfile_platform_filespec.GetCString(false)); + error = hdc.Shell(command.GetData(), minutes(1), nullptr); + if (error.Fail()) + return Status("Oatdump failed: %s", error.AsCString()); + + // Download the symbolfile from the remote device + return GetFile(symfile_platform_filespec, dst_file_spec); +} + +bool PlatformHOS::GetRemoteOSVersion() { + m_os_version = llvm::VersionTuple(GetSdkVersion()); + return !m_os_version.empty(); +} + +llvm::StringRef +PlatformHOS::GetLibdlFunctionDeclarations(lldb_private::Process *process) { + SymbolContextList matching_symbols; + std::vector dl_open_names = {"__dl_dlopen", "dlopen"}; + const char *dl_open_name = nullptr; + Target &target = process->GetTarget(); + for (auto name : dl_open_names) { + target.GetImages().FindFunctionSymbols( + ConstString(name), eFunctionNameTypeFull, matching_symbols); + if (matching_symbols.GetSize()) { + dl_open_name = name; + break; + } + } + // Older platform versions have the dl function symbols mangled + if (dl_open_name == dl_open_names[0]) + return R"( + extern "C" void* dlopen(const char*, int) asm("__dl_dlopen"); + extern "C" void* dlsym(void*, const char*) asm("__dl_dlsym"); + extern "C" int dlclose(void*) asm("__dl_dlclose"); + extern "C" char* dlerror(void) asm("__dl_dlerror"); + )"; + + return PlatformPOSIX::GetLibdlFunctionDeclarations(process); +} + +HdcClient::SyncService *PlatformHOS::GetSyncService(Status &error) { + if (m_adb_sync_svc && m_adb_sync_svc->IsConnected()) + return m_adb_sync_svc.get(); + + HdcClient hdc(m_device_id); + m_adb_sync_svc = hdc.GetSyncService(error); + return (error.Success()) ? m_adb_sync_svc.get() : nullptr; +} diff --git a/lldb/source/Plugins/Platform/HOS/PlatformHOS.h b/lldb/source/Plugins/Platform/HOS/PlatformHOS.h new file mode 100644 index 0000000000000000000000000000000000000000..07057ab83e26a2723914b47821ced07c6456b450 --- /dev/null +++ b/lldb/source/Plugins/Platform/HOS/PlatformHOS.h @@ -0,0 +1,82 @@ +//===-- PlatformHOS.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 liblldb_PlatformHOS_h_ +#define liblldb_PlatformHOS_h_ + +#include +#include + +//#include "Plugins/Platform/Android/PlatformAndroid.h" +#include "HdcClient.h" +#include "Plugins/Platform/Linux/PlatformLinux.h" + +namespace lldb_private { +namespace platform_hos { + +// class PlatformHOS : public platform_android::PlatformAndroid { +class PlatformHOS : public platform_linux::PlatformLinux { +public: + // PlatformHOS(bool is_host) : PlatformAndroid(is_host) {} + PlatformHOS(bool is_host); + // lldb_private::PluginInterface functions + ~PlatformHOS() override; + static void Initialize(); + + static void Terminate(); + + static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch); + + static ConstString GetPluginNameStatic(bool is_host); + + static const char *GetPluginDescriptionStatic(bool is_host); + + ConstString GetPluginName() override { return GetPluginNameStatic(IsHost()); } + + uint32_t GetPluginVersion() override { return 1; } + + Status ConnectRemote(Args &args) override; + + Status GetFile(const FileSpec &source, const FileSpec &destination) override; + + Status PutFile(const FileSpec &source, const FileSpec &destination, + uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX) override; + + uint32_t GetSdkVersion(); + + bool GetRemoteOSVersion() override; + + Status DisconnectRemote() override; + + uint32_t GetDefaultMemoryCacheLineSize() override; + +protected: + const char *GetCacheHostname() override; + + Status DownloadModuleSlice(const FileSpec &src_file_spec, + const uint64_t src_offset, const uint64_t src_size, + const FileSpec &dst_file_spec) override; + + Status DownloadSymbolFile(const lldb::ModuleSP &module_sp, + const FileSpec &dst_file_spec) override; + + llvm::StringRef + GetLibdlFunctionDeclarations(lldb_private::Process *process) override; + +private: + HdcClient::SyncService *GetSyncService(Status &error); + + std::unique_ptr m_adb_sync_svc; + std::string m_device_id; + uint32_t m_sdk_version; +}; + +} // namespace platform_hos +} // namespace lldb_private + +#endif // liblldb_PlatformHOS_h_ diff --git a/lldb/source/Plugins/Platform/HOS/PlatformHOSRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/HOS/PlatformHOSRemoteGDBServer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c311a93845349219cc158425620cb38484317c7 --- /dev/null +++ b/lldb/source/Plugins/Platform/HOS/PlatformHOSRemoteGDBServer.cpp @@ -0,0 +1,244 @@ +//===-- PlatformHOSRemoteGDBServer.cpp --------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/UriParser.h" + +#include "PlatformHOSRemoteGDBServer.h" + +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_hos; + +static const lldb::pid_t g_remote_platform_pid = + 0; // Alias for the process id of lldb-platform + +static Status ForwardPortWithHdc( + 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(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + + HdcClient hdc; + auto error = HdcClient::CreateByDeviceID(device_id, hdc); + if (error.Fail()) + return error; + + device_id = hdc.GetDeviceID(); + LLDB_LOGF(log, + "Hsu file(%s):%d function(ForwardPortWithHdc) Connected to Hos " + "device \"%s\"", + __FILE__, __LINE__, device_id.c_str()); + + if (remote_port != 0) { + LLDB_LOGF(log, + "Hsu file(%s):%d function(ForwardPortWithHdc) Forwarding remote " + "TCP port %d to local TCP port %d", + __FILE__, __LINE__, remote_port, local_port); + return hdc.SetPortForwarding(local_port, remote_port); + } + + LLDB_LOGF(log, "Forwarding remote socket \"%s\" to local TCP port %d", + remote_socket_name.str().c_str(), local_port); + + if (!socket_namespace) + return Status("Invalid socket namespace"); + + return hdc.SetPortForwarding(local_port, remote_socket_name, + *socket_namespace); +} + +static Status DeleteForwardPortWithHdc(uint16_t local_port, + const std::string &device_id) { + HdcClient hdc(device_id); + return hdc.DeletePortForwarding(local_port); +} + +static Status FindUnusedPort(uint16_t &port) { + Status error; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + std::unique_ptr tcp_socket(new TCPSocket(true, false)); + if (error.Fail()) + return error; + + error = tcp_socket->Listen("127.0.0.1:0", 1); + if (error.Success()) + port = tcp_socket->GetLocalPortNumber(); + + if (log) { + LLDB_LOGF(log, "Hsu file(%s):%d FindUnusedPort port(%d)", __FILE__, + __LINE__, port); + } + return error; +} + +PlatformHOSRemoteGDBServer::PlatformHOSRemoteGDBServer() {} + +PlatformHOSRemoteGDBServer::~PlatformHOSRemoteGDBServer() { + for (const auto &it : m_port_forwards) + DeleteForwardPortWithHdc(it.second, m_device_id); +} + +bool PlatformHOSRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid, + std::string &connect_url) { + uint16_t remote_port = 0; + std::string socket_name; + if (!m_gdb_client.LaunchGDBServer("127.0.0.1", pid, remote_port, socket_name)) + return false; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + + auto error = + MakeConnectURL(pid, remote_port, socket_name.c_str(), connect_url); + if (error.Success() && log) + LLDB_LOGF(log, "gdbserver connect URL: %s", connect_url.c_str()); + + return error.Success(); +} + +bool PlatformHOSRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) { + DeleteForwardPort(pid); + return m_gdb_client.KillSpawnedProcess(pid); +} + +Status PlatformHOSRemoteGDBServer::ConnectRemote(Args &args) { + m_device_id.clear(); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + + if (args.GetArgumentCount() != 1) + return Status( + "\"platform connect\" takes a single argument: "); + + int remote_port; + llvm::StringRef scheme, host, path; + const char *url = args.GetArgumentAtIndex(0); + if (!url) + return Status("URL is null."); + if (!UriParser::Parse(url, scheme, host, remote_port, path)) + return Status("Invalid URL: %s", url); + if (host != "localhost") + m_device_id = std::string(host); + + m_socket_namespace.reset(); + if (scheme == ConnectionFileDescriptor::UNIX_CONNECT_SCHEME) + m_socket_namespace = HdcClient::UnixSocketNamespaceFileSystem; + else if (scheme == ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME) + m_socket_namespace = HdcClient::UnixSocketNamespaceAbstract; + + std::string connect_url; + auto error = + MakeConnectURL(g_remote_platform_pid, (remote_port < 0) ? 0 : remote_port, + path, connect_url); + if (log) { + LLDB_LOGF(log, + "Hsu file(%s):%d g_remote_platform_pid(%lu) remote_port(%d) " + "connect_url(%s)", + __FILE__, __LINE__, g_remote_platform_pid, remote_port, + connect_url.c_str()); + } + if (error.Fail()) + return error; + + args.ReplaceArgumentAtIndex(0, connect_url); + + // Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + LLDB_LOGF(log, "Rewritten platform connect URL: %s", connect_url.c_str()); + + error = PlatformRemoteGDBServer::ConnectRemote(args); + if (error.Fail()) + DeleteForwardPort(g_remote_platform_pid); + + return error; +} + +Status PlatformHOSRemoteGDBServer::DisconnectRemote() { + DeleteForwardPort(g_remote_platform_pid); + return PlatformRemoteGDBServer::DisconnectRemote(); +} + +void PlatformHOSRemoteGDBServer::DeleteForwardPort(lldb::pid_t pid) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + + auto it = m_port_forwards.find(pid); + if (it == m_port_forwards.end()) + return; + + const auto port = it->second; + const auto error = DeleteForwardPortWithHdc(port, m_device_id); + if (error.Fail()) { + LLDB_LOGF(log, + "Failed to delete port forwarding (pid=%" PRIu64 + ", port=%d, device=%s): %s", + pid, port, m_device_id.c_str(), error.AsCString()); + } + m_port_forwards.erase(it); +} + +Status PlatformHOSRemoteGDBServer::MakeConnectURL( + const lldb::pid_t pid, const uint16_t remote_port, + llvm::StringRef remote_socket_name, std::string &connect_url) { + static const int kAttempsNum = 5; + + Status error; + // There is a race possibility that somebody will occupy a port while we're + // in between FindUnusedPort and ForwardPortWithHdc - adding the loop to + // mitigate such problem. + for (auto i = 0; i < kAttempsNum; ++i) { + uint16_t local_port = 0; + error = FindUnusedPort(local_port); + if (error.Fail()) + return error; + + error = ForwardPortWithHdc(local_port, remote_port, remote_socket_name, + m_socket_namespace, m_device_id); + if (error.Success()) { + m_port_forwards[pid] = local_port; + std::ostringstream url_str; + url_str << "connect://127.0.0.1:" << local_port; + connect_url = url_str.str(); + break; + } + } + + return error; +} + +lldb::ProcessSP PlatformHOSRemoteGDBServer::ConnectProcess( + llvm::StringRef connect_url, llvm::StringRef plugin_name, + lldb_private::Debugger &debugger, lldb_private::Target *target, + lldb_private::Status &error) { + // We don't have the pid of the remote gdbserver when it isn't started by us + // but we still want to store the list of port forwards we set up in our port + // forward map. Generate a fake pid for these cases what won't collide with + // any other valid pid on android. + static lldb::pid_t s_remote_gdbserver_fake_pid = 0xffffffffffffffffULL; + + int remote_port; + llvm::StringRef scheme, host, path; + if (!UriParser::Parse(connect_url, scheme, host, remote_port, path)) { + error.SetErrorStringWithFormat("Invalid URL: %s", + connect_url.str().c_str()); + return nullptr; + } + + std::string new_connect_url; + error = MakeConnectURL(s_remote_gdbserver_fake_pid--, + (remote_port < 0) ? 0 : remote_port, path, + new_connect_url); + if (error.Fail()) + return nullptr; + + return PlatformRemoteGDBServer::ConnectProcess(new_connect_url, plugin_name, + debugger, target, error); +} diff --git a/lldb/source/Plugins/Platform/HOS/PlatformHOSRemoteGDBServer.h b/lldb/source/Plugins/Platform/HOS/PlatformHOSRemoteGDBServer.h new file mode 100644 index 0000000000000000000000000000000000000000..c30b15dd9a803d841c6006b9f8d9f29c93cf1ee9 --- /dev/null +++ b/lldb/source/Plugins/Platform/HOS/PlatformHOSRemoteGDBServer.h @@ -0,0 +1,65 @@ +//===-- PlatformHOSRemoteGDBServer.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_SOURCE_PLUGINS_PLATFORM_HOS_PLATFORMHOSREMOTEGDBSERVER_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_HOS_PLATFORMHOSREMOTEGDBSERVER_H + +#include +#include + +#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h" + +#include "llvm/ADT/Optional.h" + +#include "HdcClient.h" + +namespace lldb_private { +namespace platform_hos { + +class PlatformHOSRemoteGDBServer + : public platform_gdb_server::PlatformRemoteGDBServer { +public: + PlatformHOSRemoteGDBServer(); + + ~PlatformHOSRemoteGDBServer() override; + + Status ConnectRemote(Args &args) override; + + Status DisconnectRemote() override; + + lldb::ProcessSP ConnectProcess(llvm::StringRef connect_url, + llvm::StringRef plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Status &error) override; + +protected: + std::string m_device_id; + std::map m_port_forwards; + llvm::Optional m_socket_namespace; + + bool LaunchGDBServer(lldb::pid_t &pid, std::string &connect_url) override; + + bool KillSpawnedProcess(lldb::pid_t pid) override; + + void DeleteForwardPort(lldb::pid_t pid); + + Status MakeConnectURL(const lldb::pid_t pid, const uint16_t remote_port, + llvm::StringRef remote_socket_name, + std::string &connect_url); + +private: + PlatformHOSRemoteGDBServer(const PlatformHOSRemoteGDBServer &) = delete; + const PlatformHOSRemoteGDBServer & + operator=(const PlatformHOSRemoteGDBServer &) = delete; +}; + +} // namespace platform_hos +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_HOS_PLATFORMANDROIDREMOTEGDBSERVER_H diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 8c3c2c0134541afb75258fd4c5010439711fcb5b..73b28a371369cef3623f273729b4cc059a6a2917 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -389,7 +389,7 @@ Platform::Platform(bool is_host) m_max_uid_name_len(0), m_max_gid_name_len(0), m_supports_rsync(false), m_rsync_opts(), m_rsync_prefix(), m_supports_ssh(false), m_ssh_opts(), m_ignores_remote_hostname(false), m_trap_handlers(), - m_calculated_trap_handlers(false), + m_container(false), m_calculated_trap_handlers(false), m_module_cache(std::make_unique()) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); LLDB_LOGF(log, "%p Platform::Platform()", static_cast(this)); @@ -404,8 +404,13 @@ Platform::~Platform() { LLDB_LOGF(log, "%p Platform::~Platform()", static_cast(this)); } +// platform select/connect θΏ”ε›žζŠ₯ζ–‡ void Platform::GetStatus(Stream &strm) { std::string s; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) { + LLDB_LOGF(log, "%p file(%s):%d Platform::GetStatus() call", static_cast(this), __FILE__, __LINE__); + } strm.Printf(" Platform: %s\n", GetPluginName().GetCString()); ArchSpec arch(GetSystemArchitecture()); @@ -431,9 +436,14 @@ void Platform::GetStatus(Stream &strm) { strm.Printf(" Hostname: %s\n", GetHostname()); } else { const bool is_connected = IsConnected(); + const bool is_container = GetContainer(); + if (log) { + LLDB_LOGF(log, "%p file(%s):%d Platform::GetStatus() is_container(%d) is_connected(%d)", static_cast(this), __FILE__, __LINE__, is_container, is_connected); + } if (is_connected) strm.Printf(" Hostname: %s\n", GetHostname()); strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); + strm.Printf(" Container: %s\n", is_container ? "yes" : "no"); } if (GetWorkingDirectory()) { diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp index 1e5856dd0b221443edf2081475b3190d12294271..1ea7dbad08c344a6e0f70f0f74a5f94c02eee3ff 100644 --- a/lldb/source/Target/TargetList.cpp +++ b/lldb/source/Target/TargetList.cpp @@ -62,6 +62,10 @@ Status TargetList::CreateTarget(Debugger &debugger, const ArchSpec &specified_arch, LoadDependentFiles load_dependent_files, PlatformSP &platform_sp, TargetSP &target_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) { + LLDB_LOGF(log,"file(%s):%d TargetList::%s call", __FILE__, __LINE__, __FUNCTION__); + } auto result = TargetList::CreateTargetInternal( debugger, user_exe_path, specified_arch, load_dependent_files, platform_sp, target_sp); @@ -76,7 +80,10 @@ Status TargetList::CreateTargetInternal( llvm::StringRef triple_str, LoadDependentFiles load_dependent_files, const OptionGroupPlatform *platform_options, TargetSP &target_sp) { Status error; - + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) { + LLDB_LOGF(log,"file(%s):%d TargetList::%s call", __FILE__, __LINE__, __FUNCTION__); + } // Let's start by looking at the selected platform. PlatformSP platform_sp = debugger.GetPlatformList().GetSelectedPlatform();