1 //===-- HostInfoMacOSX.mm ---------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Host/HostInfo.h"
11 #include "lldb/Host/macosx/HostInfoMacOSX.h"
12 #include "lldb/Utility/Args.h"
13 #include "lldb/Utility/Log.h"
14 #include "lldb/Utility/SafeMachO.h"
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/Support/FileSystem.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/raw_ostream.h"
26 #include <sys/sysctl.h>
27 #include <sys/syslimits.h>
28 #include <sys/types.h>
30 // Objective-C/C++ includes
31 #include <CoreFoundation/CoreFoundation.h>
32 #include <Foundation/Foundation.h>
33 #include <mach-o/dyld.h>
34 #include <objc/objc-auto.h>
36 // These are needed when compiling on systems
37 // that do not yet have these definitions
38 #include <AvailabilityMacros.h>
39 #ifndef CPU_SUBTYPE_X86_64_H
40 #define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8)
42 #ifndef CPU_TYPE_ARM64
43 #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
46 #include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH
48 using namespace lldb_private;
50 bool HostInfoMacOSX::GetOSBuildString(std::string &s) {
51 int mib[2] = {CTL_KERN, KERN_OSVERSION};
53 size_t cstr_len = sizeof(cstr);
54 if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0) {
55 s.assign(cstr, cstr_len);
63 bool HostInfoMacOSX::GetOSKernelDescription(std::string &s) {
64 int mib[2] = {CTL_KERN, KERN_VERSION};
66 size_t cstr_len = sizeof(cstr);
67 if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0) {
68 s.assign(cstr, cstr_len);
75 llvm::VersionTuple HostInfoMacOSX::GetOSVersion() {
76 static llvm::VersionTuple g_version;
78 if (g_version.empty()) {
80 NSDictionary *version_info = [NSDictionary
81 dictionaryWithContentsOfFile:
82 @"/System/Library/CoreServices/SystemVersion.plist"];
83 NSString *version_value = [version_info objectForKey:@"ProductVersion"];
84 const char *version_str = [version_value UTF8String];
85 g_version.tryParse(version_str);
92 FileSpec HostInfoMacOSX::GetProgramFileSpec() {
93 static FileSpec g_program_filespec;
94 if (!g_program_filespec) {
95 char program_fullpath[PATH_MAX];
96 // If DST is NULL, then return the number of bytes needed.
97 uint32_t len = sizeof(program_fullpath);
98 int err = _NSGetExecutablePath(program_fullpath, &len);
100 g_program_filespec.SetFile(program_fullpath, false,
101 FileSpec::Style::native);
102 else if (err == -1) {
103 char *large_program_fullpath = (char *)::malloc(len + 1);
105 err = _NSGetExecutablePath(large_program_fullpath, &len);
107 g_program_filespec.SetFile(large_program_fullpath, false,
108 FileSpec::Style::native);
110 ::free(large_program_fullpath);
113 return g_program_filespec;
116 bool HostInfoMacOSX::ComputeSupportExeDirectory(FileSpec &file_spec) {
117 FileSpec lldb_file_spec = GetShlibDir();
121 std::string raw_path = lldb_file_spec.GetPath();
123 size_t framework_pos = raw_path.find("LLDB.framework");
124 if (framework_pos != std::string::npos) {
125 framework_pos += strlen("LLDB.framework");
126 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
128 raw_path.resize(framework_pos);
131 raw_path.resize(framework_pos);
132 raw_path.append("/Resources");
135 // Find the bin path relative to the lib path where the cmake-based
136 // OS X .dylib lives. This is not going to work if the bin and lib
137 // dir are not both in the same dir.
139 // It is not going to work to do it by the executable path either,
140 // as in the case of a python script, the executable is python, not
142 raw_path.append("/../bin");
143 FileSpec support_dir_spec(raw_path, true);
144 if (!llvm::sys::fs::is_directory(support_dir_spec.GetPath())) {
145 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
147 log->Printf("HostInfoMacOSX::%s(): failed to find support directory",
152 // Get normalization from support_dir_spec. Note the FileSpec resolve
153 // does not remove '..' in the path.
154 char *const dir_realpath =
155 realpath(support_dir_spec.GetPath().c_str(), NULL);
157 raw_path = dir_realpath;
160 raw_path = support_dir_spec.GetPath();
164 file_spec.GetDirectory().SetString(
165 llvm::StringRef(raw_path.c_str(), raw_path.size()));
166 return (bool)file_spec.GetDirectory();
169 bool HostInfoMacOSX::ComputeHeaderDirectory(FileSpec &file_spec) {
170 FileSpec lldb_file_spec = GetShlibDir();
174 std::string raw_path = lldb_file_spec.GetPath();
176 size_t framework_pos = raw_path.find("LLDB.framework");
177 if (framework_pos != std::string::npos) {
178 framework_pos += strlen("LLDB.framework");
179 raw_path.resize(framework_pos);
180 raw_path.append("/Headers");
182 file_spec.GetDirectory().SetString(
183 llvm::StringRef(raw_path.c_str(), raw_path.size()));
187 bool HostInfoMacOSX::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
188 FileSpec lldb_file_spec = GetShlibDir();
192 std::string raw_path = lldb_file_spec.GetPath();
194 size_t framework_pos = raw_path.find("LLDB.framework");
195 if (framework_pos == std::string::npos)
198 framework_pos += strlen("LLDB.framework");
199 raw_path.resize(framework_pos);
200 raw_path.append("/Resources/PlugIns");
201 file_spec.GetDirectory().SetString(
202 llvm::StringRef(raw_path.c_str(), raw_path.size()));
206 bool HostInfoMacOSX::ComputeUserPluginsDirectory(FileSpec &file_spec) {
207 FileSpec temp_file("~/Library/Application Support/LLDB/PlugIns", true);
208 file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str());
212 void HostInfoMacOSX::ComputeHostArchitectureSupport(ArchSpec &arch_32,
214 // All apple systems support 32 bit execution.
215 uint32_t cputype, cpusubtype;
216 uint32_t is_64_bit_capable = false;
217 size_t len = sizeof(cputype);
219 // These will tell us about the kernel architecture, which even on a 64
220 // bit machine can be 32 bit...
221 if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0) {
222 len = sizeof(cpusubtype);
223 if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0)
224 cpusubtype = CPU_TYPE_ANY;
226 len = sizeof(is_64_bit_capable);
227 ::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0);
229 if (is_64_bit_capable) {
230 if (cputype & CPU_ARCH_ABI64) {
231 // We have a 64 bit kernel on a 64 bit system
232 arch_64.SetArchitecture(eArchTypeMachO, cputype, cpusubtype);
234 // We have a 64 bit kernel that is returning a 32 bit cputype, the
235 // cpusubtype will be correct as if it were for a 64 bit architecture
236 arch_64.SetArchitecture(eArchTypeMachO, cputype | CPU_ARCH_ABI64,
240 // Now we need modify the cpusubtype for the 32 bit slices.
241 uint32_t cpusubtype32 = cpusubtype;
242 #if defined(__i386__) || defined(__x86_64__)
243 if (cpusubtype == CPU_SUBTYPE_486 || cpusubtype == CPU_SUBTYPE_X86_64_H)
244 cpusubtype32 = CPU_SUBTYPE_I386_ALL;
245 #elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
246 if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
247 cpusubtype32 = CPU_SUBTYPE_ARM_V7S;
249 arch_32.SetArchitecture(eArchTypeMachO, cputype & ~(CPU_ARCH_MASK),
252 if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64) {
253 // When running on a watch or tv, report the host os correctly
254 #if defined(TARGET_OS_TV) && TARGET_OS_TV == 1
255 arch_32.GetTriple().setOS(llvm::Triple::TvOS);
256 arch_64.GetTriple().setOS(llvm::Triple::TvOS);
258 arch_32.GetTriple().setOS(llvm::Triple::IOS);
259 arch_64.GetTriple().setOS(llvm::Triple::IOS);
262 arch_32.GetTriple().setOS(llvm::Triple::MacOSX);
263 arch_64.GetTriple().setOS(llvm::Triple::MacOSX);
266 // We have a 32 bit kernel on a 32 bit system
267 arch_32.SetArchitecture(eArchTypeMachO, cputype, cpusubtype);
268 #if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
269 arch_32.GetTriple().setOS(llvm::Triple::WatchOS);
271 arch_32.GetTriple().setOS(llvm::Triple::IOS);