Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -100,6 +100,8 @@ 254FBBA51A91670E00BD6378 /* SBAttachInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 254FBBA41A91670E00BD6378 /* SBAttachInfo.cpp */; }; 257E47171AA56C2000A62F81 /* ModuleCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 257E47151AA56C2000A62F81 /* ModuleCache.cpp */; }; 257E47181AA56C2000A62F81 /* ModuleCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 257E47161AA56C2000A62F81 /* ModuleCache.h */; }; + 25EF23781AC09B3700908DF0 /* AdbClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25EF23751AC09AD800908DF0 /* AdbClient.cpp */; }; + 25EF23791AC09B4200908DF0 /* AdbClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 25EF23761AC09AD800908DF0 /* AdbClient.h */; }; 260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; 260157C81885F53100F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; 2606EDDF184E68A10034641B /* liblldb-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2689FFCA13353D7A00698AC0 /* liblldb-core.a */; }; @@ -1221,6 +1223,8 @@ 254FBBA61A91672800BD6378 /* SBAttachInfo.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBAttachInfo.i; sourceTree = ""; }; 257E47151AA56C2000A62F81 /* ModuleCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleCache.cpp; path = source/Utility/ModuleCache.cpp; sourceTree = ""; }; 257E47161AA56C2000A62F81 /* ModuleCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleCache.h; path = source/Utility/ModuleCache.h; sourceTree = ""; }; + 25EF23751AC09AD800908DF0 /* AdbClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdbClient.cpp; sourceTree = ""; }; + 25EF23761AC09AD800908DF0 /* AdbClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdbClient.h; sourceTree = ""; }; 260157C41885F4FF00F875CF /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = /usr/lib/libpanel.dylib; sourceTree = ""; }; 260223E7115F06D500A601A2 /* SBCommunication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBCommunication.h; path = include/lldb/API/SBCommunication.h; sourceTree = ""; }; 260223E8115F06E500A601A2 /* SBCommunication.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBCommunication.cpp; path = source/API/SBCommunication.cpp; sourceTree = ""; }; @@ -4971,6 +4975,8 @@ 6D55BAE61A8CD08C00A70529 /* Android */ = { isa = PBXGroup; children = ( + 25EF23751AC09AD800908DF0 /* AdbClient.cpp */, + 25EF23761AC09AD800908DF0 /* AdbClient.h */, 6D55BAE91A8CD08C00A70529 /* PlatformAndroid.cpp */, 6D55BAEA1A8CD08C00A70529 /* PlatformAndroid.h */, 6D55BAEB1A8CD08C00A70529 /* PlatformAndroidRemoteGDBServer.cpp */, @@ -5306,6 +5312,7 @@ 26CFDCA11861638D000E63E5 /* Editline.h in Headers */, 26BC17B018C7F4CB00D2196D /* RegisterContextPOSIXCore_x86_64.h in Headers */, 6D55BAF01A8CD0BD00A70529 /* PlatformAndroidRemoteGDBServer.h in Headers */, + 25EF23791AC09B4200908DF0 /* AdbClient.h in Headers */, AF9B8F34182DB52900DA866F /* SystemRuntimeMacOSX.h in Headers */, 26474CB518D0CB180073DEBA /* RegisterContextLinux_x86_64.h in Headers */, 26D1804716CEE12C00EDFB5B /* TimeSpecTimeout.h in Headers */, @@ -6086,6 +6093,7 @@ 268900C113353E5F00698AC0 /* DWARFDebugPubnames.cpp in Sources */, 268900C213353E5F00698AC0 /* DWARFDebugPubnamesSet.cpp in Sources */, 268900C313353E5F00698AC0 /* DWARFDebugRanges.cpp in Sources */, + 25EF23781AC09B3700908DF0 /* AdbClient.cpp in Sources */, 94380B8219940B0A00BFE4A8 /* StringLexer.cpp in Sources */, 268900C413353E5F00698AC0 /* DWARFDefines.cpp in Sources */, 94D0B10C16D5535900EA9C70 /* LibCxx.cpp in Sources */, Index: source/Plugins/Platform/Android/AdbClient.h =================================================================== --- /dev/null +++ source/Plugins/Platform/Android/AdbClient.h @@ -0,0 +1,69 @@ +//===-- AdbClient.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AdbClient_h_ +#define liblldb_AdbClient_h_ + +// C Includes + +// C++ Includes + +#include +#include + +// Other libraries and framework includes +// Project includes + +#include "lldb/Core/Error.h" + +namespace lldb_private { + +class AdbClient +{ +public: + using DeviceIDList = std::list; + + AdbClient () = default; + explicit AdbClient (const std::string &device_id); + + void + SetDeviceID (const std::string& device_id); + + Error + GetDevices (DeviceIDList &device_list); + + Error + SetPortForwarding (const uint16_t port); + + Error + DeletePortForwarding (const uint16_t port); + +private: + Error + Connect (); + + Error + SendMessage (const std::string &packet); + + Error + SendDeviceMessage (const std::string &packet); + + Error + ReadMessage (std::string &message); + + Error + ReadResponseStatus (); + + std::string m_device_id; + ConnectionFileDescriptor m_conn; +}; + +} // namespace lldb_private + +#endif // liblldb_AdbClient_h_ Index: source/Plugins/Platform/Android/AdbClient.cpp =================================================================== --- /dev/null +++ source/Plugins/Platform/Android/AdbClient.cpp @@ -0,0 +1,187 @@ +//===-- AdbClient.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Other libraries and framework includes +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/STLExtras.h" + +// Project includes +#include "AdbClient.h" + +#include + +using namespace lldb; +using namespace lldb_private; + +namespace { + +const uint32_t kConnTimeout = 10000; // 10 ms +const char * kOKAY = "OKAY"; +const char * kFAIL = "FAIL"; + +} // namespace + +AdbClient::AdbClient (const std::string &device_id) + : m_device_id (device_id) +{ +} + +void +AdbClient::SetDeviceID (const std::string& device_id) +{ + m_device_id = device_id; +} + +Error +AdbClient::Connect () +{ + Error error; + m_conn.Connect ("connect://localhost:5037", &error); + + return error; +} + +Error +AdbClient::GetDevices (DeviceIDList &device_list) +{ + device_list.clear (); + + auto error = SendMessage ("host:devices"); + if (error.Fail ()) + return error; + + error = ReadResponseStatus (); + if (error.Fail ()) + return error; + + std::string in_buffer; + error = ReadMessage (in_buffer); + + llvm::StringRef response (in_buffer); + llvm::SmallVector devices; + response.split (devices, "\n", -1, false); + + for (const auto device: devices) + device_list.push_back (device.split ('\t').first); + + return error; +} + +Error +AdbClient::SetPortForwarding (const uint16_t port) +{ + char message[48]; + snprintf (message, sizeof (message), "forward:tcp:%d;tcp:%d", port, port); + + const auto error = SendDeviceMessage (message); + if (error.Fail ()) + return error; + + return ReadResponseStatus (); +} + +Error +AdbClient::DeletePortForwarding (const uint16_t port) +{ + char message[32]; + snprintf (message, sizeof (message), "killforward:tcp:%d", port); + + const auto error = SendDeviceMessage (message); + if (error.Fail ()) + return error; + + return ReadResponseStatus (); +} + +Error +AdbClient::SendMessage (const std::string &packet) +{ + auto error = Connect (); + if (error.Fail ()) + return error; + + char length_buffer[5]; + snprintf (length_buffer, sizeof (length_buffer), "%04zx", 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; +} + +Error +AdbClient::SendDeviceMessage (const std::string &packet) +{ + std::ostringstream msg; + msg << "host-serial:" << m_device_id << ":" << packet; + return SendMessage (msg.str ()); +} + +Error +AdbClient::ReadMessage (std::string &message) +{ + message.clear (); + + char buffer[5]; + buffer[4] = 0; + + Error error; + ConnectionStatus status; + + m_conn.Read (buffer, 4, kConnTimeout, status, &error); + if (error.Fail ()) + return error; + + size_t packet_len = 0; + sscanf (buffer, "%zx", &packet_len); + std::string result (packet_len, 0); + m_conn.Read (&result[0], packet_len, kConnTimeout, status, &error); + if (error.Success ()) + result.swap (message); + + return error; +} + +Error +AdbClient::ReadResponseStatus() +{ + char buffer[5]; + + static const size_t packet_len = 4; + buffer[packet_len] = 0; + + Error error; + ConnectionStatus status; + + m_conn.Read (buffer, packet_len, kConnTimeout, status, &error); + if (error.Fail ()) + return error; + + if (strncmp (buffer, kOKAY, packet_len) != 0) + { + if (strncmp (buffer, kFAIL, packet_len) == 0) + { + std::string error_message; + error = ReadMessage (error_message); + if (error.Fail ()) + return error; + error.SetErrorString (error_message.c_str ()); + } + else + error.SetErrorStringWithFormat ("\"%s\" expected from adb, received: \"%s\"", kOKAY, buffer); + } + + return error; +} Index: source/Plugins/Platform/Android/CMakeLists.txt =================================================================== --- source/Plugins/Platform/Android/CMakeLists.txt +++ source/Plugins/Platform/Android/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_NO_RTTI 1) add_lldb_library(lldbPluginPlatformAndroid + AdbClient.cpp PlatformAndroid.cpp PlatformAndroidRemoteGDBServer.cpp ) Index: source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp =================================================================== --- source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -9,10 +9,12 @@ // Other libraries and framework includes #include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "llvm/ADT/StringRef.h" // Project includes +#include "AdbClient.h" #include "PlatformAndroidRemoteGDBServer.h" #include "Utility/UriParser.h" @@ -20,130 +22,37 @@ using namespace lldb_private; static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform -static const uint32_t g_adb_timeout = 10000; // 10 ms -static void -SendMessageToAdb (Connection& conn, const std::string& packet, Error& error) -{ - ConnectionStatus status; - - char length_buffer[5]; - snprintf (length_buffer, sizeof (length_buffer), "%04zx", packet.size()); - - conn.Write (length_buffer, 4, status, &error); - if (error.Fail ()) - return; - - conn.Write (packet.c_str(), packet.size(), status, &error); -} - -static std::string -ReadMessageFromAdb (Connection& conn, bool has_okay, Error& error) +static Error +ForwardPortWithAdb (uint16_t port, std::string& device_id) { - ConnectionStatus status; - - char buffer[5]; - buffer[4] = 0; - - if (has_okay) - { - conn.Read (buffer, 4, g_adb_timeout, status, &error); - if (error.Fail ()) - return ""; - - if (strncmp (buffer, "OKAY", 4) != 0) - { - error.SetErrorStringWithFormat ("\"OKAY\" expected from adb, received: \"%s\"", buffer); - return ""; - } - } + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); - conn.Read (buffer, 4, g_adb_timeout, status, &error); - if (error.Fail()) - return ""; + // Fetch the device list from ADB and if only 1 device found then use that device + // TODO: Handle the case when more device is available + AdbClient adb; - size_t packet_len = 0; - sscanf(buffer, "%zx", &packet_len); - std::string result(packet_len, 0); - conn.Read (&result[0], packet_len, g_adb_timeout, status, &error); + AdbClient::DeviceIDList connect_devices; + auto error = adb.GetDevices (connect_devices); if (error.Fail ()) - return ""; - - return result; -} - -static Error -ForwardPortWithAdb (uint16_t port, std::string& device_id) -{ - Error error; + return error; - { - // Fetch the device list from ADB and if only 1 device found then use that device - // TODO: Handle the case when more device is available - std::unique_ptr conn (new ConnectionFileDescriptor ()); - if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess) - return error; - - SendMessageToAdb (*conn, "host:devices", error); - if (error.Fail ()) - return error; - std::string in_buffer = ReadMessageFromAdb (*conn, true, error); - - llvm::StringRef deviceList(in_buffer); - std::pair devices = deviceList.split ('\n'); - if (devices.first.size () == 0 || devices.second.size () > 0) - { - error.SetErrorString ("Wrong number of devices returned from ADB"); - return error; - } - - device_id = devices.first.split ('\t').first; - } + if (connect_devices.size () != 1) + return Error ("Expected a single connected device, got instead %" PRIu64, connect_devices.size ()); - { - // Forward the port to the (only) connected device - std::unique_ptr conn (new ConnectionFileDescriptor ()); - if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess) - return error; - - char port_buffer[32]; - snprintf (port_buffer, sizeof (port_buffer), "tcp:%d;tcp:%d", port, port); - - std::string out_buffer = "host-serial:" + device_id + ":forward:" + port_buffer; - SendMessageToAdb (*conn, out_buffer, error); - if (error.Fail ()) - return error; - - std::string in_buffer = ReadMessageFromAdb (*conn, false, error); - if (in_buffer != "OKAY") - error.SetErrorString (in_buffer.c_str ()); - } + device_id = connect_devices.front (); + if (log) + log->Printf("Connected to Android device \"%s\"", device_id.c_str ()); - return error; + adb.SetDeviceID (device_id); + return adb.SetPortForwarding (port); } static Error DeleteForwardPortWithAdb (uint16_t port, const std::string& device_id) { - Error error; - - std::unique_ptr conn (new ConnectionFileDescriptor ()); - if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess) - return error; - - char port_buffer[16]; - snprintf (port_buffer, sizeof (port_buffer), "tcp:%d", port); - - std::string out_buffer = "host-serial:" + device_id + ":killforward:" + port_buffer; - SendMessageToAdb (*conn, out_buffer, error); - if (error.Fail ()) - return error; - - std::string in_buffer = ReadMessageFromAdb (*conn, true, error); - if (in_buffer != "OKAY") - error.SetErrorString (in_buffer.c_str ()); - - return error; + AdbClient adb (device_id); + return adb.DeletePortForwarding (port); } PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()