splhack created this revision.
Herald added a subscriber: danielkiss.
Herald added a project: All.
splhack added a reviewer: clayborg.
splhack updated this revision to Diff 475962.
splhack added a comment.
splhack published this revision for review.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

First, recap: what is the Android serial number.
In Android ADB protocal, the serial number following the `host-serial:` is 
URL-safe string and it could be a `host:port` string.

https://cs.android.com/android/platform/superproject/+/763ab7bb17e9c63b238222085e1e69552d978367:packages/modules/adb/sockets.cpp;l=825?q=host-serial:

  if (android::base::ConsumePrefix(&service, "host-serial:")) {
      // serial number should follow "host:" and could be a host:port string.

Second, LLDB is not able to connect it to Android device when multiple devices 
are connected to the host.

  (lldb) platform select remote-android
  (lldb) platform connect unix-abstract-connect:///data/local/tmp/debug.sock
  error: Expected a single connected device, got instead 2 - try setting 
'ANDROID_SERIAL'

However setting ANDROID_SERIAL environment variable is not always a viable 
option.
For instance, VS Code + lldb-server and debugging multiple Android devices at 
the same time.

The potential solution is to use platform connect URL.

  (lldb) platform select remote-android
  (lldb) platform connect 
unix-abstract-connect://emulator-5554/data/local/tmp/debug.sock

This works for USB-connected devices and emulators.
But it does not work for TCP/IP-connected devices.

  (lldb) platform select remote-android
  (lldb) platform connect 
unix-abstract-connect://127.0.0.1:5556/data/local/tmp/debug.sock

The reason is that the current code only uses the hostname part of the URL.

https://github.com/llvm/llvm-project/blob/ed9638c44bc0c95314694fb878b21006e6c87510/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp#L154-L155

So m_device_id will be `127.0.0.1`. But this should be `127.0.0.1:5556`
Also `localhost` should not be skipped when the port number is available. 
m_device_id should be `localhost:5556`

  (lldb) platform connect 
unix-abstract-connect://localhost:5556/data/local/tmp/debug.sock

Third, the host could be IPv6, for instance `[::1]`.

  (lldb) platform connect 
unix-abstract-connect://[::1]:5556/data/local/tmp/debug.sock

This is a valid URL and serial number `[::1]:5556`.

The parsed_url does not look it has the information of IPv6 brackets. Thus, 
`GetDeviceIDFromURL` checks the raw URL again for the bracket.

Fourth, when a port number is available in the connect URL, `MakeConnectURL` 
function create a new TCP/IP forwarding with the port number. When `adb 
devices` shows a device with `host:port` style serial number, the port in the 
serial number is already connected or forwarded to the adb server. 
`host-serial:host:port` should work.

https://github.com/llvm/llvm-project/blob/ed9638c44bc0c95314694fb878b21006e6c87510/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp#L191-L192

https://github.com/llvm/llvm-project/blob/ed9638c44bc0c95314694fb878b21006e6c87510/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp#L42-L46


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D138164

Files:
  lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
  lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
  lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
  lldb/unittests/Platform/Android/CMakeLists.txt
  lldb/unittests/Platform/Android/PlatformAndroidRemoteGDBServerTest.cpp

Index: lldb/unittests/Platform/Android/PlatformAndroidRemoteGDBServerTest.cpp
===================================================================
--- /dev/null
+++ lldb/unittests/Platform/Android/PlatformAndroidRemoteGDBServerTest.cpp
@@ -0,0 +1,50 @@
+//===-- PlatformAndroidRemoteGDBServerTest.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 "Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h"
+#include "gtest/gtest.h"
+#include <cstdlib>
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace lldb_private {
+namespace platform_android {
+
+class PlatformAndroidRemoteGDBServerTest : public ::testing::Test {};
+
+TEST(PlatformAndroidRemoteGDBServerTest, GetDeviceIDFromURL) {
+  const static std::vector<std::map<std::string, std::string>> data{
+      {{"url", "unix-abstract-connect:///sock"}, {"serial", ""}},
+      {{"url", "unix-abstract-connect://localhost/sock"}, {"serial", ""}},
+      {{"url", "unix-abstract-connect://emulator-5554/sock"},
+       {"serial", "emulator-5554"}},
+      {{"url", "unix-abstract-connect://localhost:5556/sock"},
+       {"serial", "localhost:5556"}},
+      {{"url", "unix-abstract-connect://192.168.0.1:42/sock"},
+       {"serial", "192.168.0.1:42"}},
+      {{"url", "unix-abstract-connect://[::1]:5557/sock"},
+       {"serial", "[::1]:5557"}},
+      {{"url", "unix-abstract-connect://"
+               "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:5556/sock"},
+       {"serial", "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:5556"}},
+  };
+
+  for (const auto &map : data) {
+    const auto &url = map.at("url");
+    llvm::Optional<URI> parsed_url = URI::Parse(url);
+    EXPECT_TRUE(parsed_url);
+    EXPECT_EQ(
+        PlatformAndroidRemoteGDBServer::GetDeviceIDFromURL(url, parsed_url),
+        map.at("serial"));
+  }
+}
+
+} // end namespace platform_android
+} // end namespace lldb_private
Index: lldb/unittests/Platform/Android/CMakeLists.txt
===================================================================
--- lldb/unittests/Platform/Android/CMakeLists.txt
+++ lldb/unittests/Platform/Android/CMakeLists.txt
@@ -2,6 +2,7 @@
 
 add_lldb_unittest(AdbClientTests
   AdbClientTest.cpp
+  PlatformAndroidRemoteGDBServerTest.cpp
 
   LINK_LIBS
     lldbPluginPlatformAndroid
Index: lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
===================================================================
--- lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
+++ lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
@@ -28,6 +28,9 @@
 
   ~PlatformAndroidRemoteGDBServer() override;
 
+  static std::string GetDeviceIDFromURL(llvm::StringRef url,
+                                        llvm::Optional<URI> parsed_url);
+
   Status ConnectRemote(Args &args) override;
 
   Status DisconnectRemote() override;
Index: lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
===================================================================
--- lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
+++ lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
@@ -79,6 +79,23 @@
     DeleteForwardPortWithAdb(it.second, m_device_id);
 }
 
+std::string PlatformAndroidRemoteGDBServer::GetDeviceIDFromURL(
+    const llvm::StringRef url, llvm::Optional<URI> parsed_url) {
+  const llvm::StringRef kSchemeSepWithIPv6Bracket("://[");
+  auto pos = url.find(kSchemeSepWithIPv6Bracket);
+  std::string hostname;
+  if (pos == std::string::npos)
+    hostname = parsed_url->hostname.str();
+  else
+    hostname = "[" + parsed_url->hostname.str() + "]";
+
+  if (parsed_url->port.hasValue())
+    return hostname + ":" + std::to_string(parsed_url->port.value());
+  if (hostname != "localhost")
+    return hostname;
+  return std::string();
+}
+
 bool PlatformAndroidRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid,
                                                      std::string &connect_url) {
   assert(IsConnected());
@@ -122,8 +139,7 @@
   llvm::Optional<URI> parsed_url = URI::Parse(url);
   if (!parsed_url)
     return Status("Invalid URL: %s", url);
-  if (parsed_url->hostname != "localhost")
-    m_device_id = parsed_url->hostname.str();
+  m_device_id = GetDeviceIDFromURL(url, parsed_url);
 
   m_socket_namespace.reset();
   if (parsed_url->scheme == "unix-connect")
@@ -137,9 +153,8 @@
     local_port = std::stoi(platform_local_port);
 
   std::string connect_url;
-  auto error = MakeConnectURL(g_remote_platform_pid, local_port,
-                              parsed_url->port.value_or(0), parsed_url->path,
-                              connect_url);
+  auto error = MakeConnectURL(g_remote_platform_pid, local_port, 0,
+                              parsed_url->path, connect_url);
 
   if (error.Fail())
     return error;
@@ -236,8 +251,7 @@
   }
 
   std::string new_connect_url;
-  error = MakeConnectURL(s_remote_gdbserver_fake_pid--, 0,
-                         parsed_url->port.value_or(0), parsed_url->path,
+  error = MakeConnectURL(s_remote_gdbserver_fake_pid--, 0, 0, parsed_url->path,
                          new_connect_url);
   if (error.Fail())
     return nullptr;
Index: lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
===================================================================
--- lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
+++ lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
@@ -151,8 +151,7 @@
   llvm::Optional<URI> parsed_url = URI::Parse(url);
   if (!parsed_url)
     return Status("Invalid URL: %s", url);
-  if (parsed_url->hostname != "localhost")
-    m_device_id = parsed_url->hostname.str();
+  m_device_id = PlatformAndroidRemoteGDBServer::GetDeviceIDFromURL(url, parsed_url);
 
   auto error = PlatformLinux::ConnectRemote(args);
   if (error.Success()) {
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to