Coverage Report

Created: 2022-01-22 13:19

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