1 //===-- PlatformRemoteiOS.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 #include "PlatformRemoteiOS.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Breakpoint/BreakpointLocation.h" 17 #include "lldb/Core/ArchSpec.h" 18 #include "lldb/Core/Error.h" 19 #include "lldb/Core/Module.h" 20 #include "lldb/Core/ModuleList.h" 21 #include "lldb/Core/PluginManager.h" 22 #include "lldb/Core/StreamString.h" 23 #include "lldb/Host/FileSpec.h" 24 #include "lldb/Host/Host.h" 25 #include "lldb/Target/Process.h" 26 #include "lldb/Target/Target.h" 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 PlatformRemoteiOS::SDKDirectoryInfo::SDKDirectoryInfo (const lldb_private::FileSpec &sdk_dir) : 32 directory(sdk_dir), 33 build(), 34 version_major(0), 35 version_minor(0), 36 version_update(0), 37 user_cached(false) 38 { 39 const char *dirname_cstr = sdk_dir.GetFilename().GetCString(); 40 const char *pos = Args::StringToVersion (dirname_cstr, 41 version_major, 42 version_minor, 43 version_update); 44 45 if (pos && pos[0] == ' ' && pos[1] == '(') 46 { 47 const char *build_start = pos + 2; 48 const char *end_paren = strchr (build_start, ')'); 49 if (end_paren && build_start < end_paren) 50 build.SetCStringWithLength(build_start, end_paren - build_start); 51 } 52 } 53 54 //------------------------------------------------------------------ 55 // Static Variables 56 //------------------------------------------------------------------ 57 static uint32_t g_initialize_count = 0; 58 59 //------------------------------------------------------------------ 60 // Static Functions 61 //------------------------------------------------------------------ 62 void 63 PlatformRemoteiOS::Initialize () 64 { 65 if (g_initialize_count++ == 0) 66 { 67 PluginManager::RegisterPlugin (PlatformRemoteiOS::GetShortPluginNameStatic(), 68 PlatformRemoteiOS::GetDescriptionStatic(), 69 PlatformRemoteiOS::CreateInstance); 70 } 71 } 72 73 void 74 PlatformRemoteiOS::Terminate () 75 { 76 if (g_initialize_count > 0) 77 { 78 if (--g_initialize_count == 0) 79 { 80 PluginManager::UnregisterPlugin (PlatformRemoteiOS::CreateInstance); 81 } 82 } 83 } 84 85 Platform* 86 PlatformRemoteiOS::CreateInstance (bool force, const ArchSpec *arch) 87 { 88 bool create = force; 89 if (create == false && arch && arch->IsValid()) 90 { 91 switch (arch->GetMachine()) 92 { 93 case llvm::Triple::arm: 94 case llvm::Triple::thumb: 95 { 96 const llvm::Triple &triple = arch->GetTriple(); 97 const llvm::Triple::OSType os = triple.getOS(); 98 const llvm::Triple::VendorType vendor = triple.getVendor(); 99 if (os == llvm::Triple::Darwin && vendor == llvm::Triple::Apple) 100 create = true; 101 } 102 break; 103 default: 104 break; 105 } 106 } 107 108 if (create) 109 return new PlatformRemoteiOS (); 110 return NULL; 111 } 112 113 114 const char * 115 PlatformRemoteiOS::GetPluginNameStatic () 116 { 117 return "PlatformRemoteiOS"; 118 } 119 120 const char * 121 PlatformRemoteiOS::GetShortPluginNameStatic() 122 { 123 return "remote-ios"; 124 } 125 126 const char * 127 PlatformRemoteiOS::GetDescriptionStatic() 128 { 129 return "Remote iOS platform plug-in."; 130 } 131 132 133 //------------------------------------------------------------------ 134 /// Default Constructor 135 //------------------------------------------------------------------ 136 PlatformRemoteiOS::PlatformRemoteiOS () : 137 PlatformDarwin (false), // This is a remote platform 138 m_device_support_directory_for_os_version () 139 { 140 } 141 142 //------------------------------------------------------------------ 143 /// Destructor. 144 /// 145 /// The destructor is virtual since this class is designed to be 146 /// inherited from by the plug-in instance. 147 //------------------------------------------------------------------ 148 PlatformRemoteiOS::~PlatformRemoteiOS() 149 { 150 } 151 152 153 void 154 PlatformRemoteiOS::GetStatus (Stream &strm) 155 { 156 Platform::GetStatus (strm); 157 const char *sdk_directory = GetDeviceSupportDirectoryForOSVersion(); 158 if (sdk_directory) 159 strm.Printf (" SDK Path: \"%s\"\n", sdk_directory); 160 else 161 strm.PutCString (" SDK Path: error: unable to locate SDK\n"); 162 163 // const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); 164 // for (uint32_t i=0; i<num_sdk_infos; ++i) 165 // { 166 // const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i]; 167 // strm.Printf (" SDK Roots: [%2u] \"%s/%s\"\n", 168 // i, 169 // sdk_dir_info.directory.GetDirectory().GetCString(), 170 // sdk_dir_info.directory.GetFilename().GetCString()); 171 // } 172 } 173 174 175 Error 176 PlatformRemoteiOS::ResolveExecutable (const FileSpec &exe_file, 177 const ArchSpec &exe_arch, 178 lldb::ModuleSP &exe_module_sp, 179 const FileSpecList *module_search_paths_ptr) 180 { 181 Error error; 182 // Nothing special to do here, just use the actual file and architecture 183 184 FileSpec resolved_exe_file (exe_file); 185 186 // If we have "ls" as the exe_file, resolve the executable loation based on 187 // the current path variables 188 // TODO: resolve bare executables in the Platform SDK 189 // if (!resolved_exe_file.Exists()) 190 // resolved_exe_file.ResolveExecutableLocation (); 191 192 // Resolve any executable within a bundle on MacOSX 193 // TODO: verify that this handles shallow bundles, if not then implement one ourselves 194 Host::ResolveExecutableInBundle (resolved_exe_file); 195 196 if (resolved_exe_file.Exists()) 197 { 198 if (exe_arch.IsValid()) 199 { 200 ModuleSpec module_spec (resolved_exe_file, exe_arch); 201 error = ModuleList::GetSharedModule (module_spec, 202 exe_module_sp, 203 NULL, 204 NULL, 205 NULL); 206 207 if (exe_module_sp && exe_module_sp->GetObjectFile()) 208 return error; 209 exe_module_sp.reset(); 210 } 211 // No valid architecture was specified or the exact ARM slice wasn't 212 // found so ask the platform for the architectures that we should be 213 // using (in the correct order) and see if we can find a match that way 214 StreamString arch_names; 215 ArchSpec platform_arch; 216 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx) 217 { 218 ModuleSpec module_spec (resolved_exe_file, platform_arch); 219 error = ModuleList::GetSharedModule (module_spec, 220 exe_module_sp, 221 NULL, 222 NULL, 223 NULL); 224 // Did we find an executable using one of the 225 if (error.Success()) 226 { 227 if (exe_module_sp && exe_module_sp->GetObjectFile()) 228 break; 229 else 230 error.SetErrorToGenericError(); 231 } 232 233 if (idx > 0) 234 arch_names.PutCString (", "); 235 arch_names.PutCString (platform_arch.GetArchitectureName()); 236 } 237 238 if (error.Fail() || !exe_module_sp) 239 { 240 error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain any '%s' platform architectures: %s", 241 exe_file.GetDirectory().AsCString(""), 242 exe_file.GetDirectory() ? "/" : "", 243 exe_file.GetFilename().AsCString(""), 244 GetShortPluginName(), 245 arch_names.GetString().c_str()); 246 } 247 } 248 else 249 { 250 error.SetErrorStringWithFormat ("'%s%s%s' does not exist", 251 exe_file.GetDirectory().AsCString(""), 252 exe_file.GetDirectory() ? "/" : "", 253 exe_file.GetFilename().AsCString("")); 254 } 255 256 return error; 257 } 258 259 FileSpec::EnumerateDirectoryResult 260 PlatformRemoteiOS::GetContainedFilesIntoVectorOfStringsCallback (void *baton, 261 FileSpec::FileType file_type, 262 const FileSpec &file_spec) 263 { 264 ((PlatformRemoteiOS::SDKDirectoryInfoCollection *)baton)->push_back(PlatformRemoteiOS::SDKDirectoryInfo(file_spec)); 265 return FileSpec::eEnumerateDirectoryResultNext; 266 } 267 268 bool 269 PlatformRemoteiOS::UpdateSDKDirectoryInfosInNeeded() 270 { 271 if (m_sdk_directory_infos.empty()) 272 { 273 const char *device_support_dir = GetDeviceSupportDirectory(); 274 if (device_support_dir) 275 { 276 const bool find_directories = true; 277 const bool find_files = false; 278 const bool find_other = false; 279 FileSpec::EnumerateDirectory (m_device_support_directory.c_str(), 280 find_directories, 281 find_files, 282 find_other, 283 GetContainedFilesIntoVectorOfStringsCallback, 284 &m_sdk_directory_infos); 285 286 const uint32_t num_installed = m_sdk_directory_infos.size(); 287 FileSpec local_sdk_cache("~/Library/Developer/Xcode/iOS DeviceSupport", true); 288 if (local_sdk_cache.Exists()) 289 { 290 char path[PATH_MAX]; 291 if (local_sdk_cache.GetPath(path, sizeof(path))) 292 { 293 FileSpec::EnumerateDirectory (path, 294 find_directories, 295 find_files, 296 find_other, 297 GetContainedFilesIntoVectorOfStringsCallback, 298 &m_sdk_directory_infos); 299 const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); 300 // First try for an exact match of major, minor and update 301 for (uint32_t i=num_installed; i<num_sdk_infos; ++i) 302 { 303 m_sdk_directory_infos[i].user_cached = true; 304 } 305 } 306 } 307 } 308 } 309 return !m_sdk_directory_infos.empty(); 310 } 311 312 const PlatformRemoteiOS::SDKDirectoryInfo * 313 PlatformRemoteiOS::GetSDKDirectoryForCurrentOSVersion () 314 { 315 uint32_t i; 316 if (UpdateSDKDirectoryInfosInNeeded()) 317 { 318 const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); 319 320 // Check to see if the user specified a build string. If they did, then 321 // be sure to match it. 322 std::vector<bool> check_sdk_info(num_sdk_infos, true); 323 ConstString build(m_sdk_build); 324 if (build) 325 { 326 for (i=0; i<num_sdk_infos; ++i) 327 check_sdk_info[i] = m_sdk_directory_infos[i].build == build; 328 } 329 330 // If we are connected we can find the version of the OS the platform 331 // us running on and select the right SDK 332 uint32_t major, minor, update; 333 if (GetOSVersion(major, minor, update)) 334 { 335 if (UpdateSDKDirectoryInfosInNeeded()) 336 { 337 // First try for an exact match of major, minor and update 338 for (i=0; i<num_sdk_infos; ++i) 339 { 340 if (check_sdk_info[i]) 341 { 342 if (m_sdk_directory_infos[i].version_major == major && 343 m_sdk_directory_infos[i].version_minor == minor && 344 m_sdk_directory_infos[i].version_update == update) 345 { 346 return &m_sdk_directory_infos[i]; 347 } 348 } 349 } 350 // First try for an exact match of major and minor 351 for (i=0; i<num_sdk_infos; ++i) 352 { 353 if (check_sdk_info[i]) 354 { 355 if (m_sdk_directory_infos[i].version_major == major && 356 m_sdk_directory_infos[i].version_minor == minor) 357 { 358 return &m_sdk_directory_infos[i]; 359 } 360 } 361 } 362 // Lastly try to match of major version only.. 363 for (i=0; i<num_sdk_infos; ++i) 364 { 365 if (check_sdk_info[i]) 366 { 367 if (m_sdk_directory_infos[i].version_major == major) 368 { 369 return &m_sdk_directory_infos[i]; 370 } 371 } 372 } 373 } 374 } 375 else if (build) 376 { 377 // No version, just a build number, search for the first one that matches 378 for (i=0; i<num_sdk_infos; ++i) 379 if (check_sdk_info[i]) 380 return &m_sdk_directory_infos[i]; 381 } 382 } 383 return NULL; 384 } 385 386 const PlatformRemoteiOS::SDKDirectoryInfo * 387 PlatformRemoteiOS::GetSDKDirectoryForLatestOSVersion () 388 { 389 const PlatformRemoteiOS::SDKDirectoryInfo *result = NULL; 390 if (UpdateSDKDirectoryInfosInNeeded()) 391 { 392 const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); 393 // First try for an exact match of major, minor and update 394 for (uint32_t i=0; i<num_sdk_infos; ++i) 395 { 396 const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i]; 397 if (sdk_dir_info.version_major != UINT32_MAX) 398 { 399 if (result == NULL || sdk_dir_info.version_major > result->version_major) 400 { 401 result = &sdk_dir_info; 402 } 403 else if (sdk_dir_info.version_major == result->version_major) 404 { 405 if (sdk_dir_info.version_minor > result->version_minor) 406 { 407 result = &sdk_dir_info; 408 } 409 else if (sdk_dir_info.version_minor == result->version_minor) 410 { 411 if (sdk_dir_info.version_update > result->version_update) 412 { 413 result = &sdk_dir_info; 414 } 415 } 416 } 417 } 418 } 419 } 420 return result; 421 } 422 423 424 425 const char * 426 PlatformRemoteiOS::GetDeviceSupportDirectory() 427 { 428 if (m_device_support_directory.empty()) 429 { 430 const char *device_support_dir = GetDeveloperDirectory(); 431 if (device_support_dir) 432 { 433 m_device_support_directory.assign (device_support_dir); 434 m_device_support_directory.append ("/Platforms/iPhoneOS.platform/DeviceSupport"); 435 } 436 else 437 { 438 // Assign a single NULL character so we know we tried to find the device 439 // support directory and we don't keep trying to find it over and over. 440 m_device_support_directory.assign (1, '\0'); 441 } 442 } 443 // We should have put a single NULL character into m_device_support_directory 444 // or it should have a valid path if the code gets here 445 assert (m_device_support_directory.empty() == false); 446 if (m_device_support_directory[0]) 447 return m_device_support_directory.c_str(); 448 return NULL; 449 } 450 451 452 const char * 453 PlatformRemoteiOS::GetDeviceSupportDirectoryForOSVersion() 454 { 455 if (m_sdk_sysroot) 456 return m_sdk_sysroot.GetCString(); 457 458 if (m_device_support_directory_for_os_version.empty()) 459 { 460 const PlatformRemoteiOS::SDKDirectoryInfo *sdk_dir_info = GetSDKDirectoryForCurrentOSVersion (); 461 if (sdk_dir_info == NULL) 462 sdk_dir_info = GetSDKDirectoryForLatestOSVersion (); 463 if (sdk_dir_info) 464 { 465 char path[PATH_MAX]; 466 if (sdk_dir_info->directory.GetPath(path, sizeof(path))) 467 { 468 m_device_support_directory_for_os_version = path; 469 return m_device_support_directory_for_os_version.c_str(); 470 } 471 } 472 else 473 { 474 // Assign a single NULL character so we know we tried to find the device 475 // support directory and we don't keep trying to find it over and over. 476 m_device_support_directory_for_os_version.assign (1, '\0'); 477 } 478 } 479 // We should have put a single NULL character into m_device_support_directory_for_os_version 480 // or it should have a valid path if the code gets here 481 assert (m_device_support_directory_for_os_version.empty() == false); 482 if (m_device_support_directory_for_os_version[0]) 483 return m_device_support_directory_for_os_version.c_str(); 484 return NULL; 485 } 486 487 Error 488 PlatformRemoteiOS::GetFile (const FileSpec &platform_file, 489 const UUID *uuid_ptr, 490 FileSpec &local_file) 491 { 492 Error error; 493 char platform_file_path[PATH_MAX]; 494 if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) 495 { 496 char resolved_path[PATH_MAX]; 497 498 const char * os_version_dir = GetDeviceSupportDirectoryForOSVersion(); 499 if (os_version_dir) 500 { 501 ::snprintf (resolved_path, 502 sizeof(resolved_path), 503 "%s/%s", 504 os_version_dir, 505 platform_file_path); 506 507 local_file.SetFile(resolved_path, true); 508 if (local_file.Exists()) 509 return error; 510 511 ::snprintf (resolved_path, 512 sizeof(resolved_path), 513 "%s/Symbols.Internal/%s", 514 os_version_dir, 515 platform_file_path); 516 517 local_file.SetFile(resolved_path, true); 518 if (local_file.Exists()) 519 return error; 520 ::snprintf (resolved_path, 521 sizeof(resolved_path), 522 "%s/Symbols/%s", 523 os_version_dir, 524 platform_file_path); 525 526 local_file.SetFile(resolved_path, true); 527 if (local_file.Exists()) 528 return error; 529 530 } 531 local_file = platform_file; 532 if (local_file.Exists()) 533 return error; 534 535 error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'", 536 platform_file_path, 537 GetPluginName()); 538 } 539 else 540 { 541 error.SetErrorString ("invalid platform file argument"); 542 } 543 return error; 544 } 545 546 Error 547 PlatformRemoteiOS::GetSharedModule (const ModuleSpec &module_spec, 548 ModuleSP &module_sp, 549 const FileSpecList *module_search_paths_ptr, 550 ModuleSP *old_module_sp_ptr, 551 bool *did_create_ptr) 552 { 553 // For iOS, the SDK files are all cached locally on the host 554 // system. So first we ask for the file in the cached SDK, 555 // then we attempt to get a shared module for the right architecture 556 // with the right UUID. 557 const FileSpec &platform_file = module_spec.GetFileSpec(); 558 559 FileSpec local_file; 560 Error error (GetFile (platform_file, module_spec.GetUUIDPtr(), local_file)); 561 if (error.Success()) 562 { 563 error = ResolveExecutable (local_file, module_spec.GetArchitecture(), module_sp, module_search_paths_ptr); 564 } 565 else 566 { 567 const bool always_create = false; 568 error = ModuleList::GetSharedModule (module_spec, 569 module_sp, 570 module_search_paths_ptr, 571 old_module_sp_ptr, 572 did_create_ptr, 573 always_create); 574 575 } 576 if (module_sp) 577 module_sp->SetPlatformFileSpec(platform_file); 578 579 return error; 580 } 581 582 583 uint32_t 584 PlatformRemoteiOS::FindProcesses (const ProcessInstanceInfoMatch &match_info, 585 ProcessInstanceInfoList &process_infos) 586 { 587 // TODO: if connected, send a packet to get the remote process infos by name 588 process_infos.Clear(); 589 return 0; 590 } 591 592 bool 593 PlatformRemoteiOS::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 594 { 595 // TODO: if connected, send a packet to get the remote process info 596 process_info.Clear(); 597 return false; 598 } 599 600 bool 601 PlatformRemoteiOS::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) 602 { 603 return ARMGetSupportedArchitectureAtIndex (idx, arch); 604 } 605