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