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 #if !defined(LLDB_DISABLE_PYTHON)
11 #include "Plugins/ScriptInterpreter/Python/lldb-python.h"
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"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/Support/raw_ostream.h"
28 #include <sys/sysctl.h>
29 #include <sys/syslimits.h>
30 #include <sys/types.h>
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>
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)
44 #ifndef CPU_TYPE_ARM64
45 #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
48 #include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH
50 using namespace lldb_private;
52 bool HostInfoMacOSX::GetOSBuildString(std::string &s) {
53 int mib[2] = {CTL_KERN, KERN_OSVERSION};
55 size_t cstr_len = sizeof(cstr);
56 if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0) {
57 s.assign(cstr, cstr_len);
65 bool HostInfoMacOSX::GetOSKernelDescription(std::string &s) {
66 int mib[2] = {CTL_KERN, KERN_VERSION};
68 size_t cstr_len = sizeof(cstr);
69 if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0) {
70 s.assign(cstr, cstr_len);
77 bool HostInfoMacOSX::GetOSVersion(uint32_t &major, uint32_t &minor,
79 static uint32_t g_major = 0;
80 static uint32_t g_minor = 0;
81 static uint32_t g_update = 0;
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];
91 Args::StringToVersion(llvm::StringRef(version_str), g_major, g_minor,
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);
113 g_program_filespec.SetFile(program_fullpath, false);
114 else if (err == -1) {
115 char *large_program_fullpath = (char *)::malloc(len + 1);
117 err = _NSGetExecutablePath(large_program_fullpath, &len);
119 g_program_filespec.SetFile(large_program_fullpath, false);
121 ::free(large_program_fullpath);
124 return g_program_filespec;
127 bool HostInfoMacOSX::ComputeSupportExeDirectory(FileSpec &file_spec) {
128 FileSpec lldb_file_spec;
129 if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
132 std::string raw_path = lldb_file_spec.GetPath();
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__)
139 raw_path.resize(framework_pos);
142 raw_path.resize(framework_pos);
143 raw_path.append("/Resources");
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.
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
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);
158 log->Printf("HostInfoMacOSX::%s(): failed to find support directory",
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);
168 raw_path = dir_realpath;
171 raw_path = support_dir_spec.GetPath();
175 file_spec.GetDirectory().SetString(
176 llvm::StringRef(raw_path.c_str(), raw_path.size()));
177 return (bool)file_spec.GetDirectory();
180 bool HostInfoMacOSX::ComputeHeaderDirectory(FileSpec &file_spec) {
181 FileSpec lldb_file_spec;
182 if (!HostInfo::GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
185 std::string raw_path = lldb_file_spec.GetPath();
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");
193 file_spec.GetDirectory().SetString(
194 llvm::StringRef(raw_path.c_str(), raw_path.size()));
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))
204 std::string raw_path = lldb_file_spec.GetPath();
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");
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
217 // We may get our string truncated. Should we protect this with an assert?
218 raw_path.append(python_version_dir.c_str());
220 file_spec.GetDirectory().SetString(
221 llvm::StringRef(raw_path.c_str(), raw_path.size()));
228 bool HostInfoMacOSX::ComputeClangDirectory(FileSpec &file_spec) {
229 FileSpec lldb_file_spec;
230 if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
233 std::string raw_path = lldb_file_spec.GetPath();
235 size_t framework_pos = raw_path.find("LLDB.framework");
236 if (framework_pos == std::string::npos)
237 return HostInfoPosix::ComputeClangDirectory(file_spec);
239 framework_pos += strlen("LLDB.framework");
240 raw_path.resize(framework_pos);
241 raw_path.append("/Resources/Clang");
243 file_spec.SetFile(raw_path.c_str(), true);
247 bool HostInfoMacOSX::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
248 FileSpec lldb_file_spec;
249 if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
252 std::string raw_path = lldb_file_spec.GetPath();
254 size_t framework_pos = raw_path.find("LLDB.framework");
255 if (framework_pos == std::string::npos)
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()));
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());
272 void HostInfoMacOSX::ComputeHostArchitectureSupport(ArchSpec &arch_32,
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);
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;
286 len = sizeof(is_64_bit_capable);
287 ::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0);
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);
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,
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;
309 arch_32.SetArchitecture(eArchTypeMachO, cputype & ~(CPU_ARCH_MASK),
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);
318 arch_32.GetTriple().setOS(llvm::Triple::IOS);
319 arch_64.GetTriple().setOS(llvm::Triple::IOS);
322 arch_32.GetTriple().setOS(llvm::Triple::MacOSX);
323 arch_64.GetTriple().setOS(llvm::Triple::MacOSX);
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);
331 arch_32.GetTriple().setOS(llvm::Triple::IOS);
338 uint32_t HostInfoMacOSX::GetMaxThreadNameLength() { return 64; }