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