Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
Line
Count
Source (jump to first uncovered line)
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"
10
#include "lldb/Core/PluginManager.h"
11
#include "lldb/Core/Section.h"
12
#include "lldb/Core/ValueObject.h"
13
#include "lldb/Host/HostInfo.h"
14
#include "lldb/Utility/LLDBLog.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"
21
#include "PlatformAndroidRemoteGDBServer.h"
22
#include "lldb/Target/Target.h"
23
#include <optional>
24
25
using namespace lldb;
26
using namespace lldb_private;
27
using namespace lldb_private::platform_android;
28
using namespace std::chrono;
29
30
LLDB_PLUGIN_DEFINE(PlatformAndroid)
31
32
namespace {
33
34
#define LLDB_PROPERTIES_android
35
#include "PlatformAndroidProperties.inc"
36
37
enum {
38
#define LLDB_PROPERTIES_android
39
#include "PlatformAndroidPropertiesEnum.inc"
40
};
41
42
class PluginProperties : public Properties {
43
public:
44
3.89k
  PluginProperties() {
45
3.89k
    m_collection_sp = std::make_shared<OptionValueProperties>(
46
3.89k
        PlatformAndroid::GetPluginNameStatic(false));
47
3.89k
    m_collection_sp->Initialize(g_android_properties);
48
3.89k
  }
49
};
50
51
3.89k
static PluginProperties &GetGlobalProperties() {
52
3.89k
  static PluginProperties g_settings;
53
3.89k
  return g_settings;
54
3.89k
}
55
56
uint32_t g_initialize_count = 0;
57
const unsigned int g_android_default_cache_size =
58
    2048; // Fits inside 4k adb packet.
59
60
} // end of anonymous namespace
61
62
3.95k
void PlatformAndroid::Initialize() {
63
3.95k
  PlatformLinux::Initialize();
64
65
3.95k
  if (g_initialize_count++ == 0) {
66
#if defined(__ANDROID__)
67
    PlatformSP default_platform_sp(new PlatformAndroid(true));
68
    default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
69
    Platform::SetHostPlatform(default_platform_sp);
70
#endif
71
3.95k
    PluginManager::RegisterPlugin(
72
3.95k
        PlatformAndroid::GetPluginNameStatic(false),
73
3.95k
        PlatformAndroid::GetPluginDescriptionStatic(false),
74
3.95k
        PlatformAndroid::CreateInstance, PlatformAndroid::DebuggerInitialize);
75
3.95k
  }
76
3.95k
}
77
78
3.94k
void PlatformAndroid::Terminate() {
79
3.94k
  if (g_initialize_count > 0) {
80
3.94k
    if (--g_initialize_count == 0) {
81
3.94k
      PluginManager::UnregisterPlugin(PlatformAndroid::CreateInstance);
82
3.94k
    }
83
3.94k
  }
84
85
3.94k
  PlatformLinux::Terminate();
86
3.94k
}
87
88
260
PlatformSP PlatformAndroid::CreateInstance(bool force, const ArchSpec *arch) {
89
260
  Log *log = GetLog(LLDBLog::Platform);
90
260
  if (log) {
91
0
    const char *arch_name;
92
0
    if (arch && arch->GetArchitectureName())
93
0
      arch_name = arch->GetArchitectureName();
94
0
    else
95
0
      arch_name = "<null>";
96
97
0
    const char *triple_cstr =
98
0
        arch ? arch->GetTriple().getTriple().c_str() : "<null>";
99
100
0
    LLDB_LOGF(log, "PlatformAndroid::%s(force=%s, arch={%s,%s})", __FUNCTION__,
101
0
              force ? "true" : "false", arch_name, triple_cstr);
102
0
  }
103
104
260
  bool create = force;
105
260
  if (!create && 
arch233
&&
arch->IsValid()233
) {
106
233
    const llvm::Triple &triple = arch->GetTriple();
107
233
    switch (triple.getVendor()) {
108
90
    case llvm::Triple::PC:
109
90
      create = true;
110
90
      break;
111
112
#if defined(__ANDROID__)
113
    // Only accept "unknown" for the vendor if the host is android and if
114
    // "unknown" wasn't specified (it was just returned because it was NOT
115
    // specified).
116
    case llvm::Triple::VendorType::UnknownVendor:
117
      create = !arch->TripleVendorWasSpecified();
118
      break;
119
#endif
120
143
    default:
121
143
      break;
122
233
    }
123
124
233
    if (create) {
125
90
      switch (triple.getEnvironment()) {
126
0
      case llvm::Triple::Android:
127
0
        break;
128
129
#if defined(__ANDROID__)
130
      // Only accept "unknown" for the OS if the host is android and it
131
      // "unknown" wasn't specified (it was just returned because it was NOT
132
      // specified)
133
      case llvm::Triple::EnvironmentType::UnknownEnvironment:
134
        create = !arch->TripleEnvironmentWasSpecified();
135
        break;
136
#endif
137
90
      default:
138
90
        create = false;
139
90
        break;
140
90
      }
141
90
    }
142
233
  }
143
144
260
  if (create) {
145
27
    LLDB_LOGF(log, "PlatformAndroid::%s() creating remote-android platform",
146
27
              __FUNCTION__);
147
27
    return PlatformSP(new PlatformAndroid(false));
148
27
  }
149
150
233
  LLDB_LOGF(
151
233
      log, "PlatformAndroid::%s() aborting creation of remote-android platform",
152
233
      __FUNCTION__);
153
154
233
  return PlatformSP();
155
260
}
156
157
6.06k
void PlatformAndroid::DebuggerInitialize(Debugger &debugger) {
158
6.06k
  if (!PluginManager::GetSettingForPlatformPlugin(debugger,
159
6.06k
                                                  GetPluginNameStatic(false))) {
160
3.89k
    PluginManager::CreateSettingForPlatformPlugin(
161
3.89k
        debugger, GetGlobalProperties().GetValueProperties(),
162
3.89k
        "Properties for the Android platform plugin.",
163
3.89k
        /*is_global_property=*/true);
164
3.89k
  }
165
6.06k
}
166
167
PlatformAndroid::PlatformAndroid(bool is_host)
168
34
    : PlatformLinux(is_host), m_sdk_version(0) {}
