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 AdbClient adb (m_device_id); 229 return adb.PullFile (source_spec, destination); 230 } 231 232 Error 233 PlatformAndroid::PutFile (const FileSpec& source, 234 const FileSpec& destination, 235 uint32_t uid, 236 uint32_t gid) 237 { 238 if (IsHost() || !m_remote_platform_sp) 239 return PlatformLinux::PutFile (source, destination, uid, gid); 240 241 FileSpec destination_spec (destination.GetPath (false), false, FileSpec::ePathSyntaxPosix); 242 if (destination_spec.IsRelative()) 243 destination_spec = GetRemoteWorkingDirectory ().CopyByAppendingPathComponent (destination_spec.GetCString (false)); 244 245 AdbClient adb (m_device_id); 246 // TODO: Set correct uid and gid on remote file. 247 return adb.PushFile(source, destination_spec); 248 } 249 250 const char * 251 PlatformAndroid::GetCacheHostname () 252 { 253 return m_device_id.c_str (); 254 } 255 256 Error 257 PlatformAndroid::DownloadModuleSlice (const FileSpec &src_file_spec, 258 const uint64_t src_offset, 259 const uint64_t src_size, 260 const FileSpec &dst_file_spec) 261 { 262 if (src_offset != 0) 263 return Error ("Invalid offset - %" PRIu64, src_offset); 264 265 return GetFile (src_file_spec, dst_file_spec); 266 } 267 268 Error 269 PlatformAndroid::DisconnectRemote() 270 { 271 Error error = PlatformLinux::DisconnectRemote(); 272 if (error.Success()) 273 { 274 m_device_id.clear(); 275 m_sdk_version = 0; 276 } 277 return error; 278 } 279 280 uint32_t 281 PlatformAndroid::GetDefaultMemoryCacheLineSize() 282 { 283 return g_android_default_cache_size; 284 } 285 286 uint32_t 287 PlatformAndroid::GetSdkVersion() 288 { 289 if (!IsConnected()) 290 return 0; 291 292 if (m_sdk_version != 0) 293 return m_sdk_version; 294 295 std::string version_string; 296 AdbClient adb(m_device_id); 297 Error error = adb.Shell("getprop ro.build.version.sdk", 5000 /* ms */, &version_string); 298 version_string = llvm::StringRef(version_string).trim().str(); 299 300 if (error.Fail() || version_string.empty()) 301 { 302 Log* log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM); 303 if (log) 304 log->Printf("Get SDK version failed. (error: %s, output: %s)", 305 error.AsCString(), version_string.c_str()); 306 return 0; 307 } 308 309 m_sdk_version = StringConvert::ToUInt32(version_string.c_str()); 310 return m_sdk_version; 311 } 312 313 Error 314 PlatformAndroid::DownloadSymbolFile (const lldb::ModuleSP& module_sp, 315 const FileSpec& dst_file_spec) 316 { 317 // For oat file we can try to fetch additional debug info from the device 318 if (module_sp->GetFileSpec().GetFileNameExtension() != ConstString("oat")) 319 return Error("Symbol file downloading only supported for oat files"); 320 321 // If we have no information about the platform file we can't execute oatdump 322 if (!module_sp->GetPlatformFileSpec()) 323 return Error("No platform file specified"); 324 325 // Symbolizer isn't available before SDK version 23 326 if (GetSdkVersion() < 23) 327 return Error("Symbol file generation only supported on SDK 23+"); 328 329 // If we already have symtab then we don't have to try and generate one 330 if (module_sp->GetSectionList()->FindSectionByName(ConstString(".symtab")) != nullptr) 331 return Error("Symtab already available in the module"); 332 333 AdbClient adb(m_device_id); 334 335 std::string tmpdir; 336 Error error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp", 5000 /* ms */, &tmpdir); 337 if (error.Fail() || tmpdir.empty()) 338 return Error("Failed to generate temporary directory on the device (%s)", error.AsCString()); 339 tmpdir = llvm::StringRef(tmpdir).trim().str(); 340 341 // Create file remover for the temporary directory created on the device 342 std::unique_ptr<std::string, std::function<void(std::string*)>> tmpdir_remover( 343 &tmpdir, 344 [this, &adb](std::string* s) { 345 StreamString command; 346 command.Printf("rm -rf %s", s->c_str()); 347 Error error = adb.Shell(command.GetData(), 5000 /* ms */, nullptr); 348 349 Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); 350 if (error.Fail()) 351 log->Printf("Failed to remove temp directory: %s", error.AsCString()); 352 } 353 ); 354 355 FileSpec symfile_platform_filespec(tmpdir.c_str(), false); 356 symfile_platform_filespec.AppendPathComponent("symbolized.oat"); 357 358 // Execute oatdump on the remote device to generate a file with symtab 359 StreamString command; 360 command.Printf("oatdump --symbolize=%s --output=%s", 361 module_sp->GetPlatformFileSpec().GetCString(false), 362 symfile_platform_filespec.GetCString(false)); 363 error = adb.Shell(command.GetData(), 60000 /* ms */, nullptr); 364 if (error.Fail()) 365 return Error("Oatdump failed: %s", error.AsCString()); 366 367 // Download the symbolfile from the remote device 368 return GetFile(symfile_platform_filespec, dst_file_spec); 369 } 370 371 bool 372 PlatformAndroid::GetRemoteOSVersion () 373 { 374 m_major_os_version = GetSdkVersion(); 375 m_minor_os_version = 0; 376 m_update_os_version = 0; 377 return m_major_os_version != 0; 378 } 379 380 const char* 381 PlatformAndroid::GetLibdlFunctionDeclarations() const 382 { 383 return R"( 384 extern "C" void* dlopen(const char*, int) asm("__dl_dlopen"); 385 extern "C" void* dlsym(void*, const char*) asm("__dl_dlsym"); 386 extern "C" int dlclose(void*) asm("__dl_dlclose"); 387 extern "C" char* dlerror(void) asm("__dl_dlerror"); 388 )"; 389 } 390