]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Host/macosx/HostInfoMacOSX.mm
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / source / Host / macosx / HostInfoMacOSX.mm
1 //===-- HostInfoMacOSX.mm ---------------------------------------*- 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 #if !defined(LLDB_DISABLE_PYTHON)
11 #include "Plugins/ScriptInterpreter/Python/lldb-python.h"
12 #endif
13
14 #include "lldb/Core/Log.h"
15 #include "lldb/Host/HostInfo.h"
16 #include "lldb/Host/macosx/HostInfoMacOSX.h"
17 #include "lldb/Interpreter/Args.h"
18 #include "lldb/Utility/SafeMachO.h"
19
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/Support/raw_ostream.h"
22
23 // C++ Includes
24 #include <string>
25
26 // C inclues
27 #include <stdlib.h>
28 #include <sys/sysctl.h>
29 #include <sys/syslimits.h>
30 #include <sys/types.h>
31
32 // Objective C/C++ includes
33 #include <CoreFoundation/CoreFoundation.h>
34 #include <Foundation/Foundation.h>
35 #include <mach-o/dyld.h>
36 #include <objc/objc-auto.h>
37
38 // These are needed when compiling on systems
39 // that do not yet have these definitions
40 #include <AvailabilityMacros.h>
41 #ifndef CPU_SUBTYPE_X86_64_H
42 #define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8)
43 #endif
44 #ifndef CPU_TYPE_ARM64
45 #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
46 #endif
47
48 #include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH
49
50 using namespace lldb_private;
51
52 bool HostInfoMacOSX::GetOSBuildString(std::string &s) {
53   int mib[2] = {CTL_KERN, KERN_OSVERSION};
54   char cstr[PATH_MAX];
55   size_t cstr_len = sizeof(cstr);
56   if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0) {
57     s.assign(cstr, cstr_len);
58     return true;
59   }
60
61   s.clear();
62   return false;
63 }
64
65 bool HostInfoMacOSX::GetOSKernelDescription(std::string &s) {
66   int mib[2] = {CTL_KERN, KERN_VERSION};
67   char cstr[PATH_MAX];
68   size_t cstr_len = sizeof(cstr);
69   if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0) {
70     s.assign(cstr, cstr_len);
71     return true;
72   }
73   s.clear();
74   return false;
75 }
76
77 bool HostInfoMacOSX::GetOSVersion(uint32_t &major, uint32_t &minor,
78                                   uint32_t &update) {
79   static uint32_t g_major = 0;
80   static uint32_t g_minor = 0;
81   static uint32_t g_update = 0;
82
83   if (g_major == 0) {
84     @autoreleasepool {
85       NSDictionary *version_info = [NSDictionary
86           dictionaryWithContentsOfFile:
87               @"/System/Library/CoreServices/SystemVersion.plist"];
88       NSString *version_value = [version_info objectForKey:@"ProductVersion"];
89       const char *version_str = [version_value UTF8String];
90       if (version_str)
91         Args::StringToVersion(llvm::StringRef(version_str), g_major, g_minor,
92                               g_update);
93     }
94   }
95
96   if (g_major != 0) {
97     major = g_major;
98     minor = g_minor;
99     update = g_update;
100     return true;
101   }
102   return false;
103 }
104
105 FileSpec HostInfoMacOSX::GetProgramFileSpec() {
106   static FileSpec g_program_filespec;
107   if (!g_program_filespec) {
108     char program_fullpath[PATH_MAX];
109     // If DST is NULL, then return the number of bytes needed.
110     uint32_t len = sizeof(program_fullpath);
111     int err = _NSGetExecutablePath(program_fullpath, &len);
112     if (err == 0)
113       g_program_filespec.SetFile(program_fullpath, false);
114     else if (err == -1) {
115       char *large_program_fullpath = (char *)::malloc(len + 1);
116
117       err = _NSGetExecutablePath(large_program_fullpath, &len);
118       if (err == 0)
119         g_program_filespec.SetFile(large_program_fullpath, false);
120
121       ::free(large_program_fullpath);
122     }
123   }
124   return g_program_filespec;
125 }
126
127 bool HostInfoMacOSX::ComputeSupportExeDirectory(FileSpec &file_spec) {
128   FileSpec lldb_file_spec;
129   if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
130     return false;
131
132   std::string raw_path = lldb_file_spec.GetPath();
133
134   size_t framework_pos = raw_path.find("LLDB.framework");
135   if (framework_pos != std::string::npos) {
136     framework_pos += strlen("LLDB.framework");
137 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
138     // Shallow bundle
139     raw_path.resize(framework_pos);
140 #else
141     // Normal bundle
142     raw_path.resize(framework_pos);
143     raw_path.append("/Resources");
144 #endif
145   } else {
146     // Find the bin path relative to the lib path where the cmake-based
147     // OS X .dylib lives.  This is not going to work if the bin and lib
148     // dir are not both in the same dir.
149     //
150     // It is not going to work to do it by the executable path either,
151     // as in the case of a python script, the executable is python, not
152     // the lldb driver.
153     raw_path.append("/../bin");
154     FileSpec support_dir_spec(raw_path, true);
155     if (!support_dir_spec.Exists() || !support_dir_spec.IsDirectory()) {
156       Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
157       if (log)
158         log->Printf("HostInfoMacOSX::%s(): failed to find support directory",
159                     __FUNCTION__);
160       return false;
161     }
162
163     // Get normalization from support_dir_spec.  Note the FileSpec resolve
164     // does not remove '..' in the path.
165     char *const dir_realpath =
166         realpath(support_dir_spec.GetPath().c_str(), NULL);
167     if (dir_realpath) {
168       raw_path = dir_realpath;
169       free(dir_realpath);
170     } else {
171       raw_path = support_dir_spec.GetPath();
172     }
173   }
174
175   file_spec.GetDirectory().SetString(
176       llvm::StringRef(raw_path.c_str(), raw_path.size()));
177   return (bool)file_spec.GetDirectory();
178 }
179
180 bool HostInfoMacOSX::ComputeHeaderDirectory(FileSpec &file_spec) {
181   FileSpec lldb_file_spec;
182   if (!HostInfo::GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
183     return false;
184
185   std::string raw_path = lldb_file_spec.GetPath();
186
187   size_t framework_pos = raw_path.find("LLDB.framework");
188   if (framework_pos != std::string::npos) {
189     framework_pos += strlen("LLDB.framework");
190     raw_path.resize(framework_pos);
191     raw_path.append("/Headers");
192   }
193   file_spec.GetDirectory().SetString(
194       llvm::StringRef(raw_path.c_str(), raw_path.size()));
195   return true;
196 }
197
198 bool HostInfoMacOSX::ComputePythonDirectory(FileSpec &file_spec) {
199 #ifndef LLDB_DISABLE_PYTHON
200   FileSpec lldb_file_spec;
201   if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
202     return false;
203
204   std::string raw_path = lldb_file_spec.GetPath();
205
206   size_t framework_pos = raw_path.find("LLDB.framework");
207   if (framework_pos != std::string::npos) {
208     framework_pos += strlen("LLDB.framework");
209     raw_path.resize(framework_pos);
210     raw_path.append("/Resources/Python");
211   } else {
212     llvm::SmallString<256> python_version_dir;
213     llvm::raw_svector_ostream os(python_version_dir);
214     os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION
215        << "/site-packages";
216
217     // We may get our string truncated. Should we protect this with an assert?
218     raw_path.append(python_version_dir.c_str());
219   }
220   file_spec.GetDirectory().SetString(
221       llvm::StringRef(raw_path.c_str(), raw_path.size()));
222   return true;
223 #else
224   return false;
225 #endif
226 }
227
228 bool HostInfoMacOSX::ComputeClangDirectory(FileSpec &file_spec) {
229   FileSpec lldb_file_spec;
230   if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
231     return false;
232
233   std::string raw_path = lldb_file_spec.GetPath();
234
235   size_t framework_pos = raw_path.find("LLDB.framework");
236   if (framework_pos == std::string::npos)
237     return HostInfoPosix::ComputeClangDirectory(file_spec);
238   
239   framework_pos += strlen("LLDB.framework");
240   raw_path.resize(framework_pos);
241   raw_path.append("/Resources/Clang");
242   
243   file_spec.SetFile(raw_path.c_str(), true);
244   return true;
245 }
246
247 bool HostInfoMacOSX::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
248   FileSpec lldb_file_spec;
249   if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
250     return false;
251
252   std::string raw_path = lldb_file_spec.GetPath();
253
254   size_t framework_pos = raw_path.find("LLDB.framework");
255   if (framework_pos == std::string::npos)
256     return false;
257
258   framework_pos += strlen("LLDB.framework");
259   raw_path.resize(framework_pos);
260   raw_path.append("/Resources/PlugIns");
261   file_spec.GetDirectory().SetString(
262       llvm::StringRef(raw_path.c_str(), raw_path.size()));
263   return true;
264 }
265
266 bool HostInfoMacOSX::ComputeUserPluginsDirectory(FileSpec &file_spec) {
267   FileSpec temp_file("~/Library/Application Support/LLDB/PlugIns", true);
268   file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str());
269   return true;
270 }
271
272 void HostInfoMacOSX::ComputeHostArchitectureSupport(ArchSpec &arch_32,
273                                                     ArchSpec &arch_64) {
274   // All apple systems support 32 bit execution.
275   uint32_t cputype, cpusubtype;
276   uint32_t is_64_bit_capable = false;
277   size_t len = sizeof(cputype);
278   ArchSpec host_arch;
279   // These will tell us about the kernel architecture, which even on a 64
280   // bit machine can be 32 bit...
281   if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0) {
282     len = sizeof(cpusubtype);
283     if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0)
284       cpusubtype = CPU_TYPE_ANY;
285
286     len = sizeof(is_64_bit_capable);
287     ::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0);
288
289     if (is_64_bit_capable) {
290       if (cputype & CPU_ARCH_ABI64) {
291         // We have a 64 bit kernel on a 64 bit system
292         arch_64.SetArchitecture(eArchTypeMachO, cputype, cpusubtype);
293       } else {
294         // We have a 64 bit kernel that is returning a 32 bit cputype, the
295         // cpusubtype will be correct as if it were for a 64 bit architecture
296         arch_64.SetArchitecture(eArchTypeMachO, cputype | CPU_ARCH_ABI64,
297                                 cpusubtype);
298       }
299
300       // Now we need modify the cpusubtype for the 32 bit slices.
301       uint32_t cpusubtype32 = cpusubtype;
302 #if defined(__i386__) || defined(__x86_64__)
303       if (cpusubtype == CPU_SUBTYPE_486 || cpusubtype == CPU_SUBTYPE_X86_64_H)
304         cpusubtype32 = CPU_SUBTYPE_I386_ALL;
305 #elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
306       if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
307         cpusubtype32 = CPU_SUBTYPE_ARM_V7S;
308 #endif
309       arch_32.SetArchitecture(eArchTypeMachO, cputype & ~(CPU_ARCH_MASK),
310                               cpusubtype32);
311
312       if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64) {
313 // When running on a watch or tv, report the host os correctly
314 #if defined(TARGET_OS_TV) && TARGET_OS_TV == 1
315         arch_32.GetTriple().setOS(llvm::Triple::TvOS);
316         arch_64.GetTriple().setOS(llvm::Triple::TvOS);
317 #else
318         arch_32.GetTriple().setOS(llvm::Triple::IOS);
319         arch_64.GetTriple().setOS(llvm::Triple::IOS);
320 #endif
321       } else {
322         arch_32.GetTriple().setOS(llvm::Triple::MacOSX);
323         arch_64.GetTriple().setOS(llvm::Triple::MacOSX);
324       }
325     } else {
326       // We have a 32 bit kernel on a 32 bit system
327       arch_32.SetArchitecture(eArchTypeMachO, cputype, cpusubtype);
328 #if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
329       arch_32.GetTriple().setOS(llvm::Triple::WatchOS);
330 #else
331       arch_32.GetTriple().setOS(llvm::Triple::IOS);
332 #endif
333       arch_64.Clear();
334     }
335   }
336 }
337
338 uint32_t HostInfoMacOSX::GetMaxThreadNameLength() { return 64; }