169
170
3.95k
llvm::StringRef PlatformAndroid::GetPluginDescriptionStatic(bool is_host) {
171
3.95k
  if (is_host)
172
0
    return "Local Android user platform plug-in.";
173
3.95k
  return "Remote Android user platform plug-in.";
174
3.95k
}
175
176
0
Status PlatformAndroid::ConnectRemote(Args &args) {
177
0
  m_device_id.clear();
178
179
0
  if (IsHost())
180
0
    return Status("can't connect to the host platform, always connected");
181
182
0
  if (!m_remote_platform_sp)
183
0
    m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer());
184
185
0
  const char *url = args.GetArgumentAtIndex(0);
186
0
  if (!url)
187
0
    return Status("URL is null.");
188
0
  std::optional<URI> parsed_url = URI::Parse(url);
189
0
  if (!parsed_url)
190
0
    return Status("Invalid URL: %s", url);
191
0
  if (parsed_url->hostname != "localhost")
192
0
    m_device_id = parsed_url->hostname.str();
193
194
0
  auto error = PlatformLinux::ConnectRemote(args);
195
0
  if (error.Success()) {
196
0
    AdbClient adb;
197
0
    error = AdbClient::CreateByDeviceID(m_device_id, adb);
198
0
    if (error.Fail())
199
0
      return error;
200
201
0
    m_device_id = adb.GetDeviceID();
202
0
  }
203
0
  return error;
