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