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 static uint32_t g_initialize_count = 0; 33 static const unsigned int g_android_default_cache_size = 34 2048; // Fits inside 4k adb packet. 35 36 void 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 45 PluginManager::RegisterPlugin( 46 PlatformAndroid::GetPluginNameStatic(false), 47 PlatformAndroid::GetPluginDescriptionStatic(false), 48 PlatformAndroid::CreateInstance); 49 } 50 } 51 52 void PlatformAndroid::Terminate() { 53 if (g_initialize_count > 0) { 54 if (--g_initialize_count == 0) { 55 PluginManager::UnregisterPlugin(PlatformAndroid::CreateInstance); 56 } 57 } 58 59 PlatformLinux::Terminate(); 60 } 61 62 PlatformSP PlatformAndroid::CreateInstance(bool force, const ArchSpec *arch) { 63 Log *log = GetLog(LLDBLog::Platform); 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 131 PlatformAndroid::PlatformAndroid(bool is_host) 132 : PlatformLinux(is_host), m_sdk_version(0) {} 133 134 llvm::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 140 Status PlatformAndroid::ConnectRemote(Args &args) { 141 m_device_id.clear(); 142 143 if (IsHost()) 144 return Status("can't connect to the host platform, always connected"); 145 146 if (!m_remote_platform_sp) 147 m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer()); 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; 161 error = AdbClient::CreateByDeviceID(m_device_id, adb); 162 if (error.Fail()) 163 return error; 164 165 m_device_id = adb.GetDeviceID(); 166 } 167 return error; 168 } 169 170 Status PlatformAndroid::GetFile(const FileSpec &source, 171 const FileSpec &destination) { 172 if (IsHost() || !m_remote_platform_sp) 173 return PlatformLinux::GetFile(source, destination); 174 175 FileSpec source_spec(source.GetPath(false), FileSpec::Style::posix); 176 if (source_spec.IsRelative()) 177 source_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent( 178 source_spec.GetPathAsConstString(false).GetStringRef()); 179 180 Status error; 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 195 Log *log = GetLog(LLDBLog::Platform); 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. 204 AdbClient adb(m_device_id); 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 212 Status PlatformAndroid::PutFile(const FileSpec &source, 213 const FileSpec &destination, uint32_t uid, 214 uint32_t gid) { 215 if (IsHost() || !m_remote_platform_sp) 216 return PlatformLinux::PutFile(source, destination, uid, gid); 217 218 FileSpec destination_spec(destination.GetPath(false), FileSpec::Style::posix); 219 if (destination_spec.IsRelative()) 220 destination_spec = GetRemoteWorkingDirectory().CopyByAppendingPathComponent( 221 destination_spec.GetPath(false)); 222 223 // TODO: Set correct uid and gid on remote file. 224 Status error; 225 auto sync_service = GetSyncService(error); 226 if (error.Fail()) 227 return error; 228 return sync_service->PushFile(source, destination_spec); 229 } 230 231 const char *PlatformAndroid::GetCacheHostname() { return m_device_id.c_str(); } 232 233 Status PlatformAndroid::DownloadModuleSlice(const FileSpec &src_file_spec, 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 243 Status PlatformAndroid::DisconnectRemote() { 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 252 uint32_t PlatformAndroid::GetDefaultMemoryCacheLineSize() { 253 return g_android_default_cache_size; 254 } 255 256 uint32_t PlatformAndroid::GetSdkVersion() { 257 if (!IsConnected()) 258 return 0; 259 260 if (m_sdk_version != 0) 261 return m_sdk_version; 262 263 std::string version_string; 264 AdbClient adb(m_device_id); 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()) { 270 Log *log = GetLog(LLDBLog::Platform); 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 281 Status 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 ConstString 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 302 AdbClient adb(m_device_id); 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 318 Log *log = GetLog(LLDBLog::Platform); 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 339 bool PlatformAndroid::GetRemoteOSVersion() { 340 m_os_version = llvm::VersionTuple(GetSdkVersion()); 341 return !m_os_version.empty(); 342 } 343 344 llvm::StringRef 345 PlatformAndroid::GetLibdlFunctionDeclarations(lldb_private::Process *process) { 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) { 351 target.GetImages().FindFunctionSymbols( 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 367 return PlatformPOSIX::GetLibdlFunctionDeclarations(process); 368 } 369 370 AdbClient::SyncService *PlatformAndroid::GetSyncService(Status &error) { 371 if (m_adb_sync_svc && m_adb_sync_svc->IsConnected()) 372 return m_adb_sync_svc.get(); 373 374 AdbClient adb(m_device_id); 375 m_adb_sync_svc = adb.GetSyncService(error); 376 return (error.Success()) ? m_adb_sync_svc.get() : nullptr; 377 } 378