204
0
}
205
206
Status PlatformAndroid::GetFile(const FileSpec &source,
207
8
                                const FileSpec &destination) {
208
8
  if (IsHost() || !m_remote_platform_sp)
209
4
    return PlatformLinux::GetFile(source, destination);
210
211
4
  FileSpec source_spec(source.GetPath(false), FileSpec::Style::posix);
212
4
  if (source_spec.IsRelative())
213
0
    source_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent(
214
0
        source_spec.GetPathAsConstString(false).GetStringRef());
215
216
4
  Status error;
217
4
  auto sync_service = GetSyncService(error);
218
4
  if (error.Fail())
219
0
    return error;
220
221
4
  uint32_t mode = 0, size = 0, mtime = 0;
222
4
  error = sync_service->Stat(source_spec, mode, size, mtime);
223
4
  if (error.Fail())
224
0
    return error;
225
226
4
  if (mode != 0)
227
2
    return sync_service->PullFile(source_spec, destination);
228
229
2
  std::string source_file = source_spec.GetPath(false);
230
231
2
  Log *log = GetLog(LLDBLog::Platform);
232
2
  LLDB_LOGF(log, "Got mode == 0 on '%s': try to get file via 'shell cat'",
233
2
            source_file.c_str());
234
235
2
  if (strchr(source_file.c_str(), '\'') != nullptr)
236
0
    return Status("Doesn't support single-quotes in filenames");
237
238
  // mode == 0 can signify that adbd cannot access the file due security
239
  // constraints - try "cat ..." as a fallback.
240
2
  AdbClientUP adb(GetAdbClient(error));
241
2
  if (error.Fail())
242
0
    return error;
243
244
2
  char cmd[PATH_MAX];
245
2
  snprintf(cmd, sizeof(cmd), "%scat '%s'", GetRunAs().c_str(),
246
2
           source_file.c_str());
247
248
2
  return adb->ShellToFile(cmd, minutes(1), destination);
249
2
}
250
251
Status PlatformAndroid::PutFile(const FileSpec &source,
252
                                const FileSpec &destination, uint32_t uid,
253
0
                                uint32_t gid) {
254
0
  if (IsHost() || !m_remote_platform_sp)
255
0
    return PlatformLinux::PutFile(source, destination, uid, gid);
256
257
0
  FileSpec destination_spec(destination.GetPath(false), FileSpec::Style::posix);
258
0
  if (destination_spec.IsRelative())
259
0
    destination_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent(
260
0
        destination_spec.GetPath(false));
261
262
  // TODO: Set correct uid and gid on remote file.
263
0
  Status error;
264
0
  auto sync_service = GetSyncService(error);
265
0
  if (error.Fail())
266
0
    return error;
267
0
  return sync_service->PushFile(source, destination_spec);
268
0
}
269
270
15
const char *PlatformAndroid::GetCacheHostname() { return m_device_id.c_str(); }
271
272
Status PlatformAndroid::DownloadModuleSlice(const FileSpec &src_file_spec,
273
                                            const uint64_t src_offset,
274
                                            const uint64_t src_size,
275
8
                                            const FileSpec &dst_file_spec) {
276
  // In Android API level 23 and above, dynamic loader is able to load .so
277
  // file directly from APK. In that case, src_offset will be an non-zero.
278
8
  if (src_offset == 0) // Use GetFile for a normal file.
279
5
    return GetFile(src_file_spec, dst_file_spec);
280
281
3
  std::string source_file = src_file_spec.GetPath(false);
282
3
  if (source_file.find('\'') != std::string::npos)
283
0
    return Status("Doesn't support single-quotes in filenames");
284
285
  // For zip .so file, src_file_spec will be "zip_path!/so_path".
286
  // Extract "zip_path" from the source_file.
287
3
  static constexpr llvm::StringLiteral k_zip_separator("!/");
288
3
  size_t pos = source_file.find(k_zip_separator);
289
3
  if (pos != std::string::npos)
290
3
    source_file = source_file.substr(0, pos);
291
292
3
  Status error;
293
3
  AdbClientUP adb(GetAdbClient(error));
294
3
  if (error.Fail())
295
1
    return error;
296
297
  // Use 'shell dd' to download the file slice with the offset and size.
298
2
  char cmd[PATH_MAX];
299
2
  snprintf(cmd, sizeof(cmd),
300
2
           "%sdd if='%s' iflag=skip_bytes,count_bytes "
301
2
           "skip=%" PRIu64 " count=%" PRIu64 " status=none",
302
2
           GetRunAs().c_str(), source_file.c_str(), src_offset, src_size);
303
304
2
  return adb->ShellToFile(cmd, minutes(1), dst_file_spec);
305
3
}
306
307
0
Status PlatformAndroid::DisconnectRemote() {
308
0
  Status error = PlatformLinux::DisconnectRemote();
309
0
  if (error.Success()) {
310
0
    m_device_id.clear();
311
0
    m_sdk_version = 0;
312
0
  }
313
0
  return error;
314
0
}
315
316
23
uint32_t PlatformAndroid::GetDefaultMemoryCacheLineSize() {
317
23
  return g_android_default_cache_size;
318
23
}
319
320
0
uint32_t PlatformAndroid::GetSdkVersion() {
321
0
  if (!IsConnected())
322
0
    return 0;
323
324
0
  if (m_sdk_version != 0)
325
0
    return m_sdk_version;
326
327
0
  std::string version_string;
328
0
  Status error;
329
0
  AdbClientUP adb(GetAdbClient(error));
330
0
  if (error.Fail())
331
0
    return 0;
332
0
  error =
333
0
      adb->Shell("getprop ro.build.version.sdk", seconds(5), &version_string);
334
0
  version_string = llvm::StringRef(version_string).trim().str();
335
336
0
  if (error.Fail() || version_string.empty()) {
337
0
    Log *log = GetLog(LLDBLog::Platform);
338
0
    LLDB_LOGF(log, "Get SDK version failed. (error: %s, output: %s)",
339
0
              error.AsCString(), version_string.c_str());
340
0
    return 0;
341
0
  }
342
343
  // FIXME: improve error handling
344
0
  llvm::to_integer(version_string, m_sdk_version);
345
0
  return m_sdk_version;
346
0
}
347
348
Status PlatformAndroid::DownloadSymbolFile(const lldb::ModuleSP &module_sp,
349
0
                                           const FileSpec &dst_file_spec) {
350
  // For oat file we can try to fetch additional debug info from the device
351
0
  llvm::StringRef extension = module_sp->GetFileSpec().GetFileNameExtension();
352
0
  if (extension != ".oat" && extension != ".odex")
353
0
    return Status(
354
0
        "Symbol file downloading only supported for oat and odex files");
355
356
  // If we have no information about the platform file we can't execute oatdump
357
0
  if (!module_sp->GetPlatformFileSpec())
358
0
    return Status("No platform file specified");
359
360
  // Symbolizer isn't available before SDK version 23
361
0
  if (GetSdkVersion() < 23)
362
0
    return Status("Symbol file generation only supported on SDK 23+");
363
364
  // If we already have symtab then we don't have to try and generate one
365
0
  if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) !=
