LLDB  mainline
PlatformiOSSimulator.cpp
Go to the documentation of this file.
1 //===-- PlatformiOSSimulator.cpp -----------------------------------*- C++
2 //-*-===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "PlatformiOSSimulator.h"
11 
13 #include "lldb/Core/Module.h"
14 #include "lldb/Core/ModuleList.h"
15 #include "lldb/Core/ModuleSpec.h"
17 #include "lldb/Host/Host.h"
18 #include "lldb/Host/HostInfo.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Utility/ArchSpec.h"
21 #include "lldb/Utility/FileSpec.h"
22 #include "lldb/Utility/Log.h"
24 #include "lldb/Utility/Status.h"
26 
27 #include "llvm/Support/FileSystem.h"
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 
32 namespace lldb_private {
33 class Process;
34 }
35 
36 // Static Variables
38 
39 // Static Functions
42 
43  if (g_initialize_count++ == 0) {
44  PluginManager::RegisterPlugin(PlatformiOSSimulator::GetPluginNameStatic(),
47  }
48 }
49 
51  if (g_initialize_count > 0) {
52  if (--g_initialize_count == 0) {
53  PluginManager::UnregisterPlugin(PlatformiOSSimulator::CreateInstance);
54  }
55  }
56 
58 }
59 
61  const ArchSpec *arch) {
63  if (log) {
64  const char *arch_name;
65  if (arch && arch->GetArchitectureName())
66  arch_name = arch->GetArchitectureName();
67  else
68  arch_name = "<null>";
69 
70  const char *triple_cstr =
71  arch ? arch->GetTriple().getTriple().c_str() : "<null>";
72 
73  log->Printf("PlatformiOSSimulator::%s(force=%s, arch={%s,%s})",
74  __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
75  }
76 
77  bool create = force;
78  if (!create && arch && arch->IsValid()) {
79  switch (arch->GetMachine()) {
80  case llvm::Triple::x86_64:
81  case llvm::Triple::x86: {
82  const llvm::Triple &triple = arch->GetTriple();
83  switch (triple.getVendor()) {
84  case llvm::Triple::Apple:
85  create = true;
86  break;
87 
88 #if defined(__APPLE__)
89  // Only accept "unknown" for the vendor if the host is Apple and it
90  // "unknown" wasn't specified (it was just returned because it was NOT
91  // specified)
92  case llvm::Triple::UnknownVendor:
93  create = !arch->TripleVendorWasSpecified();
94  break;
95 #endif
96  default:
97  break;
98  }
99 
100  if (create) {
101  switch (triple.getOS()) {
102  case llvm::Triple::Darwin: // Deprecated, but still support Darwin for
103  // historical reasons
104  case llvm::Triple::MacOSX:
105  case llvm::Triple::IOS: // IOS is not used for simulator triples, but
106  // accept it just in case
107  break;
108 
109 #if defined(__APPLE__)
110  // Only accept "unknown" for the OS if the host is Apple and it
111  // "unknown" wasn't specified (it was just returned because it was NOT
112  // specified)
113  case llvm::Triple::UnknownOS:
114  create = !arch->TripleOSWasSpecified();
115  break;
116 #endif
117  default:
118  create = false;
119  break;
120  }
121  }
122  } break;
123  default:
124  break;
125  }
126  }
127  if (create) {
128  if (log)
129  log->Printf("PlatformiOSSimulator::%s() creating platform", __FUNCTION__);
130 
131  return PlatformSP(new PlatformiOSSimulator());
132  }
133 
134  if (log)
135  log->Printf("PlatformiOSSimulator::%s() aborting creation of platform",
136  __FUNCTION__);
137 
138  return PlatformSP();
139 }
140 
142  static ConstString g_name("ios-simulator");
143  return g_name;
144 }
145 
147  return "iOS simulator platform plug-in.";
148 }
149 
150 /// Default Constructor
152  : PlatformAppleSimulator(), m_sdk_dir_mutex(), m_sdk_directory(),
153  m_build_update() {}
154 
155 /// Destructor.
156 ///
157 /// The destructor is virtual since this class is designed to be
158 /// inherited from by the plug-in instance.
160 
162  Platform::GetStatus(strm);
163  const char *sdk_directory = GetSDKDirectoryAsCString();
164  if (sdk_directory)
165  strm.Printf(" SDK Path: \"%s\"\n", sdk_directory);
166  else
167  strm.PutCString(" SDK Path: error: unable to locate SDK\n");
169 }
170 
172  const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp,
173  const FileSpecList *module_search_paths_ptr) {
174  Status error;
175  // Nothing special to do here, just use the actual file and architecture
176 
177  ModuleSpec resolved_module_spec(module_spec);
178 
179  // If we have "ls" as the exe_file, resolve the executable loation based on
180  // the current path variables
181  // TODO: resolve bare executables in the Platform SDK
182  // if (!resolved_exe_file.Exists())
183  // resolved_exe_file.ResolveExecutableLocation ();
184 
185  // Resolve any executable within a bundle on MacOSX
186  // TODO: verify that this handles shallow bundles, if not then implement one
187  // ourselves
188  Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec());
189 
190  if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) {
191  if (resolved_module_spec.GetArchitecture().IsValid()) {
192  error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
193  NULL, NULL, NULL);
194 
195  if (exe_module_sp && exe_module_sp->GetObjectFile())
196  return error;
197  exe_module_sp.reset();
198  }
199  // No valid architecture was specified or the exact ARM slice wasn't found
200  // so ask the platform for the architectures that we should be using (in
201  // the correct order) and see if we can find a match that way
202  StreamString arch_names;
203  ArchSpec platform_arch;
205  idx, resolved_module_spec.GetArchitecture());
206  ++idx) {
207  // Only match x86 with x86 and x86_64 with x86_64...
208  if (!module_spec.GetArchitecture().IsValid() ||
209  module_spec.GetArchitecture().GetCore() ==
210  resolved_module_spec.GetArchitecture().GetCore()) {
211  error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp,
212  NULL, NULL, NULL);
213  // Did we find an executable using one of the
214  if (error.Success()) {
215  if (exe_module_sp && exe_module_sp->GetObjectFile())
216  break;
217  else
218  error.SetErrorToGenericError();
219  }
220 
221  if (idx > 0)
222  arch_names.PutCString(", ");
223  arch_names.PutCString(platform_arch.GetArchitectureName());
224  }
225  }
226 
227  if (error.Fail() || !exe_module_sp) {
228  if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) {
230  "'%s' doesn't contain any '%s' platform architectures: %s",
231  resolved_module_spec.GetFileSpec().GetPath().c_str(),
232  GetPluginName().GetCString(), arch_names.GetString().str().c_str());
233  } else {
235  "'%s' is not readable",
236  resolved_module_spec.GetFileSpec().GetPath().c_str());
237  }
238  }
239  } else {
240  error.SetErrorStringWithFormat("'%s' does not exist",
241  module_spec.GetFileSpec().GetPath().c_str());
242  }
243 
244  return error;
245 }
246 
248 EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft,
249  llvm::StringRef path) {
250  if (ft == llvm::sys::fs::file_type::directory_file) {
251  FileSpec file_spec(path);
252  const char *filename = file_spec.GetFilename().GetCString();
253  if (filename &&
254  strncmp(filename, "iPhoneSimulator", strlen("iPhoneSimulator")) == 0) {
255  ::snprintf((char *)baton, PATH_MAX, "%s", filename);
256  return FileSystem::eEnumerateDirectoryResultQuit;
257  }
258  }
259  return FileSystem::eEnumerateDirectoryResultNext;
260 }
261 
263  std::lock_guard<std::mutex> guard(m_sdk_dir_mutex);
264  if (m_sdk_directory.empty()) {
265  const char *developer_dir = GetDeveloperDirectory();
266  if (developer_dir) {
267  char sdks_directory[PATH_MAX];
268  char sdk_dirname[PATH_MAX];
269  sdk_dirname[0] = '\0';
270  snprintf(sdks_directory, sizeof(sdks_directory),
271  "%s/Platforms/iPhoneSimulator.platform/Developer/SDKs",
272  developer_dir);
273  FileSpec simulator_sdk_spec;
274  bool find_directories = true;
275  bool find_files = false;
276  bool find_other = false;
277  FileSystem::Instance().EnumerateDirectory(
278  sdks_directory, find_directories, find_files, find_other,
279  EnumerateDirectoryCallback, sdk_dirname);
280 
281  if (sdk_dirname[0]) {
282  m_sdk_directory = sdks_directory;
283  m_sdk_directory.append(1, '/');
284  m_sdk_directory.append(sdk_dirname);
285  return m_sdk_directory.c_str();
286  }
287  }
288  // Assign a single NULL character so we know we tried to find the device
289  // support directory and we don't keep trying to find it over and over.
290  m_sdk_directory.assign(1, '\0');
291  }
292 
293  // We should have put a single NULL character into m_sdk_directory or it
294  // should have a valid path if the code gets here
295  assert(m_sdk_directory.empty() == false);
296  if (m_sdk_directory[0])
297  return m_sdk_directory.c_str();
298  return NULL;
299 }
300 
302  const UUID *uuid_ptr,
303  FileSpec &local_file) {
304  Status error;
305  char platform_file_path[PATH_MAX];
306  if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) {
307  char resolved_path[PATH_MAX];
308 
309  const char *sdk_dir = GetSDKDirectoryAsCString();
310  if (sdk_dir) {
311  ::snprintf(resolved_path, sizeof(resolved_path), "%s/%s", sdk_dir,
312  platform_file_path);
313 
314  // First try in the SDK and see if the file is in there
315  local_file.SetFile(resolved_path, FileSpec::Style::native);
316  FileSystem::Instance().Resolve(local_file);
317  if (FileSystem::Instance().Exists(local_file))
318  return error;
319 
320  // Else fall back to the actual path itself
321  local_file.SetFile(platform_file_path, FileSpec::Style::native);
322  FileSystem::Instance().Resolve(local_file);
323  if (FileSystem::Instance().Exists(local_file))
324  return error;
325  }
327  "unable to locate a platform file for '%s' in platform '%s'",
328  platform_file_path, GetPluginName().GetCString());
329  } else {
330  error.SetErrorString("invalid platform file argument");
331  }
332  return error;
333 }
334 
336  const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp,
337  const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr,
338  bool *did_create_ptr) {
339  // For iOS, the SDK files are all cached locally on the host system. So first
340  // we ask for the file in the cached SDK, then we attempt to get a shared
341  // module for the right architecture with the right UUID.
342  Status error;
343  ModuleSpec platform_module_spec(module_spec);
344  const FileSpec &platform_file = module_spec.GetFileSpec();
345  error = GetSymbolFile(platform_file, module_spec.GetUUIDPtr(),
346  platform_module_spec.GetFileSpec());
347  if (error.Success()) {
348  error = ResolveExecutable(platform_module_spec, module_sp,
349  module_search_paths_ptr);
350  } else {
351  const bool always_create = false;
352  error = ModuleList::GetSharedModule(
353  module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr,
354  did_create_ptr, always_create);
355  }
356  if (module_sp)
357  module_sp->SetPlatformFileSpec(platform_file);
358 
359  return error;
360 }
361 
362 uint32_t
364  ProcessInstanceInfoList &process_infos) {
365  ProcessInstanceInfoList all_osx_process_infos;
366  // First we get all OSX processes
367  const uint32_t n = Host::FindProcesses(match_info, all_osx_process_infos);
368 
369  // Now we filter them down to only the iOS triples
370  for (uint32_t i = 0; i < n; ++i) {
371  const ProcessInstanceInfo &proc_info =
372  all_osx_process_infos.GetProcessInfoAtIndex(i);
373  if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::IOS) {
374  process_infos.Append(proc_info);
375  }
376  }
377  return process_infos.GetSize();
378 }
379 
381  ArchSpec &arch) {
382  static const ArchSpec platform_arch(
383  HostInfo::GetArchitecture(HostInfo::eArchKindDefault));
384  static const ArchSpec platform_arch64(
385  HostInfo::GetArchitecture(HostInfo::eArchKind64));
386 
387  if (idx == 0) {
388  arch = platform_arch;
389  if (arch.IsValid()) {
390  arch.GetTriple().setOS(llvm::Triple::IOS);
391  return true;
392  }
393  } else {
394  if (platform_arch.IsExactMatch(platform_arch64)) {
395  // This macosx platform supports both 32 and 64 bit.
396  if (idx == 1) {
397  // 32/64: return "x86_64-apple-macosx" for architecture 1
398  arch = platform_arch64;
399  return true;
400  } else if (idx == 2 || idx == 3) {
401  arch = HostInfo::GetArchitecture(HostInfo::eArchKind32);
402  if (arch.IsValid()) {
403  if (idx == 2)
404  arch.GetTriple().setOS(llvm::Triple::IOS);
405  // 32/64: return "i386-apple-ios" for architecture 2 32/64: return
406  // "i386-apple-macosx" for architecture 3
407  return true;
408  }
409  }
410  } else if (idx == 1) {
411  // This macosx platform supports only 32 bit, so return the *-apple-
412  // macosx version
413  arch = platform_arch;
414  return true;
415  }
416  }
417  return false;
418 }
ConstString & GetFilename()
Filename string get accessor.
Definition: FileSpec.cpp:369
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
bool IsExactMatch(const ArchSpec &rhs) const
Compare an ArchSpec to another ArchSpec, requiring an exact cpu type match between them...
Definition: ArchSpec.cpp:977
Core GetCore() const
Definition: ArchSpec.h:410
virtual lldb_private::Status GetSymbolFile(const lldb_private::FileSpec &platform_file, const lldb_private::UUID *uuid_ptr, lldb_private::FileSpec &local_file)
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
void Append(const ProcessInstanceInfo &info)
Definition: ProcessInfo.h:166
~PlatformiOSSimulator() override
Destructor.
A file utility class.
Definition: FileSpec.h:55
An architecture specification class.
Definition: ArchSpec.h:32
#define LIBLLDB_LOG_PLATFORM
Definition: Logging.h:39
bool IsValid() const
Tests if this ArchSpec is valid.
Definition: ArchSpec.h:329
lldb_private::ConstString GetPluginName() override
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:431
lldb_private::Status ResolveExecutable(const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp, const lldb_private::FileSpecList *module_search_paths_ptr) override
const char * GetDeveloperDirectory()
lldb_private::Status GetSharedModule(const lldb_private::ModuleSpec &module_spec, lldb_private::Process *process, lldb::ModuleSP &module_sp, const lldb_private::FileSpecList *module_search_paths_ptr, lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr) override
bool TripleVendorWasSpecified() const
Definition: ArchSpec.h:334
void GetStatus(lldb_private::Stream &strm) override
Report the current status for this platform.
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition: ArchSpec.cpp:591
const char * GetSDKDirectoryAsCString()
void SetErrorToGenericError()
Set the current error to a generic error.
Definition: Status.cpp:231
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:57
void GetStatus(lldb_private::Stream &strm) override
Report the current status for this platform.
const ProcessInstanceInfo & GetProcessInfoAtIndex(size_t idx) const
Definition: ProcessInfo.h:189
static FileSystem::EnumerateDirectoryResult EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, llvm::StringRef path)
llvm::StringRef GetString() const
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
Definition: Status.cpp:241
A plug-in interface definition class for debugging a process.
Definition: Process.h:353
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
ArchSpec & GetArchitecture()
Definition: ProcessInfo.h:62
bool Success() const
Test for success condition.
Definition: Status.cpp:287
uint32_t FindProcesses(const lldb_private::ProcessInstanceInfoMatch &match_info, lldb_private::ProcessInstanceInfoList &process_infos) override
Attach to an existing process by process name.
FileSpec & GetFileSpec()
Definition: ModuleSpec.h:75
ArchSpec & GetArchitecture()
Definition: ModuleSpec.h:111
A uniqued constant string class.
Definition: ConstString.h:38
static const char * GetDescriptionStatic()
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:247
bool GetSupportedArchitectureAtIndex(uint32_t idx, lldb_private::ArchSpec &arch) override
Get the platform&#39;s supported architectures in the order in which they should be searched.
Definition: SBAddress.h:15
bool TripleOSWasSpecified() const
Definition: ArchSpec.h:338
static lldb_private::ConstString GetPluginNameStatic()
#define PATH_MAX
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
Definition: Status.cpp:255
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
Definition: FileSpec.cpp:198
PlatformiOSSimulator()
Default Constructor.
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:376
void Printf(const char *format,...) __attribute__((format(printf
Definition: Log.cpp:113
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition: ArchSpec.cpp:726
static uint32_t g_initialize_count
static lldb::PlatformSP CreateInstance(bool force, const lldb_private::ArchSpec *arch)
An error handling class.
Definition: Status.h:44