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 //------------------------------------------------------------------ 32 // Static Variables 33 //------------------------------------------------------------------ 34 static uint32_t g_initialize_count = 0; 35 36 //------------------------------------------------------------------ 37 // Static Functions 38 //------------------------------------------------------------------ 39 void 40 PlatformRemoteiOS::Initialize () 41 { 42 if (g_initialize_count++ == 0) 43 { 44 PluginManager::RegisterPlugin (PlatformRemoteiOS::GetShortPluginNameStatic(), 45 PlatformRemoteiOS::GetDescriptionStatic(), 46 PlatformRemoteiOS::CreateInstance); 47 } 48 } 49 50 void 51 PlatformRemoteiOS::Terminate () 52 { 53 if (g_initialize_count > 0) 54 { 55 if (--g_initialize_count == 0) 56 { 57 PluginManager::UnregisterPlugin (PlatformRemoteiOS::CreateInstance); 58 } 59 } 60 } 61 62 Platform* 63 PlatformRemoteiOS::CreateInstance () 64 { 65 return new PlatformRemoteiOS (); 66 } 67 68 69 const char * 70 PlatformRemoteiOS::GetPluginNameStatic () 71 { 72 return "PlatformRemoteiOS"; 73 } 74 75 const char * 76 PlatformRemoteiOS::GetShortPluginNameStatic() 77 { 78 return "remote-ios"; 79 } 80 81 const char * 82 PlatformRemoteiOS::GetDescriptionStatic() 83 { 84 return "Remote iOS platform plug-in."; 85 } 86 87 88 //------------------------------------------------------------------ 89 /// Default Constructor 90 //------------------------------------------------------------------ 91 PlatformRemoteiOS::PlatformRemoteiOS () : 92 PlatformDarwin (false), // This is a remote platform 93 m_device_support_directory (), 94 m_device_support_directory_for_os_version () 95 { 96 } 97 98 //------------------------------------------------------------------ 99 /// Destructor. 100 /// 101 /// The destructor is virtual since this class is designed to be 102 /// inherited from by the plug-in instance. 103 //------------------------------------------------------------------ 104 PlatformRemoteiOS::~PlatformRemoteiOS() 105 { 106 } 107 108 109 void 110 PlatformRemoteiOS::GetStatus (Stream &strm) 111 { 112 Platform::GetStatus (strm); 113 const char *sdk_directory = GetDeviceSupportDirectoryForOSVersion(); 114 if (sdk_directory) 115 strm.Printf (" SDK Path: \"%s\"\n", sdk_directory); 116 else 117 strm.PutCString (" SDK Path: error: unable to locate SDK\n"); 118 } 119 120 121 Error 122 PlatformRemoteiOS::ResolveExecutable (const FileSpec &exe_file, 123 const ArchSpec &exe_arch, 124 lldb::ModuleSP &exe_module_sp, 125 const FileSpecList *module_search_paths_ptr) 126 { 127 Error error; 128 // Nothing special to do here, just use the actual file and architecture 129 130 FileSpec resolved_exe_file (exe_file); 131 132 // If we have "ls" as the exe_file, resolve the executable loation based on 133 // the current path variables 134 // TODO: resolve bare executables in the Platform SDK 135 // if (!resolved_exe_file.Exists()) 136 // resolved_exe_file.ResolveExecutableLocation (); 137 138 // Resolve any executable within a bundle on MacOSX 139 // TODO: verify that this handles shallow bundles, if not then implement one ourselves 140 Host::ResolveExecutableInBundle (resolved_exe_file); 141 142 if (resolved_exe_file.Exists()) 143 { 144 if (exe_arch.IsValid()) 145 { 146 error = ModuleList::GetSharedModule (resolved_exe_file, 147 exe_arch, 148 NULL, 149 NULL, 150 0, 151 exe_module_sp, 152 NULL, 153 NULL, 154 NULL); 155 156 if (exe_module_sp->GetObjectFile()) 157 return error; 158 exe_module_sp.reset(); 159 } 160 // No valid architecture was specified or the exact ARM slice wasn't 161 // found so ask the platform for the architectures that we should be 162 // using (in the correct order) and see if we can find a match that way 163 StreamString arch_names; 164 ArchSpec platform_arch; 165 for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx) 166 { 167 error = ModuleList::GetSharedModule (resolved_exe_file, 168 platform_arch, 169 NULL, 170 NULL, 171 0, 172 exe_module_sp, 173 NULL, 174 NULL, 175 NULL); 176 // Did we find an executable using one of the 177 if (error.Success()) 178 { 179 if (exe_module_sp && exe_module_sp->GetObjectFile()) 180 break; 181 else 182 error.SetErrorToGenericError(); 183 } 184 185 if (idx > 0) 186 arch_names.PutCString (", "); 187 arch_names.PutCString (platform_arch.GetArchitectureName()); 188 } 189 190 if (error.Fail() || !exe_module_sp) 191 { 192 error.SetErrorStringWithFormat ("'%s%s%s' doesn't contain any '%s' platform architectures: %s", 193 exe_file.GetDirectory().AsCString(""), 194 exe_file.GetDirectory() ? "/" : "", 195 exe_file.GetFilename().AsCString(""), 196 GetShortPluginName(), 197 arch_names.GetString().c_str()); 198 } 199 } 200 else 201 { 202 error.SetErrorStringWithFormat ("'%s%s%s' does not exist", 203 exe_file.GetDirectory().AsCString(""), 204 exe_file.GetDirectory() ? "/" : "", 205 exe_file.GetFilename().AsCString("")); 206 } 207 208 return error; 209 } 210 211 const char * 212 PlatformRemoteiOS::GetDeviceSupportDirectory() 213 { 214 if (m_device_support_directory.empty()) 215 { 216 bool developer_dir_path_valid = false; 217 char developer_dir_path[PATH_MAX]; 218 FileSpec temp_file_spec; 219 if (Host::GetLLDBPath (ePathTypeLLDBShlibDir, temp_file_spec)) 220 { 221 if (temp_file_spec.GetPath (developer_dir_path, sizeof(developer_dir_path))) 222 { 223 char *lib_priv_frameworks = strstr (developer_dir_path, "/Library/PrivateFrameworks/LLDB.framework"); 224 if (lib_priv_frameworks) 225 { 226 *lib_priv_frameworks = '\0'; 227 developer_dir_path_valid = true; 228 } 229 } 230 } 231 232 if (!developer_dir_path_valid) 233 { 234 std::string xcode_dir_path; 235 const char *xcode_select_prefix_dir = getenv ("XCODE_SELECT_PREFIX_DIR"); 236 if (xcode_select_prefix_dir) 237 xcode_dir_path.append (xcode_select_prefix_dir); 238 xcode_dir_path.append ("/usr/share/xcode-select/xcode_dir_path"); 239 temp_file_spec.SetFile(xcode_dir_path.c_str(), false); 240 size_t bytes_read = temp_file_spec.ReadFileContents(0, developer_dir_path, sizeof(developer_dir_path), NULL); 241 if (bytes_read > 0) 242 { 243 developer_dir_path[bytes_read] = '\0'; 244 while (developer_dir_path[bytes_read-1] == '\r' || 245 developer_dir_path[bytes_read-1] == '\n') 246 developer_dir_path[--bytes_read] = '\0'; 247 developer_dir_path_valid = true; 248 } 249 } 250 251 if (developer_dir_path_valid) 252 { 253 temp_file_spec.SetFile (developer_dir_path, false); 254 if (temp_file_spec.Exists()) 255 { 256 m_device_support_directory.assign (developer_dir_path); 257 return m_device_support_directory.c_str(); 258 } 259 } 260 // Assign a single NULL character so we know we tried to find the device 261 // support directory and we don't keep trying to find it over and over. 262 m_device_support_directory.assign (1, '\0'); 263 } 264 265 // We should have put a single NULL character into m_device_support_directory 266 // or it should have a valid path if the code gets here 267 assert (m_device_support_directory.empty() == false); 268 if (m_device_support_directory[0]) 269 return m_device_support_directory.c_str(); 270 return NULL; 271 } 272 273 const char * 274 PlatformRemoteiOS::GetDeviceSupportDirectoryForOSVersion() 275 { 276 if (m_sdk_sysroot) 277 return m_sdk_sysroot.GetCString(); 278 279 if (m_device_support_directory_for_os_version.empty()) 280 { 281 const char *device_support_dir = GetDeviceSupportDirectory(); 282 const bool resolve_path = true; 283 if (device_support_dir) 284 { 285 m_device_support_directory_for_os_version.assign (device_support_dir); 286 m_device_support_directory_for_os_version.append ("/Platforms/iPhoneOS.platform/DeviceSupport"); 287 288 uint32_t major = 0; 289 uint32_t minor = 0; 290 uint32_t update = 0; 291 FileSpec file_spec; 292 char resolved_path[PATH_MAX]; 293 if (GetOSVersion(major, minor, update)) 294 { 295 if (major != UINT32_MAX && minor != UINT32_MAX && update != UINT32_MAX) 296 { 297 ::snprintf (resolved_path, 298 sizeof(resolved_path), 299 "%s/%i.%i.%i", 300 m_device_support_directory_for_os_version.c_str(), 301 major, 302 minor, 303 update); 304 305 file_spec.SetFile(resolved_path, resolve_path); 306 if (file_spec.Exists() && file_spec.GetPath(resolved_path, sizeof(resolved_path))) 307 { 308 m_device_support_directory_for_os_version.assign (resolved_path); 309 return m_device_support_directory_for_os_version.c_str(); 310 } 311 } 312 313 if (major != UINT32_MAX && minor != UINT32_MAX) 314 { 315 ::snprintf (resolved_path, 316 sizeof(resolved_path), 317 "%s/%i.%i", 318 m_device_support_directory_for_os_version.c_str(), 319 major, 320 minor); 321 322 file_spec.SetFile(resolved_path, resolve_path); 323 if (file_spec.Exists() && file_spec.GetPath(resolved_path, sizeof(resolved_path))) 324 { 325 m_device_support_directory_for_os_version.assign (resolved_path); 326 return m_device_support_directory_for_os_version.c_str(); 327 } 328 } 329 } 330 else 331 { 332 // Use the default as we have no OS version selected 333 m_device_support_directory_for_os_version.append ("/Latest"); 334 file_spec.SetFile(m_device_support_directory_for_os_version.c_str(), resolve_path); 335 336 if (file_spec.Exists() && file_spec.GetPath(resolved_path, sizeof(resolved_path))) 337 { 338 if (m_major_os_version == UINT32_MAX) 339 { 340 const char *resolved_latest_dirname = file_spec.GetFilename().GetCString(); 341 const char *pos = Args::StringToVersion (resolved_latest_dirname, 342 m_major_os_version, 343 m_minor_os_version, 344 m_update_os_version); 345 346 if (m_build_update.empty() && pos[0] == ' ' && pos[1] == '(') 347 { 348 const char *end_paren = strchr (pos + 2, ')'); 349 m_build_update.assign (pos + 2, end_paren); 350 } 351 } 352 m_device_support_directory_for_os_version.assign (resolved_path); 353 return m_device_support_directory_for_os_version.c_str(); 354 } 355 } 356 } 357 // Assign a single NULL character so we know we tried to find the device 358 // support directory and we don't keep trying to find it over and over. 359 m_device_support_directory_for_os_version.assign (1, '\0'); 360 } 361 // We should have put a single NULL character into m_device_support_directory_for_os_version 362 // or it should have a valid path if the code gets here 363 assert (m_device_support_directory_for_os_version.empty() == false); 364 if (m_device_support_directory_for_os_version[0]) 365 return m_device_support_directory_for_os_version.c_str(); 366 return NULL; 367 } 368 369 Error 370 PlatformRemoteiOS::GetFile (const FileSpec &platform_file, 371 const UUID *uuid_ptr, 372 FileSpec &local_file) 373 { 374 Error error; 375 char platform_file_path[PATH_MAX]; 376 if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) 377 { 378 char resolved_path[PATH_MAX]; 379 380 const char * os_version_dir = GetDeviceSupportDirectoryForOSVersion(); 381 if (os_version_dir) 382 { 383 ::snprintf (resolved_path, 384 sizeof(resolved_path), 385 "%s/%s", 386 os_version_dir, 387 platform_file_path); 388 389 local_file.SetFile(resolved_path, true); 390 if (local_file.Exists()) 391 return error; 392 393 ::snprintf (resolved_path, 394 sizeof(resolved_path), 395 "%s/Symbols.Internal/%s", 396 os_version_dir, 397 platform_file_path); 398 399 local_file.SetFile(resolved_path, true); 400 if (local_file.Exists()) 401 return error; 402 ::snprintf (resolved_path, 403 sizeof(resolved_path), 404 "%s/Symbols/%s", 405 os_version_dir, 406 platform_file_path); 407 408 local_file.SetFile(resolved_path, true); 409 if (local_file.Exists()) 410 return error; 411 412 } 413 local_file = platform_file; 414 if (local_file.Exists()) 415 return error; 416 417 error.SetErrorStringWithFormat ("unable to locate a platform file for '%s' in platform '%s'", 418 platform_file_path, 419 GetPluginName()); 420 } 421 else 422 { 423 error.SetErrorString ("invalid platform file argument"); 424 } 425 return error; 426 } 427 428 Error 429 PlatformRemoteiOS::GetSharedModule (const FileSpec &platform_file, 430 const ArchSpec &arch, 431 const UUID *uuid_ptr, 432 const ConstString *object_name_ptr, 433 off_t object_offset, 434 ModuleSP &module_sp, 435 const FileSpecList *module_search_paths_ptr, 436 ModuleSP *old_module_sp_ptr, 437 bool *did_create_ptr) 438 { 439 // For iOS, the SDK files are all cached locally on the host 440 // system. So first we ask for the file in the cached SDK, 441 // then we attempt to get a shared module for the right architecture 442 // with the right UUID. 443 Error error; 444 FileSpec local_file; 445 error = GetFile (platform_file, uuid_ptr, local_file); 446 if (error.Success()) 447 { 448 error = ResolveExecutable (local_file, arch, module_sp, module_search_paths_ptr); 449 } 450 else 451 { 452 const bool always_create = false; 453 error = ModuleList::GetSharedModule (platform_file, 454 arch, 455 uuid_ptr, 456 object_name_ptr, 457 object_offset, 458 module_sp, 459 module_search_paths_ptr, 460 old_module_sp_ptr, 461 did_create_ptr, 462 always_create); 463 464 } 465 if (module_sp) 466 module_sp->SetPlatformFileSpec(platform_file); 467 468 return error; 469 } 470 471 472 uint32_t 473 PlatformRemoteiOS::FindProcesses (const ProcessInstanceInfoMatch &match_info, 474 ProcessInstanceInfoList &process_infos) 475 { 476 // TODO: if connected, send a packet to get the remote process infos by name 477 process_infos.Clear(); 478 return 0; 479 } 480 481 bool 482 PlatformRemoteiOS::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) 483 { 484 // TODO: if connected, send a packet to get the remote process info 485 process_info.Clear(); 486 return false; 487 } 488 489 bool 490 PlatformRemoteiOS::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) 491 { 492 return ARMGetSupportedArchitectureAtIndex (idx, arch); 493 } 494