366
0
      nullptr)
367
0
    return Status("Symtab already available in the module");
368
369
0
  Status error;
370
0
  AdbClientUP adb(GetAdbClient(error));
371
0
  if (error.Fail())
372
0
    return error;
373
0
  std::string tmpdir;
374
0
  error = adb->Shell("mktemp --directory --tmpdir /data/local/tmp", seconds(5),
375
0
                     &tmpdir);
376
0
  if (error.Fail() || tmpdir.empty())
377
0
    return Status("Failed to generate temporary directory on the device (%s)",
378
0
                  error.AsCString());
379
0
  tmpdir = llvm::StringRef(tmpdir).trim().str();
380
381
  // Create file remover for the temporary directory created on the device
382
0
  std::unique_ptr<std::string, std::function<void(std::string *)>>
383
0
      tmpdir_remover(&tmpdir, [&adb](std::string *s) {
384
0
        StreamString command;
385
0
        command.Printf("rm -rf %s", s->c_str());
386
0
        Status error = adb->Shell(command.GetData(), seconds(5), nullptr);
387
388
0
        Log *log = GetLog(LLDBLog::Platform);
389
0
        if (log && error.Fail())
390
0
          LLDB_LOGF(log, "Failed to remove temp directory: %s",
391
0
                    error.AsCString());
392
0
      });
393
394
0
  FileSpec symfile_platform_filespec(tmpdir);
395
0
  symfile_platform_filespec.AppendPathComponent("symbolized.oat");
396
397
  // Execute oatdump on the remote device to generate a file with symtab
398
0
  StreamString command;
399
0
  command.Printf("oatdump --symbolize=%s --output=%s",
400
0
                 module_sp->GetPlatformFileSpec().GetPath(false).c_str(),
401
0
                 symfile_platform_filespec.GetPath(false).c_str());
402
0
  error = adb->Shell(command.GetData(), minutes(1), nullptr);
403
0
  if (error.Fail())
404
0
    return Status("Oatdump failed: %s", error.AsCString());
405
406
  // Download the symbolfile from the remote device
407
0
  return GetFile(symfile_platform_filespec, dst_file_spec);
408
0
}
409
410
0
bool PlatformAndroid::GetRemoteOSVersion() {
411
0
  m_os_version = llvm::VersionTuple(GetSdkVersion());
412
0
  return !m_os_version.empty();
413
0
}
414
415
llvm::StringRef
416
0
PlatformAndroid::GetLibdlFunctionDeclarations(lldb_private::Process *process) {
417
0
  SymbolContextList matching_symbols;
418
0
  std::vector<const char *> dl_open_names = {"__dl_dlopen", "dlopen"};
419
0
  const char *dl_open_name = nullptr;
420
0
  Target &target = process->GetTarget();
421
0
  for (auto name : dl_open_names) {
422
0
    target.GetImages().FindFunctionSymbols(
423
0
        ConstString(name), eFunctionNameTypeFull, matching_symbols);
424
0
    if (matching_symbols.GetSize()) {
425
0
      dl_open_name = name;
426
0
      break;
427
0
    }
428
0
  }
429
  // Older platform versions have the dl function symbols mangled
430
0
  if (dl_open_name == dl_open_names[0])
431
0
    return R"(
432
0
              extern "C" void* dlopen(const char*, int) asm("__dl_dlopen");
433
0
              extern "C" void* dlsym(void*, const char*) asm("__dl_dlsym");
434
0
              extern "C" int   dlclose(void*) asm("__dl_dlclose");
435
0
              extern "C" char* dlerror(void) asm("__dl_dlerror");
436
0
             )";
437
438
0
  return PlatformPOSIX::GetLibdlFunctionDeclarations(process);
439
0
}
440
441
0
PlatformAndroid::AdbClientUP PlatformAndroid::GetAdbClient(Status &error) {
442
0
  AdbClientUP adb(std::make_unique<AdbClient>(m_device_id));
443
0
  if (adb)
444
0
    error.Clear();
445
0
  else
446
0
    error = Status("Failed to create AdbClient");
447
0
  return adb;
448
0
}
449
450
0
llvm::StringRef PlatformAndroid::GetPropertyPackageName() {
451
0
  return GetGlobalProperties().GetPropertyAtIndexAs<llvm::StringRef>(
452
0
      ePropertyPlatformPackageName, "");
453
0
}
454
455
4
std::string PlatformAndroid::GetRunAs() {
456
4
  llvm::StringRef run_as = GetPropertyPackageName();
457
4
  if (!run_as.empty()) {
458
    // When LLDB fails to pull file from a package directory due to security
459
    // constraint, user needs to set the package name to
460
    // 'platform.plugin.remote-android.package-name' property in order to run
461
    // shell commands as the package user using 'run-as' (e.g. to get file with
462
    // 'cat' and 'dd').
463
    // https://cs.android.com/android/platform/superproject/+/master:
464
    // system/core/run-as/run-as.cpp;l=39-61;
465
    // drc=4a77a84a55522a3b122f9c63ef0d0b8a6a131627
466
2
    return std::string("run-as '") + run_as.str() + "' ";
467
2
  }
468
2
  return run_as.str();
469
4
}
470
471
4
AdbClient::SyncService *PlatformAndroid::GetSyncService(Status &error) {
472
4
  if (m_adb_sync_svc && 
m_adb_sync_svc->IsConnected()0
)
473
0
    return m_adb_sync_svc.get();
474
475
4
  AdbClientUP adb(GetAdbClient(error));
476
4
  if (error.Fail())
477
0
    return nullptr;
478
4
  m_adb_sync_svc = adb->GetSyncService(error);
479
4
  return (error.Success()) ? m_adb_sync_svc.get() : 
nullptr0
;
480
4
}