* Create new platform plugin for lldb * Create HostInfo class for android * Create ProcessLauncher for android Differential Revision: http://reviews.llvm.org/D7584 llvm-svn: 228943
225 lines
6.4 KiB
C++
225 lines
6.4 KiB
C++
//===-- 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/Host/ConnectionFileDescriptor.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
|
|
// Project includes
|
|
#include "PlatformAndroidRemoteGDBServer.h"
|
|
#include "Utility/UriParser.h"
|
|
|
|
using namespace lldb;
|
|
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)
|
|
{
|
|
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 "";
|
|
}
|
|
}
|
|
|
|
conn.Read (buffer, 4, g_adb_timeout, status, &error);
|
|
if (error.Fail())
|
|
return "";
|
|
|
|
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);
|
|
if (error.Fail ())
|
|
return "";
|
|
|
|
return result;
|
|
}
|
|
|
|
static Error
|
|
ForwardPortWithAdb (uint16_t port, std::string& device_id)
|
|
{
|
|
Error 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<ConnectionFileDescriptor> 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<llvm::StringRef, llvm::StringRef> 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;
|
|
}
|
|
|
|
{
|
|
// Forward the port to the (only) connected device
|
|
std::unique_ptr<ConnectionFileDescriptor> 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 ());
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static Error
|
|
DeleteForwardPortWithAdb (uint16_t port, const std::string& device_id)
|
|
{
|
|
Error error;
|
|
|
|
std::unique_ptr<ConnectionFileDescriptor> 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;
|
|
}
|
|
|
|
PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()
|
|
{
|
|
}
|
|
|
|
PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer ()
|
|
{
|
|
for (const auto& it : m_port_forwards)
|
|
{
|
|
DeleteForwardPortWithAdb (it.second.first, it.second.second);
|
|
}
|
|
}
|
|
|
|
uint16_t
|
|
PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
|
|
{
|
|
uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1");
|
|
if (port == 0)
|
|
return port;
|
|
|
|
std::string device_id;
|
|
Error error = ForwardPortWithAdb (port, device_id);
|
|
if (error.Fail ())
|
|
return 0;
|
|
|
|
m_port_forwards[pid] = std::make_pair (port, device_id);
|
|
|
|
return port;
|
|
}
|
|
|
|
bool
|
|
PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
|
|
{
|
|
auto it = m_port_forwards.find (pid);
|
|
if (it != m_port_forwards.end ())
|
|
{
|
|
DeleteForwardPortWithAdb (it->second.first, it->second.second);
|
|
m_port_forwards.erase (it);
|
|
}
|
|
|
|
return m_gdb_client.KillSpawnedProcess (pid);
|
|
}
|
|
|
|
Error
|
|
PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args)
|
|
{
|
|
if (args.GetArgumentCount () != 1)
|
|
return Error ("\"platform connect\" takes a single argument: <connect-url>");
|
|
|
|
int port;
|
|
std::string scheme, host, path;
|
|
const char *url = args.GetArgumentAtIndex (0);
|
|
if (!UriParser::Parse (url, scheme, host, port, path))
|
|
return Error ("invalid uri");
|
|
|
|
std::string device_id;
|
|
Error error = ForwardPortWithAdb (port, device_id);
|
|
if (error.Fail ())
|
|
return error;
|
|
|
|
m_port_forwards[g_remote_platform_pid] = std::make_pair (port, device_id);
|
|
|
|
return PlatformRemoteGDBServer::ConnectRemote (args);
|
|
}
|
|
|
|
Error
|
|
PlatformAndroidRemoteGDBServer::DisconnectRemote ()
|
|
{
|
|
auto it = m_port_forwards.find (g_remote_platform_pid);
|
|
if (it != m_port_forwards.end ())
|
|
{
|
|
DeleteForwardPortWithAdb (it->second.first, it->second.second);
|
|
m_port_forwards.erase (it);
|
|
}
|
|
|
|
return PlatformRemoteGDBServer::DisconnectRemote ();
|
|
}
|