1 //===-- PlatformRemoteDarwinDevice.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 "PlatformRemoteDarwinDevice.h" 10 11 #include "lldb/Breakpoint/BreakpointLocation.h" 12 #include "lldb/Core/Module.h" 13 #include "lldb/Core/ModuleList.h" 14 #include "lldb/Core/ModuleSpec.h" 15 #include "lldb/Core/PluginManager.h" 16 #include "lldb/Host/FileSystem.h" 17 #include "lldb/Host/Host.h" 18 #include "lldb/Host/HostInfo.h" 19 #include "lldb/Target/Process.h" 20 #include "lldb/Target/Target.h" 21 #include "lldb/Utility/FileSpec.h" 22 #include "lldb/Utility/LLDBLog.h" 23 #include "lldb/Utility/Log.h" 24 #include "lldb/Utility/Status.h" 25 #include "lldb/Utility/StreamString.h" 26 #include <optional> 27 28 using namespace lldb; 29 using namespace lldb_private; 30 31 PlatformRemoteDarwinDevice::SDKDirectoryInfo::SDKDirectoryInfo( 32 const lldb_private::FileSpec &sdk_dir) 33 : directory(sdk_dir), build(), user_cached(false) { 34 llvm::StringRef dirname_str = sdk_dir.GetFilename().GetStringRef(); 35 llvm::StringRef build_str; 36 std::tie(version, build_str) = ParseVersionBuildDir(dirname_str); 37 build.SetString(build_str); 38 } 39 40 /// Default Constructor 41 PlatformRemoteDarwinDevice::PlatformRemoteDarwinDevice() 42 : PlatformDarwinDevice(false) {} // This is a remote platform 43 44 /// Destructor. 45 /// 46 /// The destructor is virtual since this class is designed to be 47 /// inherited from by the plug-in instance. 48 PlatformRemoteDarwinDevice::~PlatformRemoteDarwinDevice() = default; 49 50 void PlatformRemoteDarwinDevice::GetStatus(Stream &strm) { 51 Platform::GetStatus(strm); 52 const char *sdk_directory = GetDeviceSupportDirectoryForOSVersion(); 53 if (sdk_directory) 54 strm.Printf(" SDK Path: \"%s\"\n", sdk_directory); 55 else 56 strm.PutCString(" SDK Path: error: unable to locate SDK\n"); 57 58 const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); 59 for (uint32_t i = 0; i < num_sdk_infos; ++i) { 60 const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i]; 61 strm.Printf(" SDK Roots: [%2u] \"%s\"\n", i, 62 sdk_dir_info.directory.GetPath().c_str()); 63 } 64 } 65 66 Status PlatformRemoteDarwinDevice::ResolveExecutable( 67 const ModuleSpec &ms, lldb::ModuleSP &exe_module_sp, 68 const FileSpecList *module_search_paths_ptr) { 69 Status error; 70 // Nothing special to do here, just use the actual file and architecture 71 72 ModuleSpec resolved_module_spec(ms); 73 74 // Resolve any executable within a bundle on MacOSX 75 // TODO: verify that this handles shallow bundles, if not then implement one 76 // ourselves 77 Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); 78 79 if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { 80 if (resolved_module_spec.GetArchitecture().IsValid() || 81 resolved_module_spec.GetUUID().IsValid()) { 82 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 83 nullptr, nullptr, nullptr); 84 85 if (exe_module_sp && exe_module_sp->GetObjectFile()) 86 return error; 87 exe_module_sp.reset(); 88 } 89 // No valid architecture was specified or the exact ARM slice wasn't found 90 // so ask the platform for the architectures that we should be using (in 91 // the correct order) and see if we can find a match that way 92 StreamString arch_names; 93 llvm::ListSeparator LS; 94 ArchSpec process_host_arch; 95 for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) { 96 resolved_module_spec.GetArchitecture() = arch; 97 error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, 98 nullptr, nullptr, nullptr); 99 // Did we find an executable using one of the 100 if (error.Success()) { 101 if (exe_module_sp && exe_module_sp->GetObjectFile()) 102 break; 103 else 104 error.SetErrorToGenericError(); 105 } 106 107 arch_names << LS << arch.GetArchitectureName(); 108 } 109 110 if (error.Fail() || !exe_module_sp) { 111 if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) { 112 error.SetErrorStringWithFormatv( 113 "'{0}' doesn't contain any '{1}' platform architectures: {2}", 114 resolved_module_spec.GetFileSpec(), GetPluginName(), 115 arch_names.GetData()); 116 } else { 117 error.SetErrorStringWithFormat( 118 "'%s' is not readable", 119 resolved_module_spec.GetFileSpec().GetPath().c_str()); 120 } 121 } 122 } else { 123 error.SetErrorStringWithFormat( 124 "'%s' does not exist", 125 resolved_module_spec.GetFileSpec().GetPath().c_str()); 126 } 127 128 return error; 129 } 130 131 bool PlatformRemoteDarwinDevice::GetFileInSDK(const char *platform_file_path, 132 uint32_t sdk_idx, 133 lldb_private::FileSpec &local_file) { 134 Log *log = GetLog(LLDBLog::Host); 135 if (sdk_idx < m_sdk_directory_infos.size()) { 136 std::string sdkroot_path = 137 m_sdk_directory_infos[sdk_idx].directory.GetPath(); 138 local_file.Clear(); 139 140 if (!sdkroot_path.empty() && platform_file_path && platform_file_path[0]) { 141 // We may need to interpose "/Symbols/" or "/Symbols.Internal/" between 142 // the 143 // SDK root directory and the file path. 144 145 const char *paths_to_try[] = {"Symbols", "", "Symbols.Internal", nullptr}; 146 for (size_t i = 0; paths_to_try[i] != nullptr; i++) { 147 local_file.SetFile(sdkroot_path, FileSpec::Style::native); 148 if (paths_to_try[i][0] != '\0') 149 local_file.AppendPathComponent(paths_to_try[i]); 150 local_file.AppendPathComponent(platform_file_path); 151 FileSystem::Instance().Resolve(local_file); 152 if (FileSystem::Instance().Exists(local_file)) { 153 LLDB_LOGF(log, "Found a copy of %s in the SDK dir %s/%s", 154 platform_file_path, sdkroot_path.c_str(), paths_to_try[i]); 155 return true; 156 } 157 local_file.Clear(); 158 } 159 } 160 } 161 return false; 162 } 163 164 Status PlatformRemoteDarwinDevice::GetSymbolFile(const FileSpec &platform_file, 165 const UUID *uuid_ptr, 166 FileSpec &local_file) { 167 Log *log = GetLog(LLDBLog::Host); 168 Status error; 169 char platform_file_path[PATH_MAX]; 170 if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) { 171 const char *os_version_dir = GetDeviceSupportDirectoryForOSVersion(); 172 if (os_version_dir) { 173 std::string resolved_path = 174 (llvm::Twine(os_version_dir) + "/" + platform_file_path).str(); 175 176 local_file.SetFile(resolved_path, FileSpec::Style::native); 177 FileSystem::Instance().Resolve(local_file); 178 if (FileSystem::Instance().Exists(local_file)) { 179 if (log) { 180 LLDB_LOGF(log, "Found a copy of %s in the DeviceSupport dir %s", 181 platform_file_path, os_version_dir); 182 } 183 return error; 184 } 185 186 resolved_path = (llvm::Twine(os_version_dir) + "/Symbols.Internal/" + 187 platform_file_path) 188 .str(); 189 190 local_file.SetFile(resolved_path, FileSpec::Style::native); 191 FileSystem::Instance().Resolve(local_file); 192 if (FileSystem::Instance().Exists(local_file)) { 193 LLDB_LOGF( 194 log, 195 "Found a copy of %s in the DeviceSupport dir %s/Symbols.Internal", 196 platform_file_path, os_version_dir); 197 return error; 198 } 199 resolved_path = 200 (llvm::Twine(os_version_dir) + "/Symbols/" + platform_file_path) 201 .str(); 202 203 local_file.SetFile(resolved_path, FileSpec::Style::native); 204 FileSystem::Instance().Resolve(local_file); 205 if (FileSystem::Instance().Exists(local_file)) { 206 LLDB_LOGF(log, "Found a copy of %s in the DeviceSupport dir %s/Symbols", 207 platform_file_path, os_version_dir); 208 return error; 209 } 210 } 211 local_file = platform_file; 212 if (FileSystem::Instance().Exists(local_file)) 213 return error; 214 215 error.SetErrorStringWithFormatv( 216 "unable to locate a platform file for '{0}' in platform '{1}'", 217 platform_file_path, GetPluginName()); 218 } else { 219 error.SetErrorString("invalid platform file argument"); 220 } 221 return error; 222 } 223 224 Status PlatformRemoteDarwinDevice::GetSharedModule( 225 const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, 226 const FileSpecList *module_search_paths_ptr, 227 llvm::SmallVectorImpl<ModuleSP> *old_modules, bool *did_create_ptr) { 228 // For iOS, the SDK files are all cached locally on the host system. So first 229 // we ask for the file in the cached SDK, then we attempt to get a shared 230 // module for the right architecture with the right UUID. 231 const FileSpec &platform_file = module_spec.GetFileSpec(); 232 Log *log = GetLog(LLDBLog::Host); 233 234 Status error; 235 char platform_file_path[PATH_MAX]; 236 237 if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) { 238 ModuleSpec platform_module_spec(module_spec); 239 240 UpdateSDKDirectoryInfosIfNeeded(); 241 242 const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); 243 244 // If we are connected we migth be able to correctly deduce the SDK 245 // directory using the OS build. 246 const uint32_t connected_sdk_idx = GetConnectedSDKIndex(); 247 if (connected_sdk_idx < num_sdk_infos) { 248 LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file, 249 m_sdk_directory_infos[connected_sdk_idx].directory); 250 if (GetFileInSDK(platform_file_path, connected_sdk_idx, 251 platform_module_spec.GetFileSpec())) { 252 module_sp.reset(); 253 error = ResolveExecutable(platform_module_spec, module_sp, nullptr); 254 if (module_sp) { 255 m_last_module_sdk_idx = connected_sdk_idx; 256 error.Clear(); 257 return error; 258 } 259 } 260 } 261 262 // Try the last SDK index if it is set as most files from an SDK will tend 263 // to be valid in that same SDK. 264 if (m_last_module_sdk_idx < num_sdk_infos) { 265 LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file, 266 m_sdk_directory_infos[m_last_module_sdk_idx].directory); 267 if (GetFileInSDK(platform_file_path, m_last_module_sdk_idx, 268 platform_module_spec.GetFileSpec())) { 269 module_sp.reset(); 270 error = ResolveExecutable(platform_module_spec, module_sp, nullptr); 271 if (module_sp) { 272 error.Clear(); 273 return error; 274 } 275 } 276 } 277 278 // First try for an exact match of major, minor and update: If a particalar 279 // SDK version was specified via --version or --build, look for a match on 280 // disk. 281 const SDKDirectoryInfo *current_sdk_info = 282 GetSDKDirectoryForCurrentOSVersion(); 283 const uint32_t current_sdk_idx = 284 GetSDKIndexBySDKDirectoryInfo(current_sdk_info); 285 if (current_sdk_idx < num_sdk_infos && 286 current_sdk_idx != m_last_module_sdk_idx) { 287 LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file, 288 m_sdk_directory_infos[current_sdk_idx].directory); 289 if (GetFileInSDK(platform_file_path, current_sdk_idx, 290 platform_module_spec.GetFileSpec())) { 291 module_sp.reset(); 292 error = ResolveExecutable(platform_module_spec, module_sp, nullptr); 293 if (module_sp) { 294 m_last_module_sdk_idx = current_sdk_idx; 295 error.Clear(); 296 return error; 297 } 298 } 299 } 300 301 // Second try all SDKs that were found. 302 for (uint32_t sdk_idx = 0; sdk_idx < num_sdk_infos; ++sdk_idx) { 303 if (m_last_module_sdk_idx == sdk_idx) { 304 // Skip the last module SDK index if we already searched it above 305 continue; 306 } 307 LLDB_LOGV(log, "Searching for {0} in sdk path {1}", platform_file, 308 m_sdk_directory_infos[sdk_idx].directory); 309 if (GetFileInSDK(platform_file_path, sdk_idx, 310 platform_module_spec.GetFileSpec())) { 311 // printf ("sdk[%u]: '%s'\n", sdk_idx, local_file.GetPath().c_str()); 312 313 error = ResolveExecutable(platform_module_spec, module_sp, nullptr); 314 if (module_sp) { 315 // Remember the index of the last SDK that we found a file in in case 316 // the wrong SDK was selected. 317 m_last_module_sdk_idx = sdk_idx; 318 error.Clear(); 319 return error; 320 } 321 } 322 } 323 } 324 // Not the module we are looking for... Nothing to see here... 325 module_sp.reset(); 326 327 // This may not be an SDK-related module. Try whether we can bring in the 328 // thing to our local cache. 329 error = GetSharedModuleWithLocalCache(module_spec, module_sp, 330 module_search_paths_ptr, old_modules, 331 did_create_ptr); 332 if (error.Success()) 333 return error; 334 335 // See if the file is present in any of the module_search_paths_ptr 336 // directories. 337 if (!module_sp) 338 error = PlatformDarwin::FindBundleBinaryInExecSearchPaths( 339 module_spec, process, module_sp, module_search_paths_ptr, old_modules, 340 did_create_ptr); 341 342 if (error.Success()) 343 return error; 344 345 const bool always_create = false; 346 error = ModuleList::GetSharedModule(module_spec, module_sp, 347 module_search_paths_ptr, old_modules, 348 did_create_ptr, always_create); 349 350 if (module_sp) 351 module_sp->SetPlatformFileSpec(platform_file); 352 353 return error; 354 } 355 356 uint32_t PlatformRemoteDarwinDevice::GetConnectedSDKIndex() { 357 if (IsConnected()) { 358 if (m_connected_module_sdk_idx == UINT32_MAX) { 359 if (std::optional<std::string> build = GetRemoteOSBuildString()) { 360 const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); 361 for (uint32_t i = 0; i < num_sdk_infos; ++i) { 362 const SDKDirectoryInfo &sdk_dir_info = m_sdk_directory_infos[i]; 363 if (strstr(sdk_dir_info.directory.GetFilename().AsCString(""), 364 build->c_str())) { 365 m_connected_module_sdk_idx = i; 366 } 367 } 368 } 369 } 370 } else { 371 m_connected_module_sdk_idx = UINT32_MAX; 372 } 373 return m_connected_module_sdk_idx; 374 } 375 376 uint32_t PlatformRemoteDarwinDevice::GetSDKIndexBySDKDirectoryInfo( 377 const SDKDirectoryInfo *sdk_info) { 378 if (sdk_info == nullptr) { 379 return UINT32_MAX; 380 } 381 382 return sdk_info - &m_sdk_directory_infos[0]; 383 } 384