summaryrefslogtreecommitdiff
path: root/source/Plugins/Platform/Android
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Platform/Android')
-rw-r--r--source/Plugins/Platform/Android/AdbClient.cpp569
-rw-r--r--source/Plugins/Platform/Android/AdbClient.h132
-rw-r--r--source/Plugins/Platform/Android/CMakeLists.txt5
-rw-r--r--source/Plugins/Platform/Android/Makefile14
-rw-r--r--source/Plugins/Platform/Android/PlatformAndroid.cpp389
-rw-r--r--source/Plugins/Platform/Android/PlatformAndroid.h114
-rw-r--r--source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp275
-rw-r--r--source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h79
8 files changed, 1577 insertions, 0 deletions
diff --git a/source/Plugins/Platform/Android/AdbClient.cpp b/source/Plugins/Platform/Android/AdbClient.cpp
new file mode 100644
index 0000000000000..736447fd22d21
--- /dev/null
+++ b/source/Plugins/Platform/Android/AdbClient.cpp
@@ -0,0 +1,569 @@
+//===-- 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/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataEncoder.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/FileUtilities.h"
+
+// Project includes
+#include "AdbClient.h"
+
+#include <limits.h>
+
+#include <algorithm>
+#include <fstream>
+#include <sstream>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::platform_android;
+
+namespace {
+
+const uint32_t kReadTimeout = 1000000; // 1 second
+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";
+
+} // namespace
+
+Error
+AdbClient::CreateByDeviceID(const std::string &device_id, AdbClient &adb)
+{
+ DeviceIDList connect_devices;
+ auto error = adb.GetDevices(connect_devices);
+ if (error.Fail())
+ return error;
+
+ if (device_id.empty())
+ {
+ if (connect_devices.size() != 1)
+ return Error("Expected a single connected device, got instead %" PRIu64,
+ static_cast<uint64_t>(connect_devices.size()));
+
+ adb.SetDeviceID(connect_devices.front());
+ }
+ else
+ {
+ auto find_it = std::find(connect_devices.begin(), connect_devices.end(), device_id);
+ if (find_it == connect_devices.end())
+ return Error("Device \"%s\" not found", device_id.c_str());
+
+ adb.SetDeviceID(*find_it);
+ }
+ return error;
+}
+
+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;
+}
+
+const std::string&
+AdbClient::GetDeviceID() const
+{
+ return m_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::vector<char> in_buffer;
+ error = ReadMessage (in_buffer);
+
+ llvm::StringRef response (&in_buffer[0], in_buffer.size ());
+ llvm::SmallVector<llvm::StringRef, 4> 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 local_port, const uint16_t remote_port)
+{
+ char message[48];
+ snprintf (message, sizeof (message), "forward:tcp:%d;tcp:%d", local_port, remote_port);
+
+ const auto error = SendDeviceMessage (message);
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::SetPortForwarding (const uint16_t local_port,
+ const char* remote_socket_name,
+ const UnixSocketNamespace socket_namespace)
+{
+ 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);
+
+ const auto error = SendDeviceMessage (message);
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::DeletePortForwarding (const uint16_t local_port)
+{
+ char message[32];
+ snprintf (message, sizeof (message), "killforward:tcp:%d", local_port);
+
+ const auto error = SendDeviceMessage (message);
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::SendMessage (const std::string &packet, const bool reconnect)
+{
+ Error error;
+ if (reconnect)
+ {
+ error = Connect ();
+ if (error.Fail ())
+ return error;
+ }
+
+ char length_buffer[5];
+ snprintf (length_buffer, sizeof (length_buffer), "%04x", static_cast<int>(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::vector<char> &message)
+{
+ message.clear ();
+
+ 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;
+}
+
+Error
+AdbClient::ReadMessageStream (std::vector<char>& message, uint32_t timeout_ms)
+{
+ auto start = std::chrono::steady_clock::now();
+ message.clear();
+
+ Error error;
+ lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
+ char buffer[1024];
+ while (error.Success() && status == lldb::eConnectionStatusSuccess)
+ {
+ auto end = std::chrono::steady_clock::now();
+ uint32_t elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
+ if (elapsed_time >= timeout_ms)
+ return Error("Timed out");
+
+ size_t n = m_conn.Read(buffer, sizeof(buffer), 1000 * (timeout_ms - elapsed_time), status, &error);
+ if (n > 0)
+ message.insert(message.end(), &buffer[0], &buffer[n]);
+ }
+ return error;
+}
+
+Error
+AdbClient::ReadResponseStatus()
+{
+ char response_id[5];
+
+ 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 (strncmp (response_id, kOKAY, packet_len) != 0)
+ return GetResponseError (response_id);
+
+ return error;
+}
+
+Error
+AdbClient::GetResponseError (const char *response_id)
+{
+ if (strcmp (response_id, kFAIL) != 0)
+ return Error ("Got unexpected response id from adb: \"%s\"", response_id);
+
+ std::vector<char> error_message;
+ auto error = ReadMessage (error_message);
+ if (error.Success ())
+ error.SetErrorString (std::string (&error_message[0], error_message.size ()).c_str ());
+
+ return error;
+}
+
+Error
+AdbClient::SwitchDeviceTransport ()
+{
+ std::ostringstream msg;
+ msg << "host:transport:" << m_device_id;
+
+ auto error = SendMessage (msg.str ());
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::PullFile (const FileSpec &remote_file, const FileSpec &local_file)
+{
+ auto error = StartSync ();
+ if (error.Fail ())
+ return error;
+
+ const auto local_file_path = local_file.GetPath ();
+ llvm::FileRemover local_file_remover (local_file_path.c_str ());
+
+ std::ofstream dst (local_file_path, std::ios::out | std::ios::binary);
+ if (!dst.is_open ())
+ return Error ("Unable to open local file %s", local_file_path.c_str());
+
+ const auto remote_file_path = remote_file.GetPath (false);
+ error = SendSyncRequest (kRECV, remote_file_path.length (), remote_file_path.c_str ());
+ if (error.Fail ())
+ return error;
+
+ std::vector<char> chunk;
+ bool eof = false;
+ while (!eof)
+ {
+ error = PullFileChunk (chunk, eof);
+ if (error.Fail ())
+ return error;
+ if (!eof)
+ dst.write (&chunk[0], chunk.size ());
+ }
+
+ local_file_remover.releaseFile ();
+ return error;
+}
+
+Error
+AdbClient::PushFile (const FileSpec &local_file, const FileSpec &remote_file)
+{
+ auto error = StartSync ();
+ if (error.Fail ())
+ return error;
+
+ const auto local_file_path (local_file.GetPath ());
+ std::ifstream src (local_file_path.c_str(), std::ios::in | std::ios::binary);
+ if (!src.is_open ())
+ return Error ("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();
+ error = SendSyncRequest (kSEND, file_description_str.length(), 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 Error ("Failed to send file chunk: %s", error.AsCString ());
+ }
+ error = SendSyncRequest(kDONE, local_file.GetModificationTime().seconds(), nullptr);
+ if (error.Fail ())
+ return error;
+
+ std::string response_id;
+ uint32_t data_len;
+ error = ReadSyncHeader (response_id, data_len);
+ if (error.Fail ())
+ return Error ("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 Error ("Failed to read DONE error message: %s", error.AsCString ());
+ return Error ("Failed to push file: %s", error_message.c_str ());
+ }
+ else if (response_id != kOKAY)
+ return Error ("Got unexpected DONE response: %s", response_id.c_str ());
+
+ // If there was an error reading the source file, finish the adb file
+ // transfer first so that adb isn't expecting any more data.
+ if (src.bad())
+ return Error ("Failed read on %s", local_file_path.c_str());
+ return error;
+}
+
+Error
+AdbClient::StartSync ()
+{
+ auto error = SwitchDeviceTransport ();
+ if (error.Fail ())
+ return Error ("Failed to switch to device transport: %s", error.AsCString ());
+
+ error = Sync ();
+ if (error.Fail ())
+ return Error ("Sync failed: %s", error.AsCString ());
+
+ return error;
+}
+
+Error
+AdbClient::Sync ()
+{
+ auto error = SendMessage ("sync:", false);
+ if (error.Fail ())
+ return error;
+
+ return ReadResponseStatus ();
+}
+
+Error
+AdbClient::PullFileChunk (std::vector<char> &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 Error ("Failed to read pull error message: %s", error.AsCString ());
+ return Error ("Failed to pull file: %s", error_message.c_str ());
+ }
+ else
+ return Error ("Pull failed with unknown response: %s", response_id.c_str ());
+
+ return Error ();
+}
+
+Error
+AdbClient::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.PutU32 (offset, data_len);
+
+ Error 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;
+}
+
+Error
+AdbClient::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;
+}
+
+Error
+AdbClient::ReadAllBytes (void *buffer, size_t size)
+{
+ Error error;
+ ConnectionStatus status;
+ char *read_buffer = static_cast<char*>(buffer);
+
+ size_t tota_read_bytes = 0;
+ while (tota_read_bytes < size)
+ {
+ auto read_bytes = m_conn.Read (read_buffer + tota_read_bytes, size - tota_read_bytes, kReadTimeout, status, &error);
+ if (error.Fail ())
+ return error;
+ tota_read_bytes += read_bytes;
+ }
+ return error;
+}
+
+Error
+AdbClient::Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime)
+{
+ auto error = StartSync ();
+ if (error.Fail ())
+ return error;
+
+ const std::string remote_file_path (remote_file.GetPath (false));
+ error = SendSyncRequest (kSTAT, remote_file_path.length (), remote_file_path.c_str ());
+ if (error.Fail ())
+ return Error ("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<char> buffer (response_len);
+ error = ReadAllBytes (&buffer[0], buffer.size ());
+ if (error.Fail ())
+ return Error ("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 Error ("Failed to get response command");
+ const char* command_str = static_cast<const char*> (command);
+ if (strncmp (command_str, kSTAT, stat_len))
+ return Error ("Got invalid stat command: %s", command_str);
+
+ mode = extractor.GetU32 (&offset);
+ size = extractor.GetU32 (&offset);
+ mtime = extractor.GetU32 (&offset);
+ return Error ();
+}
+
+Error
+AdbClient::Shell (const char* command, uint32_t timeout_ms, std::string* output)
+{
+ auto error = SwitchDeviceTransport ();
+ if (error.Fail ())
+ return Error ("Failed to switch to device transport: %s", error.AsCString ());
+
+ StreamString adb_command;
+ adb_command.Printf("shell:%s", command);
+ error = SendMessage (adb_command.GetData(), false);
+ if (error.Fail ())
+ return error;
+
+ error = ReadResponseStatus ();
+ if (error.Fail ())
+ return error;
+
+ std::vector<char> in_buffer;
+ error = ReadMessageStream (in_buffer, timeout_ms);
+ if (error.Fail())
+ return error;
+
+ if (output)
+ output->assign(in_buffer.begin(), in_buffer.end());
+ return error;
+}
diff --git a/source/Plugins/Platform/Android/AdbClient.h b/source/Plugins/Platform/Android/AdbClient.h
new file mode 100644
index 0000000000000..4ec411d1411dd
--- /dev/null
+++ b/source/Plugins/Platform/Android/AdbClient.h
@@ -0,0 +1,132 @@
+//===-- 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 <list>
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+
+namespace lldb_private {
+
+class FileSpec;
+
+namespace platform_android {
+
+class AdbClient
+{
+public:
+ enum UnixSocketNamespace
+ {
+ UnixSocketNamespaceAbstract,
+ UnixSocketNamespaceFileSystem,
+ };
+
+ using DeviceIDList = std::list<std::string>;
+
+ static Error
+ CreateByDeviceID(const std::string &device_id, AdbClient &adb);
+
+ AdbClient () = default;
+ explicit AdbClient (const std::string &device_id);
+
+ const std::string&
+ GetDeviceID() const;
+
+ Error
+ GetDevices (DeviceIDList &device_list);
+
+ Error
+ SetPortForwarding (const uint16_t local_port, const uint16_t remote_port);
+
+ Error
+ SetPortForwarding (const uint16_t local_port,
+ const char* remote_socket_name,
+ const UnixSocketNamespace socket_namespace);
+
+ Error
+ DeletePortForwarding (const uint16_t local_port);
+
+ Error
+ PullFile (const FileSpec &remote_file, const FileSpec &local_file);
+
+ Error
+ PushFile (const FileSpec &local_file, const FileSpec &remote_file);
+
+ Error
+ Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime);
+
+ Error
+ Shell (const char* command, uint32_t timeout_ms, std::string* output);
+
+private:
+ Error
+ Connect ();
+
+ void
+ SetDeviceID (const std::string &device_id);
+
+ Error
+ SendMessage (const std::string &packet, const bool reconnect = true);
+
+ Error
+ SendDeviceMessage (const std::string &packet);
+
+ Error
+ SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data);
+
+ Error
+ ReadSyncHeader (std::string &response_id, uint32_t &data_len);
+
+ Error
+ ReadMessage (std::vector<char> &message);
+
+ Error
+ ReadMessageStream (std::vector<char> &message, uint32_t timeout_ms);
+
+ Error
+ GetResponseError (const char *response_id);
+
+ Error
+ ReadResponseStatus ();
+
+ Error
+ SwitchDeviceTransport ();
+
+ Error
+ Sync ();
+
+ Error
+ StartSync ();
+
+ Error
+ PullFileChunk (std::vector<char> &buffer, bool &eof);
+
+ Error
+ ReadAllBytes (void *buffer, size_t size);
+
+ std::string m_device_id;
+ ConnectionFileDescriptor m_conn;
+};
+
+} // namespace platform_android
+} // namespace lldb_private
+
+#endif // liblldb_AdbClient_h_
diff --git a/source/Plugins/Platform/Android/CMakeLists.txt b/source/Plugins/Platform/Android/CMakeLists.txt
new file mode 100644
index 0000000000000..e831a33a4b6d4
--- /dev/null
+++ b/source/Plugins/Platform/Android/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_lldb_library(lldbPluginPlatformAndroid
+ AdbClient.cpp
+ PlatformAndroid.cpp
+ PlatformAndroidRemoteGDBServer.cpp
+ )
diff --git a/source/Plugins/Platform/Android/Makefile b/source/Plugins/Platform/Android/Makefile
new file mode 100644
index 0000000000000..aa186f924e66c
--- /dev/null
+++ b/source/Plugins/Platform/Android/Makefile
@@ -0,0 +1,14 @@
+##===- source/Plugins/Platform/Android/Makefile ------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LLDB_LEVEL := ../../../..
+LIBRARYNAME := lldbPluginPlatformAndroid
+BUILD_ARCHIVE = 1
+
+include $(LLDB_LEVEL)/Makefile
diff --git a/source/Plugins/Platform/Android/PlatformAndroid.cpp b/source/Plugins/Platform/Android/PlatformAndroid.cpp
new file mode 100644
index 0000000000000..e842884c046a3
--- /dev/null
+++ b/source/Plugins/Platform/Android/PlatformAndroid.cpp
@@ -0,0 +1,389 @@
+//===-- PlatformAndroid.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/StringConvert.h"
+#include "Utility/UriParser.h"
+
+// Project includes
+#include "AdbClient.h"
+#include "PlatformAndroid.h"
+#include "PlatformAndroidRemoteGDBServer.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::platform_android;
+
+static uint32_t g_initialize_count = 0;
+static const unsigned int g_android_default_cache_size = 2048; // Fits inside 4k adb packet.
+
+void
+PlatformAndroid::Initialize ()
+{
+ PlatformLinux::Initialize ();
+
+ if (g_initialize_count++ == 0)
+ {
+#if defined(__ANDROID__)
+ PlatformSP default_platform_sp (new PlatformAndroid(true));
+ default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
+ Platform::SetHostPlatform (default_platform_sp);
+#endif
+ PluginManager::RegisterPlugin (PlatformAndroid::GetPluginNameStatic(false),
+ PlatformAndroid::GetPluginDescriptionStatic(false),
+ PlatformAndroid::CreateInstance);
+ }
+}
+
+void
+PlatformAndroid::Terminate ()
+{
+ if (g_initialize_count > 0)
+ {
+ if (--g_initialize_count == 0)
+ {
+ PluginManager::UnregisterPlugin (PlatformAndroid::CreateInstance);
+ }
+ }
+
+ PlatformLinux::Terminate ();
+}
+
+PlatformSP
+PlatformAndroid::CreateInstance (bool force, const ArchSpec *arch)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ {
+ const char *arch_name;
+ if (arch && arch->GetArchitectureName ())
+ arch_name = arch->GetArchitectureName ();
+ else
+ arch_name = "<null>";
+
+ const char *triple_cstr = arch ? arch->GetTriple ().getTriple ().c_str() : "<null>";
+
+ log->Printf ("PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+ }
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::PC:
+ create = true;
+ break;
+
+#if defined(__ANDROID__)
+ // Only accept "unknown" for the vendor if the host is android and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified_
+ case llvm::Triple::VendorType::UnknownVendor:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::Android:
+ break;
+
+#if defined(__ANDROID__)
+ // Only accept "unknown" for the OS if the host is android and
+ // it "unknown" wasn't specified (it was just returned because it
+ // was NOT specified)
+ case llvm::Triple::OSType::UnknownOS:
+ create = !arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+
+ if (create)
+ {
+ if (log)
+ log->Printf ("PlatformAndroid::%s() creating remote-android platform", __FUNCTION__);
+ return PlatformSP(new PlatformAndroid(false));
+ }
+
+ if (log)
+ log->Printf ("PlatformAndroid::%s() aborting creation of remote-android platform", __FUNCTION__);
+
+ return PlatformSP();
+}
+
+PlatformAndroid::PlatformAndroid (bool is_host) :
+ PlatformLinux(is_host),
+ m_sdk_version(0)
+{
+}
+
+PlatformAndroid::~PlatformAndroid()
+{
+}
+
+ConstString
+PlatformAndroid::GetPluginNameStatic (bool is_host)
+{
+ if (is_host)
+ {
+ static ConstString g_host_name(Platform::GetHostPlatformName ());
+ return g_host_name;
+ }
+ else
+ {
+ static ConstString g_remote_name("remote-android");
+ return g_remote_name;
+ }
+}
+
+const char *
+PlatformAndroid::GetPluginDescriptionStatic (bool is_host)
+{
+ if (is_host)
+ return "Local Android user platform plug-in.";
+ else
+ return "Remote Android user platform plug-in.";
+}
+
+ConstString
+PlatformAndroid::GetPluginName()
+{
+ return GetPluginNameStatic(IsHost());
+}
+
+Error
+PlatformAndroid::ConnectRemote(Args& args)
+{
+ m_device_id.clear();
+
+ if (IsHost())
+ {
+ return Error ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString());
+ }
+
+ if (!m_remote_platform_sp)
+ m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer());
+
+ int port;
+ std::string scheme, host, path;
+ const char *url = args.GetArgumentAtIndex(0);
+ if (!url)
+ return Error("URL is null.");
+ if (!UriParser::Parse(url, scheme, host, port, path))
+ return Error("Invalid URL: %s", url);
+ if (host != "localhost")
+ m_device_id = host;
+
+ auto error = PlatformLinux::ConnectRemote(args);
+ if (error.Success())
+ {
+ AdbClient adb;
+ error = AdbClient::CreateByDeviceID(m_device_id, adb);
+ if (error.Fail())
+ return error;
+
+ m_device_id = adb.GetDeviceID();
+ }
+ return error;
+}
+
+Error
+PlatformAndroid::GetFile (const FileSpec& source,
+ const FileSpec& destination)
+{
+ if (IsHost() || !m_remote_platform_sp)
+ return PlatformLinux::GetFile(source, destination);
+
+ FileSpec source_spec (source.GetPath (false), false, FileSpec::ePathSyntaxPosix);
+ if (source_spec.IsRelative())
+ source_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (source_spec.GetCString (false));
+
+ AdbClient adb (m_device_id);
+ return adb.PullFile (source_spec, destination);
+}
+
+Error
+PlatformAndroid::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), false, FileSpec::ePathSyntaxPosix);
+ if (destination_spec.IsRelative())
+ destination_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (destination_spec.GetCString (false));
+
+ AdbClient adb (m_device_id);
+ // TODO: Set correct uid and gid on remote file.
+ return adb.PushFile(source, destination_spec);
+}
+
+const char *
+PlatformAndroid::GetCacheHostname ()
+{
+ return m_device_id.c_str ();
+}
+
+Error
+PlatformAndroid::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 Error ("Invalid offset - %" PRIu64, src_offset);
+
+ return GetFile (src_file_spec, dst_file_spec);
+}
+
+Error
+PlatformAndroid::DisconnectRemote()
+{
+ Error error = PlatformLinux::DisconnectRemote();
+ if (error.Success())
+ {
+ m_device_id.clear();
+ m_sdk_version = 0;
+ }
+ return error;
+}
+
+uint32_t
+PlatformAndroid::GetDefaultMemoryCacheLineSize()
+{
+ return g_android_default_cache_size;
+}
+
+uint32_t
+PlatformAndroid::GetSdkVersion()
+{
+ if (!IsConnected())
+ return 0;
+
+ if (m_sdk_version != 0)
+ return m_sdk_version;
+
+ std::string version_string;
+ AdbClient adb(m_device_id);
+ Error error = adb.Shell("getprop ro.build.version.sdk", 5000 /* ms */, &version_string);
+ version_string = llvm::StringRef(version_string).trim().str();
+
+ if (error.Fail() || version_string.empty())
+ {
+ Log* log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM);
+ if (log)
+ log->Printf("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;
+}
+
+Error
+PlatformAndroid::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
+ if (module_sp->GetFileSpec().GetFileNameExtension() != ConstString("oat"))
+ return Error("Symbol file downloading only supported for oat files");
+
+ // If we have no information about the platform file we can't execute oatdump
+ if (!module_sp->GetPlatformFileSpec())
+ return Error("No platform file specified");
+
+ // Symbolizer isn't available before SDK version 23
+ if (GetSdkVersion() < 23)
+ return Error("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 Error("Symtab already available in the module");
+
+ AdbClient adb(m_device_id);
+
+ std::string tmpdir;
+ Error error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp", 5000 /* ms */, &tmpdir);
+ if (error.Fail() || tmpdir.empty())
+ return Error("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<std::string, std::function<void(std::string*)>> tmpdir_remover(
+ &tmpdir,
+ [this, &adb](std::string* s) {
+ StreamString command;
+ command.Printf("rm -rf %s", s->c_str());
+ Error error = adb.Shell(command.GetData(), 5000 /* ms */, nullptr);
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (error.Fail())
+ log->Printf("Failed to remove temp directory: %s", error.AsCString());
+ }
+ );
+
+ FileSpec symfile_platform_filespec(tmpdir.c_str(), false);
+ 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 = adb.Shell(command.GetData(), 60000 /* ms */, nullptr);
+ if (error.Fail())
+ return Error("Oatdump failed: %s", error.AsCString());
+
+ // Download the symbolfile from the remote device
+ return GetFile(symfile_platform_filespec, dst_file_spec);
+}
+
+bool
+PlatformAndroid::GetRemoteOSVersion ()
+{
+ m_major_os_version = GetSdkVersion();
+ m_minor_os_version = 0;
+ m_update_os_version = 0;
+ return m_major_os_version != 0;
+}
+
+const char*
+PlatformAndroid::GetLibdlFunctionDeclarations() const
+{
+ 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");
+ )";
+}
diff --git a/source/Plugins/Platform/Android/PlatformAndroid.h b/source/Plugins/Platform/Android/PlatformAndroid.h
new file mode 100644
index 0000000000000..119d0a0bdf04d
--- /dev/null
+++ b/source/Plugins/Platform/Android/PlatformAndroid.h
@@ -0,0 +1,114 @@
+//===-- PlatformAndroid.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_PlatformAndroid_h_
+#define liblldb_PlatformAndroid_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Platform/Linux/PlatformLinux.h"
+
+namespace lldb_private {
+namespace platform_android {
+
+ class PlatformAndroid : public platform_linux::PlatformLinux
+ {
+ public:
+ PlatformAndroid(bool is_host);
+
+ ~PlatformAndroid() override;
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ 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;
+
+ uint32_t
+ GetPluginVersion() override
+ {
+ return 1;
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+
+ Error
+ ConnectRemote (Args& args) override;
+
+ Error
+ GetFile (const FileSpec& source,
+ const FileSpec& destination) override;
+
+ Error
+ PutFile (const FileSpec& source,
+ const FileSpec& destination,
+ uint32_t uid = UINT32_MAX,
+ uint32_t gid = UINT32_MAX) override;
+
+ uint32_t
+ GetSdkVersion();
+
+ bool
+ GetRemoteOSVersion() override;
+
+ Error
+ DisconnectRemote () override;
+
+ uint32_t
+ GetDefaultMemoryCacheLineSize() override;
+
+ protected:
+ const char *
+ GetCacheHostname () override;
+
+ Error
+ DownloadModuleSlice (const FileSpec &src_file_spec,
+ const uint64_t src_offset,
+ const uint64_t src_size,
+ const FileSpec &dst_file_spec) override;
+
+ Error
+ DownloadSymbolFile (const lldb::ModuleSP& module_sp,
+ const FileSpec& dst_file_spec) override;
+
+ const char*
+ GetLibdlFunctionDeclarations() const override;
+
+ private:
+ std::string m_device_id;
+ uint32_t m_sdk_version;
+
+ DISALLOW_COPY_AND_ASSIGN (PlatformAndroid);
+ };
+
+} // namespace platofor_android
+} // namespace lldb_private
+
+#endif // liblldb_PlatformAndroid_h_
diff --git a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
new file mode 100644
index 0000000000000..3d91dd6b7a32f
--- /dev/null
+++ b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
@@ -0,0 +1,275 @@
+//===-- PlatformAndroidRemoteGDBServer.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/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "PlatformAndroidRemoteGDBServer.h"
+#include "Utility/UriParser.h"
+
+#include <sstream>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace platform_android;
+
+static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform
+
+static Error
+ForwardPortWithAdb (const uint16_t local_port,
+ const uint16_t remote_port,
+ const char* remote_socket_name,
+ const llvm::Optional<AdbClient::UnixSocketNamespace>& socket_namespace,
+ std::string& device_id)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+
+ AdbClient adb;
+ auto error = AdbClient::CreateByDeviceID(device_id, adb);
+ if (error.Fail ())
+ return error;
+
+ device_id = adb.GetDeviceID();
+ if (log)
+ log->Printf("Connected to Android device \"%s\"", device_id.c_str ());
+
+ if (remote_port != 0)
+ {
+ if (log)
+ log->Printf("Forwarding remote TCP port %d to local TCP port %d", remote_port, local_port);
+ return adb.SetPortForwarding(local_port, remote_port);
+ }
+
+ if (log)
+ log->Printf("Forwarding remote socket \"%s\" to local TCP port %d", remote_socket_name, local_port);
+
+ if (!socket_namespace)
+ return Error("Invalid socket namespace");
+
+ return adb.SetPortForwarding(local_port, remote_socket_name, *socket_namespace);
+}
+
+static Error
+DeleteForwardPortWithAdb (uint16_t local_port, const std::string& device_id)
+{
+ AdbClient adb (device_id);
+ return adb.DeletePortForwarding (local_port);
+}
+
+static Error
+FindUnusedPort (uint16_t& port)
+{
+ Error error;
+ std::unique_ptr<TCPSocket> tcp_socket(new TCPSocket(false, error));
+ if (error.Fail())
+ return error;
+
+ error = tcp_socket->Listen("127.0.0.1:0", 1);
+ if (error.Success())
+ port = tcp_socket->GetLocalPortNumber();
+
+ return error;
+}
+
+PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()
+{
+}
+
+PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer ()
+{
+ for (const auto& it : m_port_forwards)
+ DeleteForwardPortWithAdb(it.second, m_device_id);
+}
+
+bool
+PlatformAndroidRemoteGDBServer::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)
+ log->Printf("gdbserver connect URL: %s", connect_url.c_str());
+
+ return error.Success();
+}
+
+bool
+PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
+{
+ DeleteForwardPort (pid);
+ return m_gdb_client.KillSpawnedProcess (pid);
+}
+
+Error
+PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args)
+{
+ m_device_id.clear();
+
+ if (args.GetArgumentCount() != 1)
+ return Error("\"platform connect\" takes a single argument: <connect-url>");
+
+ int remote_port;
+ std::string scheme, host, path;
+ const char *url = args.GetArgumentAtIndex (0);
+ if (!url)
+ return Error("URL is null.");
+ if (!UriParser::Parse (url, scheme, host, remote_port, path))
+ return Error("Invalid URL: %s", url);
+ if (host != "localhost")
+ m_device_id = host;
+
+ m_socket_namespace.reset();
+ if (scheme == ConnectionFileDescriptor::UNIX_CONNECT_SCHEME)
+ m_socket_namespace = AdbClient::UnixSocketNamespaceFileSystem;
+ else if (scheme == ConnectionFileDescriptor::UNIX_ABSTRACT_CONNECT_SCHEME)
+ m_socket_namespace = AdbClient::UnixSocketNamespaceAbstract;
+
+ std::string connect_url;
+ auto error = MakeConnectURL (g_remote_platform_pid,
+ (remote_port < 0) ? 0 : remote_port,
+ path.c_str (),
+ connect_url);
+
+ if (error.Fail ())
+ return error;
+
+ args.ReplaceArgumentAtIndex (0, connect_url.c_str ());
+
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf("Rewritten platform connect URL: %s", connect_url.c_str());
+
+ error = PlatformRemoteGDBServer::ConnectRemote(args);
+ if (error.Fail ())
+ DeleteForwardPort (g_remote_platform_pid);
+
+ return error;
+}
+
+Error
+PlatformAndroidRemoteGDBServer::DisconnectRemote ()
+{
+ DeleteForwardPort (g_remote_platform_pid);
+ return PlatformRemoteGDBServer::DisconnectRemote ();
+}
+
+void
+PlatformAndroidRemoteGDBServer::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 = DeleteForwardPortWithAdb(port, m_device_id);
+ if (error.Fail()) {
+ if (log)
+ log->Printf("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);
+}
+
+Error
+PlatformAndroidRemoteGDBServer::MakeConnectURL(const lldb::pid_t pid,
+ const uint16_t remote_port,
+ const char* remote_socket_name,
+ std::string& connect_url)
+{
+ static const int kAttempsNum = 5;
+
+ Error error;
+ // There is a race possibility that somebody will occupy
+ // a port while we're in between FindUnusedPort and ForwardPortWithAdb -
+ // 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 = ForwardPortWithAdb(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://localhost:" << local_port;
+ connect_url = url_str.str();
+ break;
+ }
+ }
+
+ return error;
+}
+
+lldb::ProcessSP
+PlatformAndroidRemoteGDBServer::ConnectProcess(const char* connect_url,
+ const char* plugin_name,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target,
+ lldb_private::Error &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;
+ std::string scheme, host, path;
+ if (!UriParser::Parse(connect_url, scheme, host, remote_port, path))
+ {
+ error.SetErrorStringWithFormat("Invalid URL: %s", connect_url);
+ return nullptr;
+ }
+
+ std::string new_connect_url;
+ error = MakeConnectURL(s_remote_gdbserver_fake_pid--,
+ (remote_port < 0) ? 0 : remote_port,
+ path.c_str(),
+ new_connect_url);
+ if (error.Fail())
+ return nullptr;
+
+ return PlatformRemoteGDBServer::ConnectProcess(new_connect_url.c_str(),
+ plugin_name,
+ debugger,
+ target,
+ error);
+}
+
+size_t
+PlatformAndroidRemoteGDBServer::ConnectToWaitingProcesses(Debugger& debugger, Error& error)
+{
+ std::vector<std::string> connection_urls;
+ GetPendingGdbServerList(connection_urls);
+
+ for (size_t i = 0; i < connection_urls.size(); ++i)
+ {
+ ConnectProcess(connection_urls[i].c_str(), nullptr, debugger, nullptr, error);
+ if (error.Fail())
+ return i; // We already connected to i process succsessfully
+ }
+ return connection_urls.size();
+}
diff --git a/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
new file mode 100644
index 0000000000000..3d2653812dedc
--- /dev/null
+++ b/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
@@ -0,0 +1,79 @@
+//===-- PlatformAndroidRemoteGDBServer.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_PlatformAndroidRemoteGDBServer_h_
+#define liblldb_PlatformAndroidRemoteGDBServer_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <utility>
+
+// Other libraries and framework includes
+// Project includes
+#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
+
+#include "llvm/ADT/Optional.h"
+
+#include "AdbClient.h"
+
+namespace lldb_private {
+namespace platform_android {
+
+class PlatformAndroidRemoteGDBServer : public platform_gdb_server::PlatformRemoteGDBServer
+{
+public:
+ PlatformAndroidRemoteGDBServer();
+
+ ~PlatformAndroidRemoteGDBServer() override;
+
+ Error
+ ConnectRemote (Args& args) override;
+
+ Error
+ DisconnectRemote () override;
+
+ lldb::ProcessSP
+ ConnectProcess (const char* connect_url,
+ const char* plugin_name,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target,
+ lldb_private::Error &error) override;
+
+ size_t
+ ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) override;
+
+protected:
+ std::string m_device_id;
+ std::map<lldb::pid_t, uint16_t> m_port_forwards;
+ llvm::Optional<AdbClient::UnixSocketNamespace> 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);
+
+ Error
+ MakeConnectURL(const lldb::pid_t pid,
+ const uint16_t remote_port,
+ const char* remote_socket_name,
+ std::string& connect_url);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformAndroidRemoteGDBServer);
+};
+
+} // namespace platform_android
+} // namespace lldb_private
+
+#endif // liblldb_PlatformAndroidRemoteGDBServer_h_