LLDB  mainline
PlatformAndroid.cpp
Go to the documentation of this file.
1 //===-- PlatformAndroid.cpp -------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Core/Module.h"
11 #include "lldb/Core/Section.h"
12 #include "lldb/Core/ValueObject.h"
13 #include "lldb/Host/HostInfo.h"
15 #include "lldb/Utility/Log.h"
16 #include "lldb/Utility/Scalar.h"
17 #include "lldb/Utility/UriParser.h"
18 
19 #include "AdbClient.h"
20 #include "PlatformAndroid.h"
22 #include "lldb/Target/Target.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 using namespace lldb_private::platform_android;
27 using namespace std::chrono;
28 
30 static const unsigned int g_android_default_cache_size =
31  2048; // Fits inside 4k adb packet.
32 
33 void PlatformAndroid::Initialize() {
34  PlatformLinux::Initialize();
35 
36  if (g_initialize_count++ == 0) {
37 #if defined(__ANDROID__)
38  PlatformSP default_platform_sp(new PlatformAndroid(true));
39  default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
40  Platform::SetHostPlatform(default_platform_sp);
41 #endif
42  PluginManager::RegisterPlugin(
43  PlatformAndroid::GetPluginNameStatic(false),
44  PlatformAndroid::GetPluginDescriptionStatic(false),
45  PlatformAndroid::CreateInstance);
46  }
47 }
48 
49 void PlatformAndroid::Terminate() {
50  if (g_initialize_count > 0) {
51  if (--g_initialize_count == 0) {
52  PluginManager::UnregisterPlugin(PlatformAndroid::CreateInstance);
53  }
54  }
55 
56  PlatformLinux::Terminate();
57 }
58 
59 PlatformSP PlatformAndroid::CreateInstance(bool force, const ArchSpec *arch) {
61  if (log) {
62  const char *arch_name;
63  if (arch && arch->GetArchitectureName())
64  arch_name = arch->GetArchitectureName();
65  else
66  arch_name = "<null>";
67 
68  const char *triple_cstr =
69  arch ? arch->GetTriple().getTriple().c_str() : "<null>";
70 
71  log->Printf("PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__,
72  force ? "true" : "false", arch_name, triple_cstr);
73  }
74 
75  bool create = force;
76  if (!create && arch && arch->IsValid()) {
77  const llvm::Triple &triple = arch->GetTriple();
78  switch (triple.getVendor()) {
79  case llvm::Triple::PC:
80  create = true;
81  break;
82 
83 #if defined(__ANDROID__)
84  // Only accept "unknown" for the vendor if the host is android and if
85  // "unknown" wasn't specified (it was just returned because it was NOT
86  // specified).
87  case llvm::Triple::VendorType::UnknownVendor:
88  create = !arch->TripleVendorWasSpecified();
89  break;
90 #endif
91  default:
92  break;
93  }
94 
95  if (create) {
96  switch (triple.getEnvironment()) {
97  case llvm::Triple::Android:
98  break;
99 
100 #if defined(__ANDROID__)
101  // Only accept "unknown" for the OS if the host is android and it
102  // "unknown" wasn't specified (it was just returned because it was NOT
103  // specified)
104  case llvm::Triple::EnvironmentType::UnknownEnvironment:
105  create = !arch->TripleEnvironmentWasSpecified();
106  break;
107 #endif
108  default:
109  create = false;
110  break;
111  }
112  }
113  }
114 
115  if (create) {
116  if (log)
117  log->Printf("PlatformAndroid::%s() creating remote-android platform",
118  __FUNCTION__);
119  return PlatformSP(new PlatformAndroid(false));
120  }
121 
122  if (log)
123  log->Printf(
124  "PlatformAndroid::%s() aborting creation of remote-android platform",
125  __FUNCTION__);
126 
127  return PlatformSP();
128 }
129 
130 PlatformAndroid::PlatformAndroid(bool is_host)
131  : PlatformLinux(is_host), m_sdk_version(0) {}
132 
134 
136  if (is_host) {
137  static ConstString g_host_name(Platform::GetHostPlatformName());
138  return g_host_name;
139  } else {
140  static ConstString g_remote_name("remote-android");
141  return g_remote_name;
142  }
143 }
144 
146  if (is_host)
147  return "Local Android user platform plug-in.";
148  else
149  return "Remote Android user platform plug-in.";
150 }
151 
153  return GetPluginNameStatic(IsHost());
154 }
155 
157  m_device_id.clear();
158 
159  if (IsHost()) {
160  return Status("can't connect to the host platform '%s', always connected",
161  GetPluginName().GetCString());
162  }
163 
166 
167  int port;
168  llvm::StringRef scheme, host, path;
169  const char *url = args.GetArgumentAtIndex(0);
170  if (!url)
171  return Status("URL is null.");
172  if (!UriParser::Parse(url, scheme, host, port, path))
173  return Status("Invalid URL: %s", url);
174  if (host != "localhost")
175  m_device_id = host;
176 
177  auto error = PlatformLinux::ConnectRemote(args);
178  if (error.Success()) {
179  AdbClient adb;
180  error = AdbClient::CreateByDeviceID(m_device_id, adb);
181  if (error.Fail())
182  return error;
183 
184  m_device_id = adb.GetDeviceID();
185  }
186  return error;
187 }
188 
190  const FileSpec &destination) {
191  if (IsHost() || !m_remote_platform_sp)
192  return PlatformLinux::GetFile(source, destination);
193 
194  FileSpec source_spec(source.GetPath(false), FileSpec::Style::posix);
195  if (source_spec.IsRelative())
197  source_spec.GetCString(false));
198 
199  Status error;
200  auto sync_service = GetSyncService(error);
201  if (error.Fail())
202  return error;
203 
204  uint32_t mode = 0, size = 0, mtime = 0;
205  error = sync_service->Stat(source_spec, mode, size, mtime);
206  if (error.Fail())
207  return error;
208 
209  if (mode != 0)
210  return sync_service->PullFile(source_spec, destination);
211 
212  auto source_file = source_spec.GetCString(false);
213 
215  if (log)
216  log->Printf("Got mode == 0 on '%s': try to get file via 'shell cat'",
217  source_file);
218 
219  if (strchr(source_file, '\'') != nullptr)
220  return Status("Doesn't support single-quotes in filenames");
221 
222  // mode == 0 can signify that adbd cannot access the file due security
223  // constraints - try "cat ..." as a fallback.
224  AdbClient adb(m_device_id);
225 
226  char cmd[PATH_MAX];
227  snprintf(cmd, sizeof(cmd), "cat '%s'", source_file);
228 
229  return adb.ShellToFile(cmd, minutes(1), destination);
230 }
231 
233  const FileSpec &destination, uint32_t uid,
234  uint32_t gid) {
235  if (IsHost() || !m_remote_platform_sp)
236  return PlatformLinux::PutFile(source, destination, uid, gid);
237 
238  FileSpec destination_spec(destination.GetPath(false), FileSpec::Style::posix);
239  if (destination_spec.IsRelative())
241  destination_spec.GetCString(false));
242 
243  // TODO: Set correct uid and gid on remote file.
244  Status error;
245  auto sync_service = GetSyncService(error);
246  if (error.Fail())
247  return error;
248  return sync_service->PushFile(source, destination_spec);
249 }
250 
251 const char *PlatformAndroid::GetCacheHostname() { return m_device_id.c_str(); }
252 
254  const uint64_t src_offset,
255  const uint64_t src_size,
256  const FileSpec &dst_file_spec) {
257  if (src_offset != 0)
258  return Status("Invalid offset - %" PRIu64, src_offset);
259 
260  return GetFile(src_file_spec, dst_file_spec);
261 }
262 
264  Status error = PlatformLinux::DisconnectRemote();
265  if (error.Success()) {
266  m_device_id.clear();
267  m_sdk_version = 0;
268  }
269  return error;
270 }
271 
274 }
275 
277  if (!IsConnected())
278  return 0;
279 
280  if (m_sdk_version != 0)
281  return m_sdk_version;
282 
283  std::string version_string;
284  AdbClient adb(m_device_id);
285  Status error =
286  adb.Shell("getprop ro.build.version.sdk", seconds(5), &version_string);
287  version_string = llvm::StringRef(version_string).trim().str();
288 
289  if (error.Fail() || version_string.empty()) {
291  if (log)
292  log->Printf("Get SDK version failed. (error: %s, output: %s)",
293  error.AsCString(), version_string.c_str());
294  return 0;
295  }
296 
297  m_sdk_version = StringConvert::ToUInt32(version_string.c_str());
298  return m_sdk_version;
299 }
300 
301 Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
302  const FileSpec &dst_file_spec) {
303  // For oat file we can try to fetch additional debug info from the device
304  ConstString extension = module_sp->GetFileSpec().GetFileNameExtension();
305  if (extension != ".oat" && extension != ".odex")
306  return Status(
307  "Symbol file downloading only supported for oat and odex files");
308 
309  // If we have no information about the platform file we can't execute oatdump
310  if (!module_sp->GetPlatformFileSpec())
311  return Status("No platform file specified");
312 
313  // Symbolizer isn't available before SDK version 23
314  if (GetSdkVersion() < 23)
315  return Status("Symbol file generation only supported on SDK 23+");
316 
317  // If we already have symtab then we don't have to try and generate one
318  if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) !=
319  nullptr)
320  return Status("Symtab already available in the module");
321 
322  AdbClient adb(m_device_id);
323  std::string tmpdir;
324  Status error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp",
325  seconds(5), &tmpdir);
326  if (error.Fail() || tmpdir.empty())
327  return Status("Failed to generate temporary directory on the device (%s)",
328  error.AsCString());
329  tmpdir = llvm::StringRef(tmpdir).trim().str();
330 
331  // Create file remover for the temporary directory created on the device
332  std::unique_ptr<std::string, std::function<void(std::string *)>>
333  tmpdir_remover(&tmpdir, [&adb](std::string *s) {
334  StreamString command;
335  command.Printf("rm -rf %s", s->c_str());
336  Status error = adb.Shell(command.GetData(), seconds(5), nullptr);
337 
339  if (log && error.Fail())
340  log->Printf("Failed to remove temp directory: %s", error.AsCString());
341  });
342 
343  FileSpec symfile_platform_filespec(tmpdir);
344  symfile_platform_filespec.AppendPathComponent("symbolized.oat");
345 
346  // Execute oatdump on the remote device to generate a file with symtab
347  StreamString command;
348  command.Printf("oatdump --symbolize=%s --output=%s",
349  module_sp->GetPlatformFileSpec().GetCString(false),
350  symfile_platform_filespec.GetCString(false));
351  error = adb.Shell(command.GetData(), minutes(1), nullptr);
352  if (error.Fail())
353  return Status("Oatdump failed: %s", error.AsCString());
354 
355  // Download the symbolfile from the remote device
356  return GetFile(symfile_platform_filespec, dst_file_spec);
357 }
358 
360  m_os_version = llvm::VersionTuple(GetSdkVersion());
361  return !m_os_version.empty();
362 }
363 
364 llvm::StringRef
366  SymbolContextList matching_symbols;
367  std::vector<const char *> dl_open_names = { "__dl_dlopen", "dlopen" };
368  const char *dl_open_name = nullptr;
369  Target &target = process->GetTarget();
370  for (auto name: dl_open_names) {
371  if (target.GetImages().FindFunctionSymbols(ConstString(name),
372  eFunctionNameTypeFull,
373  matching_symbols)) {
374  dl_open_name = name;
375  break;
376  }
377  }
378  // Older platform versions have the dl function symbols mangled
379  if (dl_open_name == dl_open_names[0])
380  return R"(
381  extern "C" void* dlopen(const char*, int) asm("__dl_dlopen");
382  extern "C" void* dlsym(void*, const char*) asm("__dl_dlsym");
383  extern "C" int dlclose(void*) asm("__dl_dlclose");
384  extern "C" char* dlerror(void) asm("__dl_dlerror");
385  )";
386 
388 }
389 
390 AdbClient::SyncService *PlatformAndroid::GetSyncService(Status &error) {
391  if (m_adb_sync_svc && m_adb_sync_svc->IsConnected())
392  return m_adb_sync_svc.get();
393 
394  AdbClient adb(m_device_id);
395  m_adb_sync_svc = adb.GetSyncService(error);
396  return (error.Success()) ? m_adb_sync_svc.get() : nullptr;
397 }
A command line argument class.
Definition: Args.h:32
Defines a list of symbol context objects.
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
static const char * GetPluginDescriptionStatic(bool is_host)
const std::string & GetDeviceID() const
Definition: AdbClient.cpp:135
bool TripleEnvironmentWasSpecified() const
Definition: ArchSpec.h:340
bool IsHost() const
Definition: Platform.h:450
A file utility class.
Definition: FileSpec.h:55
An architecture specification class.
Definition: ArchSpec.h:32
static const char * GetHostPlatformName()
Definition: Platform.cpp:62
static const unsigned int g_android_default_cache_size
#define LIBLLDB_LOG_PLATFORM
Definition: Logging.h:39
std::unique_ptr< SyncService > GetSyncService(Status &error)
Definition: AdbClient.cpp:420
const char * GetData() const
Definition: StreamString.h:43
bool IsValid() const
Tests if this ArchSpec is valid.
Definition: ArchSpec.h:329
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx. ...
Definition: Args.cpp:256
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:431
Status Shell(const char *command, std::chrono::milliseconds timeout, std::string *output)
Definition: AdbClient.cpp:387
bool TripleVendorWasSpecified() const
Definition: ArchSpec.h:334
Status GetFile(const FileSpec &source, const FileSpec &destination) override
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition: ArchSpec.cpp:591
Status ShellToFile(const char *command, std::chrono::milliseconds timeout, const FileSpec &output_file_spec)
Definition: AdbClient.cpp:399
FileSpec CopyByAppendingPathComponent(llvm::StringRef component) const
Definition: FileSpec.cpp:428
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:57
virtual llvm::StringRef GetLibdlFunctionDeclarations(lldb_private::Process *process)
A plug-in interface definition class for debugging a process.
Definition: Process.h:353
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
bool Success() const
Test for success condition.
Definition: Status.cpp:287
size_t FindFunctionSymbols(ConstString name, lldb::FunctionNameType name_type_mask, SymbolContextList &sc_list)
Definition: ModuleList.cpp:374
static Status CreateByDeviceID(const std::string &device_id, AdbClient &adb)
Definition: AdbClient.cpp:95
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition: Target.h:899
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1194
Status DownloadSymbolFile(const lldb::ModuleSP &module_sp, const FileSpec &dst_file_spec) override
static ConstString GetPluginNameStatic(bool is_host)
uint32_t GetDefaultMemoryCacheLineSize() override
Allow the platform to set preferred memory cache line size.
A uniqued constant string class.
Definition: ConstString.h:38
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
Definition: SBAddress.h:15
uint32_t ToUInt32(const char *s, uint32_t fail_value=0, int base=0, bool *success_ptr=nullptr)
#define PATH_MAX
static uint32_t g_initialize_count
static bool Parse(llvm::StringRef uri, llvm::StringRef &scheme, llvm::StringRef &hostname, int &port, llvm::StringRef &path)
Definition: UriParser.cpp:19
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:130
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:376
Status DownloadModuleSlice(const FileSpec &src_file_spec, const uint64_t src_offset, const uint64_t src_size, const FileSpec &dst_file_spec) override
Status PutFile(const FileSpec &source, const FileSpec &destination, uint32_t uid=UINT32_MAX, uint32_t gid=UINT32_MAX) override
llvm::VersionTuple m_os_version
Definition: Platform.h:856
void Printf(const char *format,...) __attribute__((format(printf
Definition: Log.cpp:113
llvm::StringRef GetLibdlFunctionDeclarations(lldb_private::Process *process) override
An error handling class.
Definition: Status.h:44