1 //===-- PlatformMacOSX.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 "PlatformMacOSX.h"
11 #include "lldb/Host/Config.h"
12 
13 // C++ Includes
14 
15 #include <sstream>
16 
17 // Other libraries and framework includes
18 // Project includes
19 #include "lldb/Breakpoint/BreakpointLocation.h"
20 #include "lldb/Core/DataBufferHeap.h"
21 #include "lldb/Core/Error.h"
22 #include "lldb/Core/Log.h"
23 #include "lldb/Core/Module.h"
24 #include "lldb/Core/ModuleList.h"
25 #include "lldb/Core/ModuleSpec.h"
26 #include "lldb/Core/PluginManager.h"
27 #include "lldb/Core/StreamString.h"
28 #include "lldb/Host/FileSpec.h"
29 #include "lldb/Host/FileSystem.h"
30 #include "lldb/Host/Host.h"
31 #include "lldb/Host/HostInfo.h"
32 #include "lldb/Symbol/ObjectFile.h"
33 #include "lldb/Target/Process.h"
34 #include "lldb/Target/Target.h"
35 
36 using namespace lldb;
37 using namespace lldb_private;
38 
39 static uint32_t g_initialize_count = 0;
40 
41 void PlatformMacOSX::Initialize() {
42   PlatformDarwin::Initialize();
43 
44   if (g_initialize_count++ == 0) {
45 #if defined(__APPLE__)
46     PlatformSP default_platform_sp(new PlatformMacOSX(true));
47     default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture());
48     Platform::SetHostPlatform(default_platform_sp);
49 #endif
50     PluginManager::RegisterPlugin(PlatformMacOSX::GetPluginNameStatic(false),
51                                   PlatformMacOSX::GetDescriptionStatic(false),
52                                   PlatformMacOSX::CreateInstance);
53   }
54 }
55 
56 void PlatformMacOSX::Terminate() {
57   if (g_initialize_count > 0) {
58     if (--g_initialize_count == 0) {
59       PluginManager::UnregisterPlugin(PlatformMacOSX::CreateInstance);
60     }
61   }
62 
63   PlatformDarwin::Terminate();
64 }
65 
66 PlatformSP PlatformMacOSX::CreateInstance(bool force, const ArchSpec *arch) {
67   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
68   if (log) {
69     const char *arch_name;
70     if (arch && arch->GetArchitectureName())
71       arch_name = arch->GetArchitectureName();
72     else
73       arch_name = "<null>";
74 
75     const char *triple_cstr =
76         arch ? arch->GetTriple().getTriple().c_str() : "<null>";
77 
78     log->Printf("PlatformMacOSX::%s(force=%s, arch={%s,%s})", __FUNCTION__,
79                 force ? "true" : "false", arch_name, triple_cstr);
80   }
81 
82   // The only time we create an instance is when we are creating a remote
83   // macosx platform
84   const bool is_host = false;
85 
86   bool create = force;
87   if (create == false && arch && arch->IsValid()) {
88     const llvm::Triple &triple = arch->GetTriple();
89     switch (triple.getVendor()) {
90     case llvm::Triple::Apple:
91       create = true;
92       break;
93 
94 #if defined(__APPLE__)
95     // Only accept "unknown" for vendor if the host is Apple and
96     // it "unknown" wasn't specified (it was just returned because it
97     // was NOT specified)
98     case llvm::Triple::UnknownArch:
99       create = !arch->TripleVendorWasSpecified();
100       break;
101 #endif
102     default:
103       break;
104     }
105 
106     if (create) {
107       switch (triple.getOS()) {
108       case llvm::Triple::Darwin: // Deprecated, but still support Darwin for
109                                  // historical reasons
110       case llvm::Triple::MacOSX:
111         break;
112 #if defined(__APPLE__)
113       // Only accept "vendor" for vendor if the host is Apple and
114       // it "unknown" wasn't specified (it was just returned because it
115       // was NOT specified)
116       case llvm::Triple::UnknownOS:
117         create = !arch->TripleOSWasSpecified();
118         break;
119 #endif
120       default:
121         create = false;
122         break;
123       }
124     }
125   }
126   if (create) {
127     if (log)
128       log->Printf("PlatformMacOSX::%s() creating platform", __FUNCTION__);
129     return PlatformSP(new PlatformMacOSX(is_host));
130   }
131 
132   if (log)
133     log->Printf("PlatformMacOSX::%s() aborting creation of platform",
134                 __FUNCTION__);
135 
136   return PlatformSP();
137 }
138 
139 lldb_private::ConstString PlatformMacOSX::GetPluginNameStatic(bool is_host) {
140   if (is_host) {
141     static ConstString g_host_name(Platform::GetHostPlatformName());
142     return g_host_name;
143   } else {
144     static ConstString g_remote_name("remote-macosx");
145     return g_remote_name;
146   }
147 }
148 
149 const char *PlatformMacOSX::GetDescriptionStatic(bool is_host) {
150   if (is_host)
151     return "Local Mac OS X user platform plug-in.";
152   else
153     return "Remote Mac OS X user platform plug-in.";
154 }
155 
156 //------------------------------------------------------------------
157 /// Default Constructor
158 //------------------------------------------------------------------
159 PlatformMacOSX::PlatformMacOSX(bool is_host) : PlatformDarwin(is_host) {}
160 
161 //------------------------------------------------------------------
162 /// Destructor.
163 ///
164 /// The destructor is virtual since this class is designed to be
165 /// inherited from by the plug-in instance.
166 //------------------------------------------------------------------
167 PlatformMacOSX::~PlatformMacOSX() {}
168 
169 ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) {
170   ModuleSP exe_module_sp(target.GetExecutableModule());
171   if (exe_module_sp) {
172     ObjectFile *objfile = exe_module_sp->GetObjectFile();
173     if (objfile) {
174       std::string xcode_contents_path;
175       std::string default_xcode_sdk;
176       FileSpec fspec;
177       uint32_t versions[2];
178       if (objfile->GetSDKVersion(versions, sizeof(versions))) {
179         if (HostInfo::GetLLDBPath(ePathTypeLLDBShlibDir, fspec)) {
180           std::string path;
181           xcode_contents_path = fspec.GetPath();
182           size_t pos = xcode_contents_path.find("/Xcode.app/Contents/");
183           if (pos != std::string::npos) {
184             // LLDB.framework is inside an Xcode app bundle, we can locate the
185             // SDK from here
186             xcode_contents_path.erase(pos + strlen("/Xcode.app/Contents/"));
187           } else {
188             xcode_contents_path.clear();
189             // Use the selected Xcode
190             int status = 0;
191             int signo = 0;
192             std::string output;
193             const char *command = "xcrun -sdk macosx --show-sdk-path";
194             lldb_private::Error error = RunShellCommand(
195                 command, // shell command to run
196                 NULL,    // current working directory
197                 &status, // Put the exit status of the process in here
198                 &signo,  // Put the signal that caused the process to exit in
199                          // here
200                 &output, // Get the output from the command and place it in this
201                          // string
202                 3); // Timeout in seconds to wait for shell program to finish
203             if (status == 0 && !output.empty()) {
204               size_t first_non_newline = output.find_last_not_of("\r\n");
205               if (first_non_newline != std::string::npos)
206                 output.erase(first_non_newline + 1);
207               default_xcode_sdk = output;
208 
209               pos = default_xcode_sdk.find("/Xcode.app/Contents/");
210               if (pos != std::string::npos)
211                 xcode_contents_path = default_xcode_sdk.substr(
212                     0, pos + strlen("/Xcode.app/Contents/"));
213             }
214           }
215         }
216 
217         if (!xcode_contents_path.empty()) {
218           StreamString sdk_path;
219           sdk_path.Printf("%sDeveloper/Platforms/MacOSX.platform/Developer/"
220                           "SDKs/MacOSX%u.%u.sdk",
221                           xcode_contents_path.c_str(), versions[0],
222                           versions[1]);
223           fspec.SetFile(sdk_path.GetString().c_str(), false);
224           if (fspec.Exists())
225             return ConstString(sdk_path.GetString().c_str());
226         }
227 
228         if (!default_xcode_sdk.empty()) {
229           fspec.SetFile(default_xcode_sdk.c_str(), false);
230           if (fspec.Exists())
231             return ConstString(default_xcode_sdk.c_str());
232         }
233       }
234     }
235   }
236   return ConstString();
237 }
238 
239 Error PlatformMacOSX::GetSymbolFile(const FileSpec &platform_file,
240                                     const UUID *uuid_ptr,
241                                     FileSpec &local_file) {
242   if (IsRemote()) {
243     if (m_remote_platform_sp)
244       return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr,
245                                                    local_file);
246   }
247 
248   // Default to the local case
249   local_file = platform_file;
250   return Error();
251 }
252 
253 lldb_private::Error
254 PlatformMacOSX::GetFileWithUUID(const lldb_private::FileSpec &platform_file,
255                                 const lldb_private::UUID *uuid_ptr,
256                                 lldb_private::FileSpec &local_file) {
257   if (IsRemote() && m_remote_platform_sp) {
258     std::string local_os_build;
259 #if !defined(__linux__)
260     HostInfo::GetOSBuildString(local_os_build);
261 #endif
262     std::string remote_os_build;
263     m_remote_platform_sp->GetOSBuildString(remote_os_build);
264     if (local_os_build.compare(remote_os_build) == 0) {
265       // same OS version: the local file is good enough
266       local_file = platform_file;
267       return Error();
268     } else {
269       // try to find the file in the cache
270       std::string cache_path(GetLocalCacheDirectory());
271       std::string module_path(platform_file.GetPath());
272       cache_path.append(module_path);
273       FileSpec module_cache_spec(cache_path.c_str(), false);
274       if (module_cache_spec.Exists()) {
275         local_file = module_cache_spec;
276         return Error();
277       }
278       // bring in the remote module file
279       FileSpec module_cache_folder =
280           module_cache_spec.CopyByRemovingLastPathComponent();
281       // try to make the local directory first
282       Error err = FileSystem::MakeDirectory(module_cache_folder,
283                                             eFilePermissionsDirectoryDefault);
284       if (err.Fail())
285         return err;
286       err = GetFile(platform_file, module_cache_spec);
287       if (err.Fail())
288         return err;
289       if (module_cache_spec.Exists()) {
290         local_file = module_cache_spec;
291         return Error();
292       } else
293         return Error("unable to obtain valid module file");
294     }
295   }
296   local_file = platform_file;
297   return Error();
298 }
299 
300 bool PlatformMacOSX::GetSupportedArchitectureAtIndex(uint32_t idx,
301                                                      ArchSpec &arch) {
302 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
303   return ARMGetSupportedArchitectureAtIndex(idx, arch);
304 #else
305   return x86GetSupportedArchitectureAtIndex(idx, arch);
306 #endif
307 }
308 
309 lldb_private::Error PlatformMacOSX::GetSharedModule(
310     const lldb_private::ModuleSpec &module_spec, Process *process,
311     lldb::ModuleSP &module_sp,
312     const lldb_private::FileSpecList *module_search_paths_ptr,
313     lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr) {
314   Error error = GetSharedModuleWithLocalCache(
315       module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr,
316       did_create_ptr);
317 
318   if (module_sp) {
319     if (module_spec.GetArchitecture().GetCore() ==
320         ArchSpec::eCore_x86_64_x86_64h) {
321       ObjectFile *objfile = module_sp->GetObjectFile();
322       if (objfile == NULL) {
323         // We didn't find an x86_64h slice, fall back to a x86_64 slice
324         ModuleSpec module_spec_x86_64(module_spec);
325         module_spec_x86_64.GetArchitecture() = ArchSpec("x86_64-apple-macosx");
326         lldb::ModuleSP x86_64_module_sp;
327         lldb::ModuleSP old_x86_64_module_sp;
328         bool did_create = false;
329         Error x86_64_error = GetSharedModuleWithLocalCache(
330             module_spec_x86_64, x86_64_module_sp, module_search_paths_ptr,
331             &old_x86_64_module_sp, &did_create);
332         if (x86_64_module_sp && x86_64_module_sp->GetObjectFile()) {
333           module_sp = x86_64_module_sp;
334           if (old_module_sp_ptr)
335             *old_module_sp_ptr = old_x86_64_module_sp;
336           if (did_create_ptr)
337             *did_create_ptr = did_create;
338           return x86_64_error;
339         }
340       }
341     }
342   }
343   return error;
344 }
345