summaryrefslogtreecommitdiff
path: root/source/Host/macosx
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-01-06 20:12:03 +0000
commit9e6d35490a6542f9c97607f93c2ef8ca8e03cbcc (patch)
treedd2a1ddf0476664c2b823409c36cbccd52662ca7 /source/Host/macosx
parent3bd2e91faeb9eeec1aae82c64a3253afff551cfd (diff)
Notes
Diffstat (limited to 'source/Host/macosx')
-rw-r--r--source/Host/macosx/Host.mm1587
-rw-r--r--source/Host/macosx/HostInfoMacOSX.mm372
-rw-r--r--source/Host/macosx/HostThreadMacOSX.mm102
-rw-r--r--source/Host/macosx/Symbols.cpp559
-rw-r--r--source/Host/macosx/ThisThread.cpp39
-rw-r--r--source/Host/macosx/cfcpp/CFCBundle.cpp99
-rw-r--r--source/Host/macosx/cfcpp/CFCBundle.h50
-rw-r--r--source/Host/macosx/cfcpp/CFCData.cpp82
-rw-r--r--source/Host/macosx/cfcpp/CFCData.h35
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableArray.cpp166
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableArray.h39
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableDictionary.cpp529
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableDictionary.h79
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableSet.cpp114
-rw-r--r--source/Host/macosx/cfcpp/CFCMutableSet.h53
-rw-r--r--source/Host/macosx/cfcpp/CFCReleaser.h158
-rw-r--r--source/Host/macosx/cfcpp/CFCString.cpp195
-rw-r--r--source/Host/macosx/cfcpp/CFCString.h41
-rw-r--r--source/Host/macosx/cfcpp/CoreFoundationCPP.h30
19 files changed, 4329 insertions, 0 deletions
diff --git a/source/Host/macosx/Host.mm b/source/Host/macosx/Host.mm
new file mode 100644
index 0000000000000..2db27a276e4ab
--- /dev/null
+++ b/source/Host/macosx/Host.mm
@@ -0,0 +1,1587 @@
+//===-- Host.mm -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Host.h"
+
+#include <AvailabilityMacros.h>
+
+#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+#define NO_XPC_SERVICES 1
+#endif
+
+#if !defined(NO_XPC_SERVICES)
+#define __XPC_PRIVATE_H__
+#include <xpc/xpc.h>
+
+#define LaunchUsingXPCRightName "com.apple.dt.Xcode.RootDebuggingXPCService"
+
+// These XPC messaging keys are used for communication between Host.mm and the XPC service.
+#define LauncherXPCServiceAuthKey "auth-key"
+#define LauncherXPCServiceArgPrefxKey "arg"
+#define LauncherXPCServiceEnvPrefxKey "env"
+#define LauncherXPCServiceCPUTypeKey "cpuType"
+#define LauncherXPCServicePosixspawnFlagsKey "posixspawnFlags"
+#define LauncherXPCServiceStdInPathKeyKey "stdInPath"
+#define LauncherXPCServiceStdOutPathKeyKey "stdOutPath"
+#define LauncherXPCServiceStdErrPathKeyKey "stdErrPath"
+#define LauncherXPCServiceChildPIDKey "childPID"
+#define LauncherXPCServiceErrorTypeKey "errorType"
+#define LauncherXPCServiceCodeTypeKey "errorCode"
+
+#endif
+
+#include "llvm/Support/Host.h"
+
+#include <asl.h>
+#include <crt_externs.h>
+#include <grp.h>
+#include <libproc.h>
+#include <pwd.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StructuredData.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Utility/CleanUp.h"
+#include "lldb/Utility/NameMatches.h"
+
+#include "cfcpp/CFCBundle.h"
+#include "cfcpp/CFCMutableArray.h"
+#include "cfcpp/CFCMutableDictionary.h"
+#include "cfcpp/CFCReleaser.h"
+#include "cfcpp/CFCString.h"
+
+
+#include <objc/objc-auto.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+
+#ifndef _POSIX_SPAWN_DISABLE_ASLR
+#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
+#endif
+
+extern "C"
+{
+ int __pthread_chdir(const char *path);
+ int __pthread_fchdir (int fildes);
+}
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle_directory)
+{
+#if defined (__APPLE__)
+ if (file.GetFileType () == FileSpec::eFileTypeDirectory)
+ {
+ char path[PATH_MAX];
+ if (file.GetPath(path, sizeof(path)))
+ {
+ CFCBundle bundle (path);
+ if (bundle.GetPath (path, sizeof(path)))
+ {
+ bundle_directory.SetFile (path, false);
+ return true;
+ }
+ }
+ }
+#endif
+ bundle_directory.Clear();
+ return false;
+}
+
+
+bool
+Host::ResolveExecutableInBundle (FileSpec &file)
+{
+#if defined (__APPLE__)
+ if (file.GetFileType () == FileSpec::eFileTypeDirectory)
+ {
+ char path[PATH_MAX];
+ if (file.GetPath(path, sizeof(path)))
+ {
+ CFCBundle bundle (path);
+ CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
+ if (url.get())
+ {
+ if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
+ {
+ file.SetFile(path, false);
+ return true;
+ }
+ }
+ }
+ }
+#endif
+ return false;
+}
+
+static void *
+AcceptPIDFromInferior (void *arg)
+{
+ const char *connect_url = (const char *)arg;
+ ConnectionFileDescriptor file_conn;
+ Error error;
+ if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
+ {
+ char pid_str[256];
+ ::memset (pid_str, 0, sizeof(pid_str));
+ ConnectionStatus status;
+ const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL);
+ if (pid_str_len > 0)
+ {
+ int pid = atoi (pid_str);
+ return (void *)(intptr_t)pid;
+ }
+ }
+ return NULL;
+}
+
+static bool
+WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
+{
+ const int time_delta_usecs = 100000;
+ const int num_retries = timeout_in_seconds/time_delta_usecs;
+ for (int i=0; i<num_retries; i++)
+ {
+ struct proc_bsdinfo bsd_info;
+ int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
+ (uint64_t) 0,
+ &bsd_info,
+ PROC_PIDTBSDINFO_SIZE);
+
+ switch (error)
+ {
+ case EINVAL:
+ case ENOTSUP:
+ case ESRCH:
+ case EPERM:
+ return false;
+
+ default:
+ break;
+
+ case 0:
+ if (bsd_info.pbi_status == SSTOP)
+ return true;
+ }
+ ::usleep (time_delta_usecs);
+ }
+ return false;
+}
+#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
+
+//static lldb::pid_t
+//LaunchInNewTerminalWithCommandFile
+//(
+// const char **argv,
+// const char **envp,
+// const char *working_dir,
+// const ArchSpec *arch_spec,
+// bool stop_at_entry,
+// bool disable_aslr
+//)
+//{
+// if (!argv || !argv[0])
+// return LLDB_INVALID_PROCESS_ID;
+//
+// OSStatus error = 0;
+//
+// FileSpec program (argv[0], false);
+//
+//
+// std::string unix_socket_name;
+//
+// char temp_file_path[PATH_MAX];
+// const char *tmpdir = ::getenv ("TMPDIR");
+// if (tmpdir == NULL)
+// tmpdir = "/tmp/";
+// ::snprintf (temp_file_path, sizeof(temp_file_path), "%s%s-XXXXXX", tmpdir, program.GetFilename().AsCString());
+//
+// if (::mktemp (temp_file_path) == NULL)
+// return LLDB_INVALID_PROCESS_ID;
+//
+// unix_socket_name.assign (temp_file_path);
+//
+// ::strlcat (temp_file_path, ".command", sizeof (temp_file_path));
+//
+// StreamFile command_file;
+// command_file.GetFile().Open (temp_file_path,
+// File::eOpenOptionWrite | File::eOpenOptionCanCreate,
+// lldb::eFilePermissionsDefault);
+//
+// if (!command_file.GetFile().IsValid())
+// return LLDB_INVALID_PROCESS_ID;
+//
+// FileSpec darwin_debug_file_spec;
+// if (!HostInfo::GetLLDBPath (ePathTypeSupportExecutableDir, darwin_debug_file_spec))
+// return LLDB_INVALID_PROCESS_ID;
+// darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
+//
+// if (!darwin_debug_file_spec.Exists())
+// return LLDB_INVALID_PROCESS_ID;
+//
+// char launcher_path[PATH_MAX];
+// darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
+// command_file.Printf("\"%s\" ", launcher_path);
+//
+// command_file.Printf("--unix-socket=%s ", unix_socket_name.c_str());
+//
+// if (arch_spec && arch_spec->IsValid())
+// {
+// command_file.Printf("--arch=%s ", arch_spec->GetArchitectureName());
+// }
+//
+// if (disable_aslr)
+// {
+// command_file.PutCString("--disable-aslr ");
+// }
+//
+// command_file.PutCString("-- ");
+//
+// if (argv)
+// {
+// for (size_t i=0; argv[i] != NULL; ++i)
+// {
+// command_file.Printf("\"%s\" ", argv[i]);
+// }
+// }
+// command_file.PutCString("\necho Process exited with status $?\n");
+// command_file.GetFile().Close();
+// if (::chmod (temp_file_path, S_IRWXU | S_IRWXG) != 0)
+// return LLDB_INVALID_PROCESS_ID;
+//
+// CFCMutableDictionary cf_env_dict;
+//
+// const bool can_create = true;
+// if (envp)
+// {
+// for (size_t i=0; envp[i] != NULL; ++i)
+// {
+// const char *env_entry = envp[i];
+// const char *equal_pos = strchr(env_entry, '=');
+// if (equal_pos)
+// {
+// std::string env_key (env_entry, equal_pos);
+// std::string env_val (equal_pos + 1);
+// CFCString cf_env_key (env_key.c_str(), kCFStringEncodingUTF8);
+// CFCString cf_env_val (env_val.c_str(), kCFStringEncodingUTF8);
+// cf_env_dict.AddValue (cf_env_key.get(), cf_env_val.get(), can_create);
+// }
+// }
+// }
+//
+// LSApplicationParameters app_params;
+// ::memset (&app_params, 0, sizeof (app_params));
+// app_params.flags = kLSLaunchDontAddToRecents | kLSLaunchAsync;
+// app_params.argv = NULL;
+// app_params.environment = (CFDictionaryRef)cf_env_dict.get();
+//
+// CFCReleaser<CFURLRef> command_file_url (::CFURLCreateFromFileSystemRepresentation (NULL,
+// (const UInt8 *)temp_file_path,
+// strlen(temp_file_path),
+// false));
+//
+// CFCMutableArray urls;
+//
+// // Terminal.app will open the ".command" file we have created
+// // and run our process inside it which will wait at the entry point
+// // for us to attach.
+// urls.AppendValue(command_file_url.get());
+//
+//
+// lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+//
+// Error lldb_error;
+// // Sleep and wait a bit for debugserver to start to listen...
+// char connect_url[128];
+// ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name.c_str());
+//
+// // Spawn a new thread to accept incoming connection on the connect_url
+// // so we can grab the pid from the inferior
+// lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name.c_str(),
+// AcceptPIDFromInferior,
+// connect_url,
+// &lldb_error);
+//
+// ProcessSerialNumber psn;
+// error = LSOpenURLsWithRole(urls.get(), kLSRolesShell, NULL, &app_params, &psn, 1);
+// if (error == noErr)
+// {
+// thread_result_t accept_thread_result = NULL;
+// if (Host::ThreadJoin (accept_thread, &accept_thread_result, &lldb_error))
+// {
+// if (accept_thread_result)
+// {
+// pid = (intptr_t)accept_thread_result;
+//
+// // Wait for process to be stopped the entry point by watching
+// // for the process status to be set to SSTOP which indicates it it
+// // SIGSTOP'ed at the entry point
+// WaitForProcessToSIGSTOP (pid, 5);
+// }
+// }
+// }
+// else
+// {
+// Host::ThreadCancel (accept_thread, &lldb_error);
+// }
+//
+// return pid;
+//}
+
+const char *applscript_in_new_tty =
+"tell application \"Terminal\"\n"
+" do script \"%s\"\n"
+"end tell\n";
+
+
+const char *applscript_in_existing_tty = "\
+set the_shell_script to \"%s\"\n\
+tell application \"Terminal\"\n\
+ repeat with the_window in (get windows)\n\
+ repeat with the_tab in tabs of the_window\n\
+ set the_tty to tty in the_tab\n\
+ if the_tty contains \"%s\" then\n\
+ if the_tab is not busy then\n\
+ set selected of the_tab to true\n\
+ set frontmost of the_window to true\n\
+ do script the_shell_script in the_tab\n\
+ return\n\
+ end if\n\
+ end if\n\
+ end repeat\n\
+ end repeat\n\
+ do script the_shell_script\n\
+end tell\n";
+
+
+static Error
+LaunchInNewTerminalWithAppleScript (const char *exe_path, ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
+ if (::mktemp (unix_socket_name) == NULL)
+ {
+ error.SetErrorString ("failed to make temporary path for a unix socket");
+ return error;
+ }
+
+ StreamString command;
+ FileSpec darwin_debug_file_spec;
+ if (!HostInfo::GetLLDBPath(ePathTypeSupportExecutableDir, darwin_debug_file_spec))
+ {
+ error.SetErrorString ("can't locate the 'darwin-debug' executable");
+ return error;
+ }
+
+ darwin_debug_file_spec.GetFilename().SetCString("darwin-debug");
+
+ if (!darwin_debug_file_spec.Exists())
+ {
+ error.SetErrorStringWithFormat ("the 'darwin-debug' executable doesn't exists at '%s'",
+ darwin_debug_file_spec.GetPath().c_str());
+ return error;
+ }
+
+ char launcher_path[PATH_MAX];
+ darwin_debug_file_spec.GetPath(launcher_path, sizeof(launcher_path));
+
+ const ArchSpec &arch_spec = launch_info.GetArchitecture();
+ // Only set the architecture if it is valid and if it isn't Haswell (x86_64h).
+ if (arch_spec.IsValid() && arch_spec.GetCore() != ArchSpec::eCore_x86_64_x86_64h)
+ command.Printf("arch -arch %s ", arch_spec.GetArchitectureName());
+
+ command.Printf("'%s' --unix-socket=%s", launcher_path, unix_socket_name);
+
+ if (arch_spec.IsValid())
+ command.Printf(" --arch=%s", arch_spec.GetArchitectureName());
+
+ FileSpec working_dir{launch_info.GetWorkingDirectory()};
+ if (working_dir)
+ command.Printf(" --working-dir '%s'", working_dir.GetCString());
+ else
+ {
+ char cwd[PATH_MAX];
+ if (getcwd(cwd, PATH_MAX))
+ command.Printf(" --working-dir '%s'", cwd);
+ }
+
+ if (launch_info.GetFlags().Test (eLaunchFlagDisableASLR))
+ command.PutCString(" --disable-aslr");
+
+ // We are launching on this host in a terminal. So compare the environment on the host
+ // to what is supplied in the launch_info. Any items that aren't in the host environment
+ // need to be sent to darwin-debug. If we send all environment entries, we might blow the
+ // max command line length, so we only send user modified entries.
+ const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector ();
+
+ StringList host_env;
+ const size_t host_env_count = Host::GetEnvironment (host_env);
+
+ if (envp && envp[0])
+ {
+ const char *env_entry;
+ for (size_t env_idx = 0; (env_entry = envp[env_idx]) != NULL; ++env_idx)
+ {
+ bool add_entry = true;
+ for (size_t i=0; i<host_env_count; ++i)
+ {
+ const char *host_env_entry = host_env.GetStringAtIndex(i);
+ if (strcmp(env_entry, host_env_entry) == 0)
+ {
+ add_entry = false;
+ break;
+ }
+ }
+ if (add_entry)
+ {
+ command.Printf(" --env='%s'", env_entry);
+ }
+ }
+ }
+
+ command.PutCString(" -- ");
+
+ const char **argv = launch_info.GetArguments().GetConstArgumentVector ();
+ if (argv)
+ {
+ for (size_t i=0; argv[i] != NULL; ++i)
+ {
+ if (i==0)
+ command.Printf(" '%s'", exe_path);
+ else
+ command.Printf(" '%s'", argv[i]);
+ }
+ }
+ else
+ {
+ command.Printf(" '%s'", exe_path);
+ }
+ command.PutCString (" ; echo Process exited with status $?");
+ if (launch_info.GetFlags().Test(lldb::eLaunchFlagCloseTTYOnExit))
+ command.PutCString (" ; exit");
+
+ StreamString applescript_source;
+
+ const char *tty_command = command.GetString().c_str();
+// if (tty_name && tty_name[0])
+// {
+// applescript_source.Printf (applscript_in_existing_tty,
+// tty_command,
+// tty_name);
+// }
+// else
+// {
+ applescript_source.Printf (applscript_in_new_tty,
+ tty_command);
+// }
+
+
+
+ const char *script_source = applescript_source.GetString().c_str();
+ //puts (script_source);
+ NSAppleScript* applescript = [[NSAppleScript alloc] initWithSource:[NSString stringWithCString:script_source encoding:NSUTF8StringEncoding]];
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ Error lldb_error;
+ // Sleep and wait a bit for debugserver to start to listen...
+ ConnectionFileDescriptor file_conn;
+ char connect_url[128];
+ ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
+
+ // Spawn a new thread to accept incoming connection on the connect_url
+ // so we can grab the pid from the inferior. We have to do this because we
+ // are sending an AppleScript that will launch a process in Terminal.app,
+ // in a shell and the shell will fork/exec a couple of times before we get
+ // to the process that we wanted to launch. So when our process actually
+ // gets launched, we will handshake with it and get the process ID for it.
+ HostThread accept_thread = ThreadLauncher::LaunchThread(unix_socket_name, AcceptPIDFromInferior, connect_url, &lldb_error);
+
+ [applescript executeAndReturnError:nil];
+
+ thread_result_t accept_thread_result = NULL;
+ lldb_error = accept_thread.Join(&accept_thread_result);
+ if (lldb_error.Success() && accept_thread_result)
+ {
+ pid = (intptr_t)accept_thread_result;
+
+ // Wait for process to be stopped at the entry point by watching
+ // for the process status to be set to SSTOP which indicates it it
+ // SIGSTOP'ed at the entry point
+ WaitForProcessToSIGSTOP(pid, 5);
+ }
+
+ FileSystem::Unlink(FileSpec{unix_socket_name, false});
+ [applescript release];
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ launch_info.SetProcessID (pid);
+ return error;
+}
+
+#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
+
+
+// On MacOSX CrashReporter will display a string for each shared library if
+// the shared library has an exported symbol named "__crashreporter_info__".
+
+static Mutex&
+GetCrashReporterMutex ()
+{
+ static Mutex g_mutex;
+ return g_mutex;
+}
+
+extern "C" {
+ const char *__crashreporter_info__ = NULL;
+}
+
+asm(".desc ___crashreporter_info__, 0x10");
+
+void
+Host::SetCrashDescriptionWithFormat (const char *format, ...)
+{
+ static StreamString g_crash_description;
+ Mutex::Locker locker (GetCrashReporterMutex ());
+
+ if (format)
+ {
+ va_list args;
+ va_start (args, format);
+ g_crash_description.GetString().clear();
+ g_crash_description.PrintfVarArg(format, args);
+ va_end (args);
+ __crashreporter_info__ = g_crash_description.GetData();
+ }
+ else
+ {
+ __crashreporter_info__ = NULL;
+ }
+}
+
+void
+Host::SetCrashDescription (const char *cstr)
+{
+ Mutex::Locker locker (GetCrashReporterMutex ());
+ static std::string g_crash_description;
+ if (cstr)
+ {
+ g_crash_description.assign (cstr);
+ __crashreporter_info__ = g_crash_description.c_str();
+ }
+ else
+ {
+ __crashreporter_info__ = NULL;
+ }
+}
+
+bool
+Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
+{
+#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ return false;
+#else
+ // We attach this to an 'odoc' event to specify a particular selection
+ typedef struct {
+ int16_t reserved0; // must be zero
+ int16_t fLineNumber;
+ int32_t fSelStart;
+ int32_t fSelEnd;
+ uint32_t reserved1; // must be zero
+ uint32_t reserved2; // must be zero
+ } BabelAESelInfo;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST));
+ char file_path[PATH_MAX];
+ file_spec.GetPath(file_path, PATH_MAX);
+ CFCString file_cfstr (file_path, kCFStringEncodingUTF8);
+ CFCReleaser<CFURLRef> file_URL (::CFURLCreateWithFileSystemPath (NULL,
+ file_cfstr.get(),
+ kCFURLPOSIXPathStyle,
+ false));
+
+ if (log)
+ log->Printf("Sending source file: \"%s\" and line: %d to external editor.\n", file_path, line_no);
+
+ long error;
+ BabelAESelInfo file_and_line_info =
+ {
+ 0, // reserved0
+ (int16_t)(line_no - 1), // fLineNumber (zero based line number)
+ 1, // fSelStart
+ 1024, // fSelEnd
+ 0, // reserved1
+ 0 // reserved2
+ };
+
+ AEKeyDesc file_and_line_desc;
+
+ error = ::AECreateDesc (typeUTF8Text,
+ &file_and_line_info,
+ sizeof (file_and_line_info),
+ &(file_and_line_desc.descContent));
+
+ if (error != noErr)
+ {
+ if (log)
+ log->Printf("Error creating AEDesc: %ld.\n", error);
+ return false;
+ }
+
+ file_and_line_desc.descKey = keyAEPosition;
+
+ static std::string g_app_name;
+ static FSRef g_app_fsref;
+
+ LSApplicationParameters app_params;
+ ::memset (&app_params, 0, sizeof (app_params));
+ app_params.flags = kLSLaunchDefaults |
+ kLSLaunchDontAddToRecents |
+ kLSLaunchDontSwitch;
+
+ char *external_editor = ::getenv ("LLDB_EXTERNAL_EDITOR");
+
+ if (external_editor)
+ {
+ if (log)
+ log->Printf("Looking for external editor \"%s\".\n", external_editor);
+
+ if (g_app_name.empty() || strcmp (g_app_name.c_str(), external_editor) != 0)
+ {
+ CFCString editor_name (external_editor, kCFStringEncodingUTF8);
+ error = ::LSFindApplicationForInfo (kLSUnknownCreator,
+ NULL,
+ editor_name.get(),
+ &g_app_fsref,
+ NULL);
+
+ // If we found the app, then store away the name so we don't have to re-look it up.
+ if (error != noErr)
+ {
+ if (log)
+ log->Printf("Could not find External Editor application, error: %ld.\n", error);
+ return false;
+ }
+
+ }
+ app_params.application = &g_app_fsref;
+ }
+
+ ProcessSerialNumber psn;
+ CFCReleaser<CFArrayRef> file_array(CFArrayCreate (NULL, (const void **) file_URL.ptr_address(false), 1, NULL));
+ error = ::LSOpenURLsWithRole (file_array.get(),
+ kLSRolesAll,
+ &file_and_line_desc,
+ &app_params,
+ &psn,
+ 1);
+
+ AEDisposeDesc (&(file_and_line_desc.descContent));
+
+ if (error != noErr)
+ {
+ if (log)
+ log->Printf("LSOpenURLsWithRole failed, error: %ld.\n", error);
+
+ return false;
+ }
+
+ return true;
+#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
+}
+
+size_t
+Host::GetEnvironment (StringList &env)
+{
+ char **host_env = *_NSGetEnviron();
+ char *env_entry;
+ size_t i;
+ for (i=0; (env_entry = host_env[i]) != NULL; ++i)
+ env.AppendString(env_entry);
+ return i;
+
+}
+
+static bool
+GetMacOSXProcessCPUType (ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid())
+ {
+ // Make a new mib to stay thread safe
+ int mib[CTL_MAXNAME]={0,};
+ size_t mib_len = CTL_MAXNAME;
+ if (::sysctlnametomib("sysctl.proc_cputype", mib, &mib_len))
+ return false;
+
+ mib[mib_len] = process_info.GetProcessID();
+ mib_len++;
+
+ cpu_type_t cpu, sub = 0;
+ size_t len = sizeof(cpu);
+ if (::sysctl (mib, mib_len, &cpu, &len, 0, 0) == 0)
+ {
+ switch (cpu)
+ {
+ case CPU_TYPE_I386: sub = CPU_SUBTYPE_I386_ALL; break;
+ case CPU_TYPE_X86_64: sub = CPU_SUBTYPE_X86_64_ALL; break;
+
+#if defined (CPU_TYPE_ARM64) && defined (CPU_SUBTYPE_ARM64_ALL)
+ case CPU_TYPE_ARM64: sub = CPU_SUBTYPE_ARM64_ALL; break;
+#endif
+
+ case CPU_TYPE_ARM:
+ {
+ // Note that we fetched the cpu type from the PROCESS but we can't get a cpusubtype of the
+ // process -- we can only get the host's cpu subtype.
+ uint32_t cpusubtype = 0;
+ len = sizeof(cpusubtype);
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
+ sub = cpusubtype;
+
+ bool host_cpu_is_64bit;
+ uint32_t is64bit_capable;
+ size_t is64bit_capable_len = sizeof (is64bit_capable);
+ if (sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, &is64bit_capable_len, NULL, 0) == 0)
+ host_cpu_is_64bit = true;
+ else
+ host_cpu_is_64bit = false;
+
+ // if the host is an armv8 device, its cpusubtype will be in CPU_SUBTYPE_ARM64 numbering
+ // and we need to rewrite it to a reasonable CPU_SUBTYPE_ARM value instead.
+
+ if (host_cpu_is_64bit)
+ {
+ sub = CPU_SUBTYPE_ARM_V7;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ process_info.GetArchitecture ().SetArchitecture (eArchTypeMachO, cpu, sub);
+ return true;
+ }
+ }
+ process_info.GetArchitecture().Clear();
+ return false;
+}
+
+static bool
+GetMacOSXProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
+ ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid())
+ {
+ int proc_args_mib[3] = { CTL_KERN, KERN_PROCARGS2, (int)process_info.GetProcessID() };
+
+ size_t arg_data_size = 0;
+ if (::sysctl (proc_args_mib, 3, nullptr, &arg_data_size, NULL, 0) || arg_data_size == 0)
+ arg_data_size = 8192;
+
+ // Add a few bytes to the calculated length, I know we need to add at least one byte
+ // to this number otherwise we get junk back, so add 128 just in case...
+ DataBufferHeap arg_data(arg_data_size+128, 0);
+ arg_data_size = arg_data.GetByteSize();
+ if (::sysctl (proc_args_mib, 3, arg_data.GetBytes(), &arg_data_size , NULL, 0) == 0)
+ {
+ DataExtractor data (arg_data.GetBytes(), arg_data_size, endian::InlHostByteOrder(), sizeof(void *));
+ lldb::offset_t offset = 0;
+ uint32_t argc = data.GetU32 (&offset);
+ llvm::Triple &triple = process_info.GetArchitecture().GetTriple();
+ const llvm::Triple::ArchType triple_arch = triple.getArch();
+ const bool check_for_ios_simulator = (triple_arch == llvm::Triple::x86 || triple_arch == llvm::Triple::x86_64);
+ const char *cstr = data.GetCStr (&offset);
+ if (cstr)
+ {
+ process_info.GetExecutableFile().SetFile(cstr, false);
+
+ if (match_info_ptr == NULL ||
+ NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
+ match_info_ptr->GetNameMatchType(),
+ match_info_ptr->GetProcessInfo().GetName()))
+ {
+ // Skip NULLs
+ while (1)
+ {
+ const uint8_t *p = data.PeekData(offset, 1);
+ if ((p == NULL) || (*p != '\0'))
+ break;
+ ++offset;
+ }
+ // Now extract all arguments
+ Args &proc_args = process_info.GetArguments();
+ for (int i=0; i<static_cast<int>(argc); ++i)
+ {
+ cstr = data.GetCStr(&offset);
+ if (cstr)
+ proc_args.AppendArgument(cstr);
+ }
+
+ Args &proc_env = process_info.GetEnvironmentEntries ();
+ while ((cstr = data.GetCStr(&offset)))
+ {
+ if (cstr[0] == '\0')
+ break;
+
+ if (check_for_ios_simulator)
+ {
+ if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == 0)
+ process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::IOS);
+ else
+ process_info.GetArchitecture().GetTriple().setOS(llvm::Triple::MacOSX);
+ }
+
+ proc_env.AppendArgument(cstr);
+ }
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+GetMacOSXProcessUserAndGroup (ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid())
+ {
+ int mib[4];
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = process_info.GetProcessID();
+ struct kinfo_proc proc_kinfo;
+ size_t proc_kinfo_size = sizeof(struct kinfo_proc);
+
+ if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
+ {
+ if (proc_kinfo_size > 0)
+ {
+ process_info.SetParentProcessID (proc_kinfo.kp_eproc.e_ppid);
+ process_info.SetUserID (proc_kinfo.kp_eproc.e_pcred.p_ruid);
+ process_info.SetGroupID (proc_kinfo.kp_eproc.e_pcred.p_rgid);
+ process_info.SetEffectiveUserID (proc_kinfo.kp_eproc.e_ucred.cr_uid);
+ if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
+ process_info.SetEffectiveGroupID (proc_kinfo.kp_eproc.e_ucred.cr_groups[0]);
+ else
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+ return true;
+ }
+ }
+ }
+ process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
+ process_info.SetUserID (UINT32_MAX);
+ process_info.SetGroupID (UINT32_MAX);
+ process_info.SetEffectiveUserID (UINT32_MAX);
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+ return false;
+}
+
+
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ std::vector<struct kinfo_proc> kinfos;
+
+ int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
+
+ size_t pid_data_size = 0;
+ if (::sysctl (mib, 4, NULL, &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ // Add a few extra in case a few more show up
+ const size_t estimated_pid_count = (pid_data_size / sizeof(struct kinfo_proc)) + 10;
+
+ kinfos.resize (estimated_pid_count);
+ pid_data_size = kinfos.size() * sizeof(struct kinfo_proc);
+
+ if (::sysctl (mib, 4, &kinfos[0], &pid_data_size, NULL, 0) != 0)
+ return 0;
+
+ const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc));
+
+ bool all_users = match_info.GetMatchAllUsers();
+ const lldb::pid_t our_pid = getpid();
+ const uid_t our_uid = getuid();
+ for (size_t i = 0; i < actual_pid_count; i++)
+ {
+ const struct kinfo_proc &kinfo = kinfos[i];
+
+ bool kinfo_user_matches = false;
+ if (all_users)
+ kinfo_user_matches = true;
+ else
+ kinfo_user_matches = kinfo.kp_eproc.e_pcred.p_ruid == our_uid;
+
+ // Special case, if lldb is being run as root we can attach to anything.
+ if (our_uid == 0)
+ kinfo_user_matches = true;
+
+ if (kinfo_user_matches == false || // Make sure the user is acceptable
+ static_cast<lldb::pid_t>(kinfo.kp_proc.p_pid) == our_pid || // Skip this process
+ kinfo.kp_proc.p_pid == 0 || // Skip kernel (kernel pid is zero)
+ kinfo.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains...
+ kinfo.kp_proc.p_flag & P_TRACED || // Being debugged?
+ kinfo.kp_proc.p_flag & P_WEXIT || // Working on exiting?
+ kinfo.kp_proc.p_flag & P_TRANSLATED) // Skip translated ppc (Rosetta)
+ continue;
+
+ ProcessInstanceInfo process_info;
+ process_info.SetProcessID (kinfo.kp_proc.p_pid);
+ process_info.SetParentProcessID (kinfo.kp_eproc.e_ppid);
+ process_info.SetUserID (kinfo.kp_eproc.e_pcred.p_ruid);
+ process_info.SetGroupID (kinfo.kp_eproc.e_pcred.p_rgid);
+ process_info.SetEffectiveUserID (kinfo.kp_eproc.e_ucred.cr_uid);
+ if (kinfo.kp_eproc.e_ucred.cr_ngroups > 0)
+ process_info.SetEffectiveGroupID (kinfo.kp_eproc.e_ucred.cr_groups[0]);
+ else
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+
+ // Make sure our info matches before we go fetch the name and cpu type
+ if (match_info.Matches (process_info))
+ {
+ // Get CPU type first so we can know to look for iOS simulator is we have x86 or x86_64
+ if (GetMacOSXProcessCPUType (process_info))
+ {
+ if (GetMacOSXProcessArgs (&match_info, process_info))
+ {
+ if (match_info.Matches (process_info))
+ process_infos.Append (process_info);
+ }
+ }
+ }
+ }
+ return process_infos.GetSize();
+}
+
+bool
+Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.SetProcessID(pid);
+ bool success = false;
+
+ // Get CPU type first so we can know to look for iOS simulator is we have x86 or x86_64
+ if (GetMacOSXProcessCPUType (process_info))
+ success = true;
+
+ if (GetMacOSXProcessArgs (NULL, process_info))
+ success = true;
+
+ if (GetMacOSXProcessUserAndGroup (process_info))
+ success = true;
+
+ if (success)
+ return true;
+
+ process_info.Clear();
+ return false;
+}
+
+#if !NO_XPC_SERVICES
+static void
+PackageXPCArguments (xpc_object_t message, const char *prefix, const Args& args)
+{
+ size_t count = args.GetArgumentCount();
+ char buf[50]; // long enough for 'argXXX'
+ memset(buf, 0, 50);
+ sprintf(buf, "%sCount", prefix);
+ xpc_dictionary_set_int64(message, buf, count);
+ for (size_t i=0; i<count; i++) {
+ memset(buf, 0, 50);
+ sprintf(buf, "%s%zi", prefix, i);
+ xpc_dictionary_set_string(message, buf, args.GetArgumentAtIndex(i));
+ }
+}
+
+/*
+ A valid authorizationRef means that
+ - there is the LaunchUsingXPCRightName rights in the /etc/authorization
+ - we have successfully copied the rights to be send over the XPC wire
+ Once obtained, it will be valid for as long as the process lives.
+ */
+static AuthorizationRef authorizationRef = NULL;
+static Error
+getXPCAuthorization (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+ if ((launch_info.GetUserID() == 0) && !authorizationRef)
+ {
+ OSStatus createStatus = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef);
+ if (createStatus != errAuthorizationSuccess)
+ {
+ error.SetError(1, eErrorTypeGeneric);
+ error.SetErrorString("Can't create authorizationRef.");
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+ return error;
+ }
+
+ OSStatus rightsStatus = AuthorizationRightGet(LaunchUsingXPCRightName, NULL);
+ if (rightsStatus != errAuthorizationSuccess)
+ {
+ // No rights in the security database, Create it with the right prompt.
+ CFStringRef prompt = CFSTR("Xcode is trying to take control of a root process.");
+ CFStringRef keys[] = { CFSTR("en") };
+ CFTypeRef values[] = { prompt };
+ CFDictionaryRef promptDict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+ CFStringRef keys1[] = { CFSTR("class"), CFSTR("group"), CFSTR("comment"), CFSTR("default-prompt"), CFSTR("shared") };
+ CFTypeRef values1[] = { CFSTR("user"), CFSTR("admin"), CFSTR(LaunchUsingXPCRightName), promptDict, kCFBooleanFalse };
+ CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys1, (const void **)values1, 5, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ rightsStatus = AuthorizationRightSet(authorizationRef, LaunchUsingXPCRightName, dict, NULL, NULL, NULL);
+ CFRelease(promptDict);
+ CFRelease(dict);
+ }
+
+ OSStatus copyRightStatus = errAuthorizationDenied;
+ if (rightsStatus == errAuthorizationSuccess)
+ {
+ AuthorizationItem item1 = { LaunchUsingXPCRightName, 0, NULL, 0 };
+ AuthorizationItem items[] = {item1};
+ AuthorizationRights requestedRights = {1, items };
+ AuthorizationFlags authorizationFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
+ copyRightStatus = AuthorizationCopyRights(authorizationRef, &requestedRights, kAuthorizationEmptyEnvironment, authorizationFlags, NULL);
+ }
+
+ if (copyRightStatus != errAuthorizationSuccess)
+ {
+ // Eventually when the commandline supports running as root and the user is not
+ // logged in in the current audit session, we will need the trick in gdb where
+ // we ask the user to type in the root passwd in the terminal.
+ error.SetError(2, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Launching as root needs root authorization.");
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+
+ if (authorizationRef)
+ {
+ AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
+ authorizationRef = NULL;
+ }
+ }
+ }
+
+ return error;
+}
+#endif
+
+static Error
+LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid)
+{
+#if !NO_XPC_SERVICES
+ Error error = getXPCAuthorization(launch_info);
+ if (error.Fail())
+ return error;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+ uid_t requested_uid = launch_info.GetUserID();
+ const char *xpc_service = nil;
+ bool send_auth = false;
+ AuthorizationExternalForm extForm;
+ if (requested_uid == 0)
+ {
+ if (AuthorizationMakeExternalForm(authorizationRef, &extForm) == errAuthorizationSuccess)
+ {
+ send_auth = true;
+ }
+ else
+ {
+ error.SetError(3, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Launching root via XPC needs to externalize authorization reference.");
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+ return error;
+ }
+ xpc_service = LaunchUsingXPCRightName;
+ }
+ else
+ {
+ error.SetError(4, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Launching via XPC is only currently available for root.");
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+ return error;
+ }
+
+ xpc_connection_t conn = xpc_connection_create(xpc_service, NULL);
+
+ xpc_connection_set_event_handler(conn, ^(xpc_object_t event) {
+ xpc_type_t type = xpc_get_type(event);
+
+ if (type == XPC_TYPE_ERROR) {
+ if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
+ // The service has either canceled itself, crashed, or been terminated.
+ // The XPC connection is still valid and sending a message to it will re-launch the service.
+ // If the service is state-full, this is the time to initialize the new service.
+ return;
+ } else if (event == XPC_ERROR_CONNECTION_INVALID) {
+ // The service is invalid. Either the service name supplied to xpc_connection_create() is incorrect
+ // or we (this process) have canceled the service; we can do any cleanup of application state at this point.
+ // printf("Service disconnected");
+ return;
+ } else {
+ // printf("Unexpected error from service: %s", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
+ }
+
+ } else {
+ // printf("Received unexpected event in handler");
+ }
+ });
+
+ xpc_connection_set_finalizer_f (conn, xpc_finalizer_t(xpc_release));
+ xpc_connection_resume (conn);
+ xpc_object_t message = xpc_dictionary_create (nil, nil, 0);
+
+ if (send_auth)
+ {
+ xpc_dictionary_set_data(message, LauncherXPCServiceAuthKey, extForm.bytes, sizeof(AuthorizationExternalForm));
+ }
+
+ PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey, launch_info.GetArguments());
+ PackageXPCArguments(message, LauncherXPCServiceEnvPrefxKey, launch_info.GetEnvironmentEntries());
+
+ // Posix spawn stuff.
+ xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey, launch_info.GetArchitecture().GetMachOCPUType());
+ xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey, Host::GetPosixspawnFlags(launch_info));
+ const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
+ if (file_action && file_action->GetPath())
+ {
+ xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey, file_action->GetPath());
+ }
+ file_action = launch_info.GetFileActionForFD(STDOUT_FILENO);
+ if (file_action && file_action->GetPath())
+ {
+ xpc_dictionary_set_string(message, LauncherXPCServiceStdOutPathKeyKey, file_action->GetPath());
+ }
+ file_action = launch_info.GetFileActionForFD(STDERR_FILENO);
+ if (file_action && file_action->GetPath())
+ {
+ xpc_dictionary_set_string(message, LauncherXPCServiceStdErrPathKeyKey, file_action->GetPath());
+ }
+
+ xpc_object_t reply = xpc_connection_send_message_with_reply_sync(conn, message);
+ xpc_type_t returnType = xpc_get_type(reply);
+ if (returnType == XPC_TYPE_DICTIONARY)
+ {
+ pid = xpc_dictionary_get_int64(reply, LauncherXPCServiceChildPIDKey);
+ if (pid == 0)
+ {
+ int errorType = xpc_dictionary_get_int64(reply, LauncherXPCServiceErrorTypeKey);
+ int errorCode = xpc_dictionary_get_int64(reply, LauncherXPCServiceCodeTypeKey);
+
+ error.SetError(errorCode, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Problems with launching via XPC. Error type : %i, code : %i", errorType, errorCode);
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+
+ if (authorizationRef)
+ {
+ AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults);
+ authorizationRef = NULL;
+ }
+ }
+ }
+ else if (returnType == XPC_TYPE_ERROR)
+ {
+ error.SetError(5, eErrorTypeGeneric);
+ error.SetErrorStringWithFormat("Problems with launching via XPC. XPC error : %s", xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION));
+ if (log)
+ {
+ error.PutToLog(log, "%s", error.AsCString());
+ }
+ }
+
+ return error;
+#else
+ Error error;
+ return error;
+#endif
+}
+
+static bool
+ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info)
+{
+ bool result = false;
+
+#if !NO_XPC_SERVICES
+ bool launchingAsRoot = launch_info.GetUserID() == 0;
+ bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0;
+
+ if (launchingAsRoot && !currentUserIsRoot)
+ {
+ // If current user is already root, we don't need XPC's help.
+ result = true;
+ }
+#endif
+
+ return result;
+}
+
+Error
+Host::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ char exe_path[PATH_MAX];
+ PlatformSP host_platform_sp (Platform::GetHostPlatform ());
+
+ ModuleSpec exe_module_spec(launch_info.GetExecutableFile(), launch_info.GetArchitecture());
+
+ FileSpec::FileType file_type = exe_module_spec.GetFileSpec().GetFileType();
+ if (file_type != FileSpec::eFileTypeRegular)
+ {
+ lldb::ModuleSP exe_module_sp;
+ error = host_platform_sp->ResolveExecutable (exe_module_spec,
+ exe_module_sp,
+ NULL);
+
+ if (error.Fail())
+ return error;
+
+ if (exe_module_sp)
+ exe_module_spec.GetFileSpec() = exe_module_sp->GetFileSpec();
+ }
+
+ if (exe_module_spec.GetFileSpec().Exists())
+ {
+ exe_module_spec.GetFileSpec().GetPath (exe_path, sizeof(exe_path));
+ }
+ else
+ {
+ launch_info.GetExecutableFile().GetPath (exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat ("executable doesn't exist: '%s'", exe_path);
+ return error;
+ }
+
+ if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
+ {
+#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
+ return LaunchInNewTerminalWithAppleScript (exe_path, launch_info);
+#else
+ error.SetErrorString ("launching a process in a new terminal is not supported on iOS devices");
+ return error;
+#endif
+ }
+
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ if (ShouldLaunchUsingXPC(launch_info))
+ {
+ error = LaunchProcessXPC(exe_path, launch_info, pid);
+ }
+ else
+ {
+ error = LaunchProcessPosixSpawn(exe_path, launch_info, pid);
+ }
+
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // If all went well, then set the process ID into the launch info
+ launch_info.SetProcessID(pid);
+
+ // Make sure we reap any processes we spawn or we will have zombies.
+ if (!launch_info.MonitorProcess())
+ {
+ const bool monitor_signals = false;
+ Host::MonitorChildProcessCallback callback = nullptr;
+
+ if (!launch_info.GetFlags().Test(lldb::eLaunchFlagDontSetExitStatus))
+ callback = Process::SetProcessExitStatus;
+
+ StartMonitoringChildProcess (callback,
+ NULL,
+ pid,
+ monitor_signals);
+ }
+ }
+ else
+ {
+ // Invalid process ID, something didn't go well
+ if (error.Success())
+ error.SetErrorString ("process launch failed for unknown reasons");
+ }
+ return error;
+}
+
+Error
+Host::ShellExpandArguments (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments))
+ {
+ FileSpec expand_tool_spec;
+ if (!HostInfo::GetLLDBPath(lldb::ePathTypeSupportExecutableDir, expand_tool_spec))
+ {
+ error.SetErrorString("could not get support executable directory for lldb-argdumper tool");
+ return error;
+ }
+ expand_tool_spec.AppendPathComponent("lldb-argdumper");
+ if (!expand_tool_spec.Exists())
+ {
+ error.SetErrorStringWithFormat("could not find the lldb-argdumper tool: %s", expand_tool_spec.GetPath().c_str());
+ return error;
+ }
+
+ StreamString expand_tool_spec_stream;
+ expand_tool_spec_stream.Printf("\"%s\"",expand_tool_spec.GetPath().c_str());
+
+ Args expand_command(expand_tool_spec_stream.GetData());
+ expand_command.AppendArguments (launch_info.GetArguments());
+
+ int status;
+ std::string output;
+ FileSpec cwd(launch_info.GetWorkingDirectory());
+ if (!cwd.Exists())
+ {
+ char *wd = getcwd(nullptr, 0);
+ if (wd == nullptr)
+ {
+ error.SetErrorStringWithFormat("cwd does not exist; cannot launch with shell argument expansion");
+ return error;
+ }
+ else
+ {
+ FileSpec working_dir(wd, false);
+ free(wd);
+ launch_info.SetWorkingDirectory(working_dir);
+
+ }
+ }
+ RunShellCommand(expand_command, cwd, &status, nullptr, &output, 10);
+
+ if (status != 0)
+ {
+ error.SetErrorStringWithFormat("lldb-argdumper exited with error %d", status);
+ return error;
+ }
+
+ auto data_sp = StructuredData::ParseJSON(output);
+ if (!data_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto dict_sp = data_sp->GetAsDictionary();
+ if (!data_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto args_sp = dict_sp->GetObjectForDotSeparatedPath("arguments");
+ if (!args_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ auto args_array_sp = args_sp->GetAsArray();
+ if (!args_array_sp)
+ {
+ error.SetErrorString("invalid JSON");
+ return error;
+ }
+
+ launch_info.GetArguments().Clear();
+
+ for (size_t i = 0;
+ i < args_array_sp->GetSize();
+ i++)
+ {
+ auto item_sp = args_array_sp->GetItemAtIndex(i);
+ if (!item_sp)
+ continue;
+ auto str_sp = item_sp->GetAsString();
+ if (!str_sp)
+ continue;
+
+ launch_info.GetArguments().AppendArgument(str_sp->GetValue().c_str());
+ }
+ }
+
+ return error;
+}
+
+HostThread
+Host::StartMonitoringChildProcess(Host::MonitorChildProcessCallback callback, void *callback_baton, lldb::pid_t pid, bool monitor_signals)
+{
+ unsigned long mask = DISPATCH_PROC_EXIT;
+ if (monitor_signals)
+ mask |= DISPATCH_PROC_SIGNAL;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_HOST | LIBLLDB_LOG_PROCESS));
+
+
+ dispatch_source_t source = ::dispatch_source_create (DISPATCH_SOURCE_TYPE_PROC,
+ pid,
+ mask,
+ ::dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT,0));
+
+ if (log)
+ log->Printf ("Host::StartMonitoringChildProcess (callback=%p, baton=%p, pid=%i, monitor_signals=%i) source = %p\n",
+ callback,
+ callback_baton,
+ (int)pid,
+ monitor_signals,
+ source);
+
+ if (source)
+ {
+ ::dispatch_source_set_cancel_handler (source, ^{
+ ::dispatch_release (source);
+ });
+ ::dispatch_source_set_event_handler (source, ^{
+
+ int status= 0;
+ int wait_pid = 0;
+ bool cancel = false;
+ bool exited = false;
+ do
+ {
+ wait_pid = ::waitpid (pid, &status, 0);
+ } while (wait_pid < 0 && errno == EINTR);
+
+ if (wait_pid >= 0)
+ {
+ int signal = 0;
+ int exit_status = 0;
+ const char *status_cstr = NULL;
+ if (WIFSTOPPED(status))
+ {
+ signal = WSTOPSIG(status);
+ status_cstr = "STOPPED";
+ }
+ else if (WIFEXITED(status))
+ {
+ exit_status = WEXITSTATUS(status);
+ status_cstr = "EXITED";
+ exited = true;
+ }
+ else if (WIFSIGNALED(status))
+ {
+ signal = WTERMSIG(status);
+ status_cstr = "SIGNALED";
+ exited = true;
+ exit_status = -1;
+ }
+ else
+ {
+ status_cstr = "???";
+ }
+
+ if (log)
+ log->Printf ("::waitpid (pid = %llu, &status, 0) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_status = %i",
+ pid,
+ wait_pid,
+ status,
+ status_cstr,
+ signal,
+ exit_status);
+
+ if (callback)
+ cancel = callback (callback_baton, pid, exited, signal, exit_status);
+
+ if (exited || cancel)
+ {
+ ::dispatch_source_cancel(source);
+ }
+ }
+ });
+
+ ::dispatch_resume (source);
+ }
+ return HostThread();
+}
+
+//----------------------------------------------------------------------
+// Log to both stderr and to ASL Logging when running on MacOSX.
+//----------------------------------------------------------------------
+void
+Host::SystemLog (SystemLogType type, const char *format, va_list args)
+{
+ if (format && format[0])
+ {
+ static aslmsg g_aslmsg = NULL;
+ if (g_aslmsg == NULL)
+ {
+ g_aslmsg = ::asl_new (ASL_TYPE_MSG);
+ char asl_key_sender[PATH_MAX];
+ snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.LLDB.framework");
+ ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender);
+ }
+
+ // Copy the va_list so we can log this message twice
+ va_list copy_args;
+ va_copy (copy_args, args);
+ // Log to stderr
+ ::vfprintf (stderr, format, copy_args);
+ va_end (copy_args);
+
+ int asl_level;
+ switch (type)
+ {
+ case eSystemLogError:
+ asl_level = ASL_LEVEL_ERR;
+ break;
+
+ case eSystemLogWarning:
+ asl_level = ASL_LEVEL_WARNING;
+ break;
+ }
+
+ // Log to ASL
+ ::asl_vlog (NULL, g_aslmsg, asl_level, format, args);
+ }
+}
+
+lldb::DataBufferSP
+Host::GetAuxvData(lldb_private::Process *process)
+{
+ return lldb::DataBufferSP();
+}
diff --git a/source/Host/macosx/HostInfoMacOSX.mm b/source/Host/macosx/HostInfoMacOSX.mm
new file mode 100644
index 0000000000000..f5a0540e87749
--- /dev/null
+++ b/source/Host/macosx/HostInfoMacOSX.mm
@@ -0,0 +1,372 @@
+//===-- HostInfoMacOSX.mm ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if !defined(LLDB_DISABLE_PYTHON)
+#include "Plugins/ScriptInterpreter/Python/lldb-python.h"
+#endif
+
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/macosx/HostInfoMacOSX.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/SafeMachO.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
+
+// C++ Includes
+#include <string>
+
+// C inclues
+#include <stdlib.h>
+#include <sys/sysctl.h>
+#include <sys/syslimits.h>
+#include <sys/types.h>
+
+// Objective C/C++ includes
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+#include <mach-o/dyld.h>
+#include <objc/objc-auto.h>
+
+// These are needed when compiling on systems
+// that do not yet have these definitions
+#include <AvailabilityMacros.h>
+#ifndef CPU_SUBTYPE_X86_64_H
+#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8)
+#endif
+#ifndef CPU_TYPE_ARM64
+#define CPU_TYPE_ARM64 (CPU_TYPE_ARM|CPU_ARCH_ABI64)
+#endif
+
+#include <TargetConditionals.h> // for TARGET_OS_TV, TARGET_OS_WATCH
+
+using namespace lldb_private;
+
+bool
+HostInfoMacOSX::GetOSBuildString(std::string &s)
+{
+ int mib[2] = {CTL_KERN, KERN_OSVERSION};
+ char cstr[PATH_MAX];
+ size_t cstr_len = sizeof(cstr);
+ if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0)
+ {
+ s.assign(cstr, cstr_len);
+ return true;
+ }
+
+ s.clear();
+ return false;
+}
+
+bool
+HostInfoMacOSX::GetOSKernelDescription(std::string &s)
+{
+ int mib[2] = {CTL_KERN, KERN_VERSION};
+ char cstr[PATH_MAX];
+ size_t cstr_len = sizeof(cstr);
+ if (::sysctl(mib, 2, cstr, &cstr_len, NULL, 0) == 0)
+ {
+ s.assign(cstr, cstr_len);
+ return true;
+ }
+ s.clear();
+ return false;
+}
+
+bool
+HostInfoMacOSX::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update)
+{
+ static uint32_t g_major = 0;
+ static uint32_t g_minor = 0;
+ static uint32_t g_update = 0;
+
+ if (g_major == 0)
+ {
+ @autoreleasepool
+ {
+ NSDictionary *version_info = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"];
+ NSString *version_value = [version_info objectForKey:@"ProductVersion"];
+ const char *version_str = [version_value UTF8String];
+ if (version_str)
+ Args::StringToVersion(version_str, g_major, g_minor, g_update);
+ }
+ }
+
+ if (g_major != 0)
+ {
+ major = g_major;
+ minor = g_minor;
+ update = g_update;
+ return true;
+ }
+ return false;
+}
+
+FileSpec
+HostInfoMacOSX::GetProgramFileSpec()
+{
+ static FileSpec g_program_filespec;
+ if (!g_program_filespec)
+ {
+ char program_fullpath[PATH_MAX];
+ // If DST is NULL, then return the number of bytes needed.
+ uint32_t len = sizeof(program_fullpath);
+ int err = _NSGetExecutablePath(program_fullpath, &len);
+ if (err == 0)
+ g_program_filespec.SetFile(program_fullpath, false);
+ else if (err == -1)
+ {
+ char *large_program_fullpath = (char *)::malloc(len + 1);
+
+ err = _NSGetExecutablePath(large_program_fullpath, &len);
+ if (err == 0)
+ g_program_filespec.SetFile(large_program_fullpath, false);
+
+ ::free(large_program_fullpath);
+ }
+ }
+ return g_program_filespec;
+}
+
+bool
+HostInfoMacOSX::ComputeSupportExeDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos != std::string::npos)
+ {
+ framework_pos += strlen("LLDB.framework");
+#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ // Shallow bundle
+ raw_path.resize(framework_pos);
+#else
+ // Normal bundle
+ raw_path.resize(framework_pos);
+ raw_path.append("/Resources");
+#endif
+ }
+ else
+ {
+ // Find the bin path relative to the lib path where the cmake-based
+ // OS X .dylib lives. This is not going to work if the bin and lib
+ // dir are not both in the same dir.
+ //
+ // It is not going to work to do it by the executable path either,
+ // as in the case of a python script, the executable is python, not
+ // the lldb driver.
+ raw_path.append("/../bin");
+ FileSpec support_dir_spec(raw_path, true);
+ if (!support_dir_spec.Exists() || !support_dir_spec.IsDirectory())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log)
+ log->Printf("HostInfoMacOSX::%s(): failed to find support directory",
+ __FUNCTION__);
+ return false;
+ }
+
+ // Get normalization from support_dir_spec. Note the FileSpec resolve
+ // does not remove '..' in the path.
+ char *const dir_realpath = realpath(support_dir_spec.GetPath().c_str(), NULL);
+ if (dir_realpath)
+ {
+ raw_path = dir_realpath;
+ free(dir_realpath);
+ }
+ else
+ {
+ raw_path = support_dir_spec.GetPath();
+ }
+ }
+
+ file_spec.GetDirectory().SetString(llvm::StringRef(raw_path.c_str(), raw_path.size()));
+ return (bool)file_spec.GetDirectory();
+}
+
+bool
+HostInfoMacOSX::ComputeHeaderDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!HostInfo::GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos != std::string::npos)
+ {
+ framework_pos += strlen("LLDB.framework");
+ raw_path.resize(framework_pos);
+ raw_path.append("/Headers");
+ }
+ file_spec.GetDirectory().SetString(llvm::StringRef(raw_path.c_str(), raw_path.size()));
+ return true;
+}
+
+bool
+HostInfoMacOSX::ComputePythonDirectory(FileSpec &file_spec)
+{
+#ifndef LLDB_DISABLE_PYTHON
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos != std::string::npos)
+ {
+ framework_pos += strlen("LLDB.framework");
+ raw_path.resize(framework_pos);
+ raw_path.append("/Resources/Python");
+ }
+ else
+ {
+ llvm::SmallString<256> python_version_dir;
+ llvm::raw_svector_ostream os(python_version_dir);
+ os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages";
+
+ // We may get our string truncated. Should we protect this with an assert?
+ raw_path.append(python_version_dir.c_str());
+ }
+ file_spec.GetDirectory().SetString(llvm::StringRef(raw_path.c_str(), raw_path.size()));
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool
+HostInfoMacOSX::ComputeClangDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath (lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos != std::string::npos)
+ {
+ framework_pos += strlen("LLDB.framework");
+ raw_path.resize(framework_pos);
+ raw_path.append("/Resources/Clang");
+ }
+ file_spec.SetFile (raw_path.c_str(), true);
+ return true;
+}
+
+bool
+HostInfoMacOSX::ComputeSystemPluginsDirectory(FileSpec &file_spec)
+{
+ FileSpec lldb_file_spec;
+ if (!GetLLDBPath(lldb::ePathTypeLLDBShlibDir, lldb_file_spec))
+ return false;
+
+ std::string raw_path = lldb_file_spec.GetPath();
+
+ size_t framework_pos = raw_path.find("LLDB.framework");
+ if (framework_pos == std::string::npos)
+ return false;
+
+ framework_pos += strlen("LLDB.framework");
+ raw_path.resize(framework_pos);
+ raw_path.append("/Resources/PlugIns");
+ file_spec.GetDirectory().SetString(llvm::StringRef(raw_path.c_str(), raw_path.size()));
+ return true;
+}
+
+bool
+HostInfoMacOSX::ComputeUserPluginsDirectory(FileSpec &file_spec)
+{
+ FileSpec temp_file("~/Library/Application Support/LLDB/PlugIns", true);
+ file_spec.GetDirectory().SetCString(temp_file.GetPath().c_str());
+ return true;
+}
+
+void
+HostInfoMacOSX::ComputeHostArchitectureSupport(ArchSpec &arch_32, ArchSpec &arch_64)
+{
+ // All apple systems support 32 bit execution.
+ uint32_t cputype, cpusubtype;
+ uint32_t is_64_bit_capable = false;
+ size_t len = sizeof(cputype);
+ ArchSpec host_arch;
+ // These will tell us about the kernel architecture, which even on a 64
+ // bit machine can be 32 bit...
+ if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0)
+ {
+ len = sizeof(cpusubtype);
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0)
+ cpusubtype = CPU_TYPE_ANY;
+
+ len = sizeof(is_64_bit_capable);
+ ::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0);
+
+ if (is_64_bit_capable)
+ {
+ if (cputype & CPU_ARCH_ABI64)
+ {
+ // We have a 64 bit kernel on a 64 bit system
+ arch_64.SetArchitecture(eArchTypeMachO, cputype, cpusubtype);
+ }
+ else
+ {
+ // We have a 64 bit kernel that is returning a 32 bit cputype, the
+ // cpusubtype will be correct as if it were for a 64 bit architecture
+ arch_64.SetArchitecture(eArchTypeMachO, cputype | CPU_ARCH_ABI64, cpusubtype);
+ }
+
+ // Now we need modify the cpusubtype for the 32 bit slices.
+ uint32_t cpusubtype32 = cpusubtype;
+#if defined(__i386__) || defined(__x86_64__)
+ if (cpusubtype == CPU_SUBTYPE_486 || cpusubtype == CPU_SUBTYPE_X86_64_H)
+ cpusubtype32 = CPU_SUBTYPE_I386_ALL;
+#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
+ if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
+ cpusubtype32 = CPU_SUBTYPE_ARM_V7S;
+#endif
+ arch_32.SetArchitecture(eArchTypeMachO, cputype & ~(CPU_ARCH_MASK), cpusubtype32);
+
+ if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64)
+ {
+ // When running on a watch or tv, report the host os correctly
+#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1
+ arch_32.GetTriple().setOS(llvm::Triple::TvOS);
+ arch_64.GetTriple().setOS(llvm::Triple::TvOS);
+#else
+ arch_32.GetTriple().setOS(llvm::Triple::IOS);
+ arch_64.GetTriple().setOS(llvm::Triple::IOS);
+#endif
+ }
+ else
+ {
+ arch_32.GetTriple().setOS(llvm::Triple::MacOSX);
+ arch_64.GetTriple().setOS(llvm::Triple::MacOSX);
+ }
+ }
+ else
+ {
+ // We have a 32 bit kernel on a 32 bit system
+ arch_32.SetArchitecture(eArchTypeMachO, cputype, cpusubtype);
+#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1
+ arch_32.GetTriple().setOS(llvm::Triple::WatchOS);
+#else
+ arch_32.GetTriple().setOS(llvm::Triple::IOS);
+#endif
+ arch_64.Clear();
+ }
+ }
+}
diff --git a/source/Host/macosx/HostThreadMacOSX.mm b/source/Host/macosx/HostThreadMacOSX.mm
new file mode 100644
index 0000000000000..c84a78efd9e6c
--- /dev/null
+++ b/source/Host/macosx/HostThreadMacOSX.mm
@@ -0,0 +1,102 @@
+//===-- HostThreadMacOSX.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/macosx/HostThreadMacOSX.h"
+#include "lldb/Host/Host.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+
+#include <objc/objc-auto.h>
+#include <pthread.h>
+
+using namespace lldb_private;
+
+namespace
+{
+
+pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
+pthread_key_t g_thread_create_key = 0;
+
+class MacOSXDarwinThread
+{
+ public:
+ MacOSXDarwinThread()
+ : m_pool(nil)
+ {
+ // Register our thread with the collector if garbage collection is enabled.
+ if (objc_collectingEnabled())
+ {
+#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
+ // On Leopard and earlier there is no way objc_registerThreadWithCollector
+ // function, so we do it manually.
+ auto_zone_register_thread(auto_zone());
+#else
+ // On SnowLeopard and later we just call the thread registration function.
+ objc_registerThreadWithCollector();
+#endif
+ }
+ else
+ {
+ m_pool = [[NSAutoreleasePool alloc] init];
+ }
+ }
+
+ ~MacOSXDarwinThread()
+ {
+ if (m_pool)
+ {
+ [m_pool drain];
+ m_pool = nil;
+ }
+ }
+
+ static void
+ PThreadDestructor(void *v)
+ {
+ if (v)
+ delete static_cast<MacOSXDarwinThread *>(v);
+ ::pthread_setspecific(g_thread_create_key, NULL);
+ }
+
+ protected:
+ NSAutoreleasePool *m_pool;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MacOSXDarwinThread);
+};
+
+void
+InitThreadCreated()
+{
+ ::pthread_key_create(&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor);
+}
+} // namespace
+
+HostThreadMacOSX::HostThreadMacOSX()
+ : HostThreadPosix()
+{
+}
+
+HostThreadMacOSX::HostThreadMacOSX(lldb::thread_t thread)
+ : HostThreadPosix(thread)
+{
+}
+
+lldb::thread_result_t
+HostThreadMacOSX::ThreadCreateTrampoline(lldb::thread_arg_t arg)
+{
+ ::pthread_once(&g_thread_create_once, InitThreadCreated);
+ if (g_thread_create_key)
+ {
+ ::pthread_setspecific(g_thread_create_key, new MacOSXDarwinThread());
+ }
+
+ return HostThreadPosix::ThreadCreateTrampoline(arg);
+}
diff --git a/source/Host/macosx/Symbols.cpp b/source/Host/macosx/Symbols.cpp
new file mode 100644
index 0000000000000..f6a18febe6da9
--- /dev/null
+++ b/source/Host/macosx/Symbols.cpp
@@ -0,0 +1,559 @@
+//===-- Symbols.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Symbols.h"
+
+// C Includes
+#include <dirent.h>
+#include <pwd.h>
+#include "lldb/Utility/SafeMachO.h"
+
+// C++ Includes
+// Other libraries and framework includes
+#include <CoreFoundation/CoreFoundation.h>
+
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Utility/CleanUp.h"
+#include "Host/macosx/cfcpp/CFCBundle.h"
+#include "Host/macosx/cfcpp/CFCData.h"
+#include "Host/macosx/cfcpp/CFCReleaser.h"
+#include "Host/macosx/cfcpp/CFCString.h"
+#include "mach/machine.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm::MachO;
+
+#if !defined (__arm__) && !defined (__arm64__) && !defined (__aarch64__) // No DebugSymbols on the iOS devices
+extern "C" {
+
+CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url);
+CFDictionaryRef DBGCopyDSYMPropertyLists (CFURLRef dsym_url);
+
+}
+#endif
+
+int
+LocateMacOSXFilesUsingDebugSymbols
+(
+ const ModuleSpec &module_spec,
+ ModuleSpec &return_module_spec
+)
+{
+ return_module_spec = module_spec;
+ return_module_spec.GetFileSpec().Clear();
+ return_module_spec.GetSymbolFileSpec().Clear();
+
+ int items_found = 0;
+
+#if !defined (__arm__) && !defined (__arm64__) && !defined (__aarch64__) // No DebugSymbols on the iOS devices
+
+ const UUID *uuid = module_spec.GetUUIDPtr();
+ const ArchSpec *arch = module_spec.GetArchitecturePtr();
+
+ if (uuid && uuid->IsValid())
+ {
+ // Try and locate the dSYM file using DebugSymbols first
+ const UInt8 *module_uuid = (const UInt8 *)uuid->GetBytes();
+ if (module_uuid != NULL)
+ {
+ CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes (NULL,
+ module_uuid[0],
+ module_uuid[1],
+ module_uuid[2],
+ module_uuid[3],
+ module_uuid[4],
+ module_uuid[5],
+ module_uuid[6],
+ module_uuid[7],
+ module_uuid[8],
+ module_uuid[9],
+ module_uuid[10],
+ module_uuid[11],
+ module_uuid[12],
+ module_uuid[13],
+ module_uuid[14],
+ module_uuid[15]));
+
+ if (module_uuid_ref.get())
+ {
+ CFCReleaser<CFURLRef> exec_url;
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (exec_fspec)
+ {
+ char exec_cf_path[PATH_MAX];
+ if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
+ exec_url.reset(::CFURLCreateFromFileSystemRepresentation (NULL,
+ (const UInt8 *)exec_cf_path,
+ strlen(exec_cf_path),
+ FALSE));
+ }
+
+ CFCReleaser<CFURLRef> dsym_url (::DBGCopyFullDSYMURLForUUID(module_uuid_ref.get(), exec_url.get()));
+ char path[PATH_MAX];
+
+ if (dsym_url.get())
+ {
+ if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
+ {
+ if (log)
+ {
+ log->Printf ("DebugSymbols framework returned dSYM path of %s for UUID %s -- looking for the dSYM", path, uuid->GetAsString().c_str());
+ }
+ FileSpec dsym_filespec(path, path[0] == '~');
+
+ if (dsym_filespec.GetFileType () == FileSpec::eFileTypeDirectory)
+ {
+ dsym_filespec = Symbols::FindSymbolFileInBundle (dsym_filespec, uuid, arch);
+ ++items_found;
+ }
+ else
+ {
+ ++items_found;
+ }
+ return_module_spec.GetSymbolFileSpec() = dsym_filespec;
+ }
+
+ bool success = false;
+ if (log)
+ {
+ if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
+ {
+ log->Printf ("DebugSymbols framework returned dSYM path of %s for UUID %s -- looking for an exec file", path, uuid->GetAsString().c_str());
+ }
+
+ }
+
+ CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get()));
+ CFDictionaryRef uuid_dict = NULL;
+ if (dict.get())
+ {
+ CFCString uuid_cfstr (uuid->GetAsString().c_str());
+ uuid_dict = static_cast<CFDictionaryRef>(::CFDictionaryGetValue (dict.get(), uuid_cfstr.get()));
+ }
+ if (uuid_dict)
+ {
+ CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (uuid_dict, CFSTR("DBGSymbolRichExecutable")));
+ if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path)))
+ {
+ if (log)
+ {
+ log->Printf ("plist bundle has exec path of %s for UUID %s", path, uuid->GetAsString().c_str());
+ }
+ ++items_found;
+ FileSpec exec_filespec (path, path[0] == '~');
+ if (exec_filespec.Exists())
+ {
+ success = true;
+ return_module_spec.GetFileSpec() = exec_filespec;
+ }
+ }
+ }
+
+ if (!success)
+ {
+ // No dictionary, check near the dSYM bundle for an executable that matches...
+ if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1))
+ {
+ char *dsym_extension_pos = ::strstr (path, ".dSYM");
+ if (dsym_extension_pos)
+ {
+ *dsym_extension_pos = '\0';
+ if (log)
+ {
+ log->Printf ("Looking for executable binary next to dSYM bundle with name with name %s", path);
+ }
+ FileSpec file_spec (path, true);
+ ModuleSpecList module_specs;
+ ModuleSpec matched_module_spec;
+ switch (file_spec.GetFileType())
+ {
+ case FileSpec::eFileTypeDirectory: // Bundle directory?
+ {
+ CFCBundle bundle (path);
+ CFCReleaser<CFURLRef> bundle_exe_url (bundle.CopyExecutableURL ());
+ if (bundle_exe_url.get())
+ {
+ if (::CFURLGetFileSystemRepresentation (bundle_exe_url.get(), true, (UInt8*)path, sizeof(path)-1))
+ {
+ FileSpec bundle_exe_file_spec (path, true);
+ if (ObjectFile::GetModuleSpecifications(bundle_exe_file_spec, 0, 0, module_specs) &&
+ module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+
+ {
+ ++items_found;
+ return_module_spec.GetFileSpec() = bundle_exe_file_spec;
+ if (log)
+ {
+ log->Printf ("Executable binary %s next to dSYM is compatible; using", path);
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case FileSpec::eFileTypePipe: // Forget pipes
+ case FileSpec::eFileTypeSocket: // We can't process socket files
+ case FileSpec::eFileTypeInvalid: // File doesn't exist...
+ break;
+
+ case FileSpec::eFileTypeUnknown:
+ case FileSpec::eFileTypeRegular:
+ case FileSpec::eFileTypeSymbolicLink:
+ case FileSpec::eFileTypeOther:
+ if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0, module_specs) &&
+ module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
+
+ {
+ ++items_found;
+ return_module_spec.GetFileSpec() = file_spec;
+ if (log)
+ {
+ log->Printf ("Executable binary %s next to dSYM is compatible; using", path);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif // #if !defined (__arm__) && !defined (__arm64__) && !defined (__aarch64__)
+
+ return items_found;
+}
+
+FileSpec
+Symbols::FindSymbolFileInBundle (const FileSpec& dsym_bundle_fspec,
+ const lldb_private::UUID *uuid,
+ const ArchSpec *arch)
+{
+ char path[PATH_MAX];
+
+ FileSpec dsym_fspec;
+
+ if (dsym_bundle_fspec.GetPath(path, sizeof(path)))
+ {
+ ::strncat (path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
+
+ lldb_utility::CleanUp <DIR *, int> dirp (opendir(path), NULL, closedir);
+ if (dirp.is_valid())
+ {
+ dsym_fspec.GetDirectory().SetCString(path);
+ struct dirent* dp;
+ while ((dp = readdir(dirp.get())) != NULL)
+ {
+ // Only search directories
+ if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
+ {
+ if (dp->d_namlen == 1 && dp->d_name[0] == '.')
+ continue;
+
+ if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
+ continue;
+ }
+
+ if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN)
+ {
+ dsym_fspec.GetFilename().SetCString(dp->d_name);
+ ModuleSpecList module_specs;
+ if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs))
+ {
+ ModuleSpec spec;
+ for (size_t i = 0; i < module_specs.GetSize(); ++i)
+ {
+ assert(module_specs.GetModuleSpecAtIndex(i, spec));
+ if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
+ (arch == NULL || (spec.GetArchitecturePtr() && spec.GetArchitecture().IsCompatibleMatch(*arch))))
+ {
+ return dsym_fspec;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ dsym_fspec.Clear();
+ return dsym_fspec;
+}
+
+static bool
+GetModuleSpecInfoFromUUIDDictionary (CFDictionaryRef uuid_dict, ModuleSpec &module_spec)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ bool success = false;
+ if (uuid_dict != NULL && CFGetTypeID (uuid_dict) == CFDictionaryGetTypeID ())
+ {
+ std::string str;
+ CFStringRef cf_str;
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSymbolRichExecutable"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ if (CFCString::FileSystemRepresentation(cf_str, str))
+ {
+ module_spec.GetFileSpec().SetFile (str.c_str(), true);
+ if (log)
+ {
+ log->Printf ("From dsymForUUID plist: Symbol rich executable is at '%s'", str.c_str());
+ }
+ }
+ }
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGDSYMPath"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ if (CFCString::FileSystemRepresentation(cf_str, str))
+ {
+ module_spec.GetSymbolFileSpec().SetFile (str.c_str(), true);
+ success = true;
+ if (log)
+ {
+ log->Printf ("From dsymForUUID plist: dSYM is at '%s'", str.c_str());
+ }
+ }
+ }
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGArchitecture"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ if (CFCString::FileSystemRepresentation(cf_str, str))
+ module_spec.GetArchitecture().SetTriple(str.c_str());
+ }
+
+ std::string DBGBuildSourcePath;
+ std::string DBGSourcePath;
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGBuildSourcePath"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
+ }
+
+ cf_str = (CFStringRef)CFDictionaryGetValue ((CFDictionaryRef) uuid_dict, CFSTR("DBGSourcePath"));
+ if (cf_str && CFGetTypeID (cf_str) == CFStringGetTypeID ())
+ {
+ CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
+ }
+
+ if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty())
+ {
+ module_spec.GetSourceMappingList().Append (ConstString(DBGBuildSourcePath.c_str()), ConstString(DBGSourcePath.c_str()), true);
+ }
+ }
+ return success;
+}
+
+
+bool
+Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
+{
+ bool success = false;
+ const UUID *uuid_ptr = module_spec.GetUUIDPtr();
+ const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
+
+ // It's expensive to check for the DBGShellCommands defaults setting, only do it once per
+ // lldb run and cache the result.
+ static bool g_have_checked_for_dbgshell_command = false;
+ static const char *g_dbgshell_command = NULL;
+ if (g_have_checked_for_dbgshell_command == false)
+ {
+ g_have_checked_for_dbgshell_command = true;
+ CFTypeRef defaults_setting = CFPreferencesCopyAppValue (CFSTR ("DBGShellCommands"), CFSTR ("com.apple.DebugSymbols"));
+ if (defaults_setting && CFGetTypeID (defaults_setting) == CFStringGetTypeID())
+ {
+ char cstr_buf[PATH_MAX];
+ if (CFStringGetCString ((CFStringRef) defaults_setting, cstr_buf, sizeof (cstr_buf), kCFStringEncodingUTF8))
+ {
+ g_dbgshell_command = strdup (cstr_buf); // this malloc'ed memory will never be freed
+ }
+ }
+ if (defaults_setting)
+ {
+ CFRelease (defaults_setting);
+ }
+ }
+
+ // When g_dbgshell_command is NULL, the user has not enabled the use of an external program
+ // to find the symbols, don't run it for them.
+ if (force_lookup == false && g_dbgshell_command == NULL)
+ {
+ return false;
+ }
+
+ if (uuid_ptr || (file_spec_ptr && file_spec_ptr->Exists()))
+ {
+ static bool g_located_dsym_for_uuid_exe = false;
+ static bool g_dsym_for_uuid_exe_exists = false;
+ static char g_dsym_for_uuid_exe_path[PATH_MAX];
+ if (!g_located_dsym_for_uuid_exe)
+ {
+ g_located_dsym_for_uuid_exe = true;
+ const char *dsym_for_uuid_exe_path_cstr = getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE");
+ FileSpec dsym_for_uuid_exe_spec;
+ if (dsym_for_uuid_exe_path_cstr)
+ {
+ dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, true);
+ g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
+ }
+
+ if (!g_dsym_for_uuid_exe_exists)
+ {
+ dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", false);
+ g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
+ if (!g_dsym_for_uuid_exe_exists)
+ {
+ long bufsize;
+ if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1)
+ {
+ char buffer[bufsize];
+ struct passwd pwd;
+ struct passwd *tilde_rc = NULL;
+ // we are a library so we need to use the reentrant version of getpwnam()
+ if (getpwnam_r ("rc", &pwd, buffer, bufsize, &tilde_rc) == 0
+ && tilde_rc
+ && tilde_rc->pw_dir)
+ {
+ std::string dsymforuuid_path(tilde_rc->pw_dir);
+ dsymforuuid_path += "/bin/dsymForUUID";
+ dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), false);
+ g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
+ }
+ }
+ }
+ }
+ if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL)
+ {
+ dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, true);
+ g_dsym_for_uuid_exe_exists = dsym_for_uuid_exe_spec.Exists();
+ }
+
+ if (g_dsym_for_uuid_exe_exists)
+ dsym_for_uuid_exe_spec.GetPath (g_dsym_for_uuid_exe_path, sizeof(g_dsym_for_uuid_exe_path));
+ }
+ if (g_dsym_for_uuid_exe_exists)
+ {
+ std::string uuid_str;
+ char file_path[PATH_MAX];
+ file_path[0] = '\0';
+
+ if (uuid_ptr)
+ uuid_str = uuid_ptr->GetAsString();
+
+ if (file_spec_ptr)
+ file_spec_ptr->GetPath(file_path, sizeof(file_path));
+
+ StreamString command;
+ if (!uuid_str.empty())
+ command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, uuid_str.c_str());
+ else if (file_path[0] != '\0')
+ command.Printf("%s --ignoreNegativeCache --copyExecutable %s", g_dsym_for_uuid_exe_path, file_path);
+
+ if (!command.GetString().empty())
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ int exit_status = -1;
+ int signo = -1;
+ std::string command_output;
+ if (log)
+ {
+ if (!uuid_str.empty())
+ log->Printf("Calling %s with UUID %s to find dSYM", g_dsym_for_uuid_exe_path, uuid_str.c_str());
+ else if (file_path[0] != '\0')
+ log->Printf("Calling %s with file %s to find dSYM", g_dsym_for_uuid_exe_path, file_path);
+ }
+ Error error = Host::RunShellCommand (command.GetData(),
+ NULL, // current working directory
+ &exit_status, // Exit status
+ &signo, // Signal int *
+ &command_output, // Command output
+ 30, // Large timeout to allow for long dsym download times
+ false); // Don't run in a shell (we don't need shell expansion)
+ if (error.Success() && exit_status == 0 && !command_output.empty())
+ {
+ CFCData data (CFDataCreateWithBytesNoCopy (NULL,
+ (const UInt8 *)command_output.data(),
+ command_output.size(),
+ kCFAllocatorNull));
+
+ CFCReleaser<CFDictionaryRef> plist((CFDictionaryRef)::CFPropertyListCreateFromXMLData (NULL, data.get(), kCFPropertyListImmutable, NULL));
+
+ if (plist.get() && CFGetTypeID (plist.get()) == CFDictionaryGetTypeID ())
+ {
+ if (!uuid_str.empty())
+ {
+ CFCString uuid_cfstr(uuid_str.c_str());
+ CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue (plist.get(), uuid_cfstr.get());
+ success = GetModuleSpecInfoFromUUIDDictionary (uuid_dict, module_spec);
+ }
+ else
+ {
+ const CFIndex num_values = ::CFDictionaryGetCount(plist.get());
+ if (num_values > 0)
+ {
+ std::vector<CFStringRef> keys (num_values, NULL);
+ std::vector<CFDictionaryRef> values (num_values, NULL);
+ ::CFDictionaryGetKeysAndValues(plist.get(), NULL, (const void **)&values[0]);
+ if (num_values == 1)
+ {
+ return GetModuleSpecInfoFromUUIDDictionary (values[0], module_spec);
+ }
+ else
+ {
+ for (CFIndex i=0; i<num_values; ++i)
+ {
+ ModuleSpec curr_module_spec;
+ if (GetModuleSpecInfoFromUUIDDictionary (values[i], curr_module_spec))
+ {
+ if (module_spec.GetArchitecture().IsCompatibleMatch(curr_module_spec.GetArchitecture()))
+ {
+ module_spec = curr_module_spec;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ {
+ if (!uuid_str.empty())
+ log->Printf("Called %s on %s, no matches", g_dsym_for_uuid_exe_path, uuid_str.c_str());
+ else if (file_path[0] != '\0')
+ log->Printf("Called %s on %s, no matches", g_dsym_for_uuid_exe_path, file_path);
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
diff --git a/source/Host/macosx/ThisThread.cpp b/source/Host/macosx/ThisThread.cpp
new file mode 100644
index 0000000000000..95c7f2bf1e38b
--- /dev/null
+++ b/source/Host/macosx/ThisThread.cpp
@@ -0,0 +1,39 @@
+//===-- ThisThread.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/ThisThread.h"
+
+#include <pthread.h>
+
+using namespace lldb_private;
+
+void
+ThisThread::SetName(llvm::StringRef name)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
+ ::pthread_setname_np(name);
+#endif
+}
+
+void
+ThisThread::GetName(llvm::SmallVectorImpl<char> &name)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
+ char pthread_name[1024];
+ dispatch_queue_t current_queue = ::dispatch_get_current_queue();
+ if (current_queue != NULL)
+ {
+ const char *queue_name = dispatch_queue_get_label(current_queue);
+ if (queue_name && queue_name[0])
+ {
+ name = queue_name;
+ }
+ }
+#endif
+}
diff --git a/source/Host/macosx/cfcpp/CFCBundle.cpp b/source/Host/macosx/cfcpp/CFCBundle.cpp
new file mode 100644
index 0000000000000..71b074993661d
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCBundle.cpp
@@ -0,0 +1,99 @@
+//===-- CFCBundle.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCBundle.h"
+#include "CFCString.h"
+
+//----------------------------------------------------------------------
+// CFCBundle constructor
+//----------------------------------------------------------------------
+CFCBundle::CFCBundle(const char *path) :
+ CFCReleaser<CFBundleRef>()
+{
+ if (path && path[0])
+ SetPath(path);
+}
+
+CFCBundle::CFCBundle(CFURLRef url) :
+ CFCReleaser<CFBundleRef>(url ? CFBundleCreate(NULL, url) : NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCBundle::~CFCBundle()
+{
+}
+
+//----------------------------------------------------------------------
+// Set the path for a bundle by supplying a
+//----------------------------------------------------------------------
+bool
+CFCBundle::SetPath (const char *path)
+{
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ // Release our old bundle and URL
+ reset();
+
+ // Make a CFStringRef from the supplied path
+ CFCString cf_path;
+ cf_path.SetFileSystemRepresentation(path);
+ if (cf_path.get())
+ {
+ // Make our Bundle URL
+ CFCReleaser<CFURLRef> bundle_url (::CFURLCreateWithFileSystemPath (alloc, cf_path.get(), kCFURLPOSIXPathStyle, true));
+ if (bundle_url.get())
+ reset (::CFBundleCreate (alloc, bundle_url.get()));
+ }
+ return get() != NULL;
+}
+
+bool
+CFCBundle::GetPath (char *dst, size_t dst_len)
+{
+ CFBundleRef bundle = get();
+ if (bundle)
+ {
+ CFCReleaser<CFURLRef> bundle_url (CFBundleCopyBundleURL (bundle));
+ if (bundle_url.get())
+ {
+ Boolean resolveAgainstBase = 0;
+ return ::CFURLGetFileSystemRepresentation (bundle_url.get(), resolveAgainstBase, (UInt8 *)dst, dst_len) != 0;
+ }
+ }
+ return false;
+}
+
+CFStringRef
+CFCBundle::GetIdentifier () const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return ::CFBundleGetIdentifier (bundle);
+ return NULL;
+}
+
+CFTypeRef
+CFCBundle::GetValueForInfoDictionaryKey(CFStringRef key) const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return ::CFBundleGetValueForInfoDictionaryKey(bundle, key);
+ return NULL;
+}
+
+CFURLRef
+CFCBundle::CopyExecutableURL () const
+{
+ CFBundleRef bundle = get();
+ if (bundle != NULL)
+ return CFBundleCopyExecutableURL(bundle);
+ return NULL;
+}
diff --git a/source/Host/macosx/cfcpp/CFCBundle.h b/source/Host/macosx/cfcpp/CFCBundle.h
new file mode 100644
index 0000000000000..1cd1b681af840
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCBundle.h
@@ -0,0 +1,50 @@
+//===-- CFCBundle.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFBundle_h_
+#define CoreFoundationCPP_CFBundle_h_
+
+#include "CFCReleaser.h"
+
+class CFCBundle : public CFCReleaser<CFBundleRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCBundle (const char *path = NULL);
+ CFCBundle (CFURLRef url);
+
+ virtual
+ ~CFCBundle();
+
+ CFURLRef
+ CopyExecutableURL () const;
+
+ CFStringRef
+ GetIdentifier () const;
+
+ CFTypeRef
+ GetValueForInfoDictionaryKey(CFStringRef key) const;
+
+ bool
+ GetPath (char *dst, size_t dst_len);
+
+ bool
+ SetPath (const char *path);
+
+private:
+ // Disallow copy and assignment constructors
+ CFCBundle(const CFCBundle&);
+
+ const CFCBundle&
+ operator=(const CFCBundle&);
+};
+
+#endif // #ifndef CoreFoundationCPP_CFBundle_h_
diff --git a/source/Host/macosx/cfcpp/CFCData.cpp b/source/Host/macosx/cfcpp/CFCData.cpp
new file mode 100644
index 0000000000000..4f49368ad8adf
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCData.cpp
@@ -0,0 +1,82 @@
+//===-- CFCData.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCData.h"
+
+//----------------------------------------------------------------------
+// CFCData constructor
+//----------------------------------------------------------------------
+CFCData::CFCData(CFDataRef data) :
+ CFCReleaser<CFDataRef>(data)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFCData copy constructor
+//----------------------------------------------------------------------
+CFCData::CFCData(const CFCData& rhs) :
+ CFCReleaser<CFDataRef>(rhs)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFCData copy constructor
+//----------------------------------------------------------------------
+CFCData&
+CFCData::operator=(const CFCData& rhs)
+
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCData::~CFCData()
+{
+}
+
+
+CFIndex
+CFCData::GetLength() const
+{
+ CFDataRef data = get();
+ if (data)
+ return CFDataGetLength (data);
+ return 0;
+}
+
+
+const uint8_t*
+CFCData::GetBytePtr() const
+{
+ CFDataRef data = get();
+ if (data)
+ return CFDataGetBytePtr (data);
+ return NULL;
+}
+
+CFDataRef
+CFCData::Serialize(CFPropertyListRef plist, CFPropertyListFormat format)
+{
+ CFAllocatorRef alloc = kCFAllocatorDefault;
+ reset();
+ CFCReleaser<CFWriteStreamRef> stream (::CFWriteStreamCreateWithAllocatedBuffers (alloc, alloc));
+ ::CFWriteStreamOpen (stream.get());
+ CFIndex len = ::CFPropertyListWriteToStream (plist, stream.get(), format, NULL);
+ if (len > 0)
+ reset((CFDataRef)::CFWriteStreamCopyProperty (stream.get(), kCFStreamPropertyDataWritten));
+ ::CFWriteStreamClose (stream.get());
+ return get();
+}
+
diff --git a/source/Host/macosx/cfcpp/CFCData.h b/source/Host/macosx/cfcpp/CFCData.h
new file mode 100644
index 0000000000000..6a718f54c0555
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCData.h
@@ -0,0 +1,35 @@
+//===-- CFCData.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFData_h_
+#define CoreFoundationCPP_CFData_h_
+
+#include "CFCReleaser.h"
+
+class CFCData : public CFCReleaser<CFDataRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCData(CFDataRef data = NULL);
+ CFCData(const CFCData& rhs);
+ CFCData& operator=(const CFCData& rhs);
+ virtual ~CFCData();
+
+ CFDataRef Serialize(CFPropertyListRef plist, CFPropertyListFormat format);
+ const uint8_t* GetBytePtr () const;
+ CFIndex GetLength () const;
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFCData can see and modify these
+ //------------------------------------------------------------------
+};
+
+#endif // #ifndef CoreFoundationCPP_CFData_h_
diff --git a/source/Host/macosx/cfcpp/CFCMutableArray.cpp b/source/Host/macosx/cfcpp/CFCMutableArray.cpp
new file mode 100644
index 0000000000000..c3c0a11193a7c
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableArray.cpp
@@ -0,0 +1,166 @@
+//===-- CFCMutableArray.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCMutableArray.h"
+#include "CFCString.h"
+
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCMutableArray::CFCMutableArray(CFMutableArrayRef s) :
+ CFCReleaser<CFMutableArrayRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableArray copy constructor
+//----------------------------------------------------------------------
+CFCMutableArray::CFCMutableArray(const CFCMutableArray& rhs) :
+ CFCReleaser<CFMutableArrayRef> (rhs) // NOTE: this won't make a copy of the array, just add a new reference to it
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableArray copy constructor
+//----------------------------------------------------------------------
+CFCMutableArray&
+CFCMutableArray::operator=(const CFCMutableArray& rhs)
+{
+ if (this != &rhs)
+ *this = rhs; // NOTE: this operator won't make a copy of the array, just add a new reference to it
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCMutableArray::~CFCMutableArray()
+{
+}
+
+
+CFIndex
+CFCMutableArray::GetCount() const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ return ::CFArrayGetCount (array);
+ return 0;
+}
+
+CFIndex
+CFCMutableArray::GetCountOfValue(CFRange range, const void *value) const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ return ::CFArrayGetCountOfValue (array, range, value);
+ return 0;
+}
+
+CFIndex
+CFCMutableArray::GetCountOfValue(const void *value) const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ return ::CFArrayGetCountOfValue (array, CFRangeMake(0, GetCount()), value);
+ return 0;
+}
+
+const void *
+CFCMutableArray::GetValueAtIndex(CFIndex idx) const
+{
+ CFMutableArrayRef array = get();
+ if (array)
+ {
+ const CFIndex num_array_items = ::CFArrayGetCount (array);
+ if (0 <= idx && idx < num_array_items)
+ {
+ return ::CFArrayGetValueAtIndex (array, idx);
+ }
+ }
+ return NULL;
+}
+
+bool
+CFCMutableArray::SetValueAtIndex(CFIndex idx, const void *value)
+{
+ CFMutableArrayRef array = get();
+ if (array != NULL)
+ {
+ const CFIndex num_array_items = ::CFArrayGetCount (array);
+ if (0 <= idx && idx < num_array_items)
+ {
+ ::CFArraySetValueAtIndex (array, idx, value);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableArray::AppendValue(const void *value, bool can_create)
+{
+ CFMutableArrayRef array = get();
+ if (array == NULL)
+ {
+ if (can_create == false)
+ return false;
+ array = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ reset ( array );
+ }
+ if (array != NULL)
+ {
+ ::CFArrayAppendValue(array, value);
+ return true;
+ }
+ return false;
+}
+
+
+bool
+CFCMutableArray::AppendCStringAsCFString (const char *s, CFStringEncoding encoding, bool can_create)
+{
+ CFMutableArrayRef array = get();
+ if (array == NULL)
+ {
+ if (can_create == false)
+ return false;
+ array = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ reset ( array );
+ }
+ if (array != NULL)
+ {
+ CFCString cf_str (s, encoding);
+ ::CFArrayAppendValue (array, cf_str.get());
+ return true;
+ }
+ return false;
+}
+
+bool
+CFCMutableArray::AppendFileSystemRepresentationAsCFString (const char *s, bool can_create)
+{
+ CFMutableArrayRef array = get();
+ if (array == NULL)
+ {
+ if (can_create == false)
+ return false;
+ array = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+ reset ( array );
+ }
+ if (array != NULL)
+ {
+ CFCString cf_path;
+ cf_path.SetFileSystemRepresentation(s);
+ ::CFArrayAppendValue (array, cf_path.get());
+ return true;
+ }
+ return false;
+}
diff --git a/source/Host/macosx/cfcpp/CFCMutableArray.h b/source/Host/macosx/cfcpp/CFCMutableArray.h
new file mode 100644
index 0000000000000..f78cd92ffab16
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableArray.h
@@ -0,0 +1,39 @@
+//===-- CFCMutableArray.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFMutableArray_h_
+#define CoreFoundationCPP_CFMutableArray_h_
+
+#include "CFCReleaser.h"
+
+class CFCMutableArray : public CFCReleaser<CFMutableArrayRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCMutableArray(CFMutableArrayRef array = NULL);
+ CFCMutableArray(const CFCMutableArray& rhs); // This will copy the array contents into a new array
+ CFCMutableArray& operator=(const CFCMutableArray& rhs); // This will re-use the same array and just bump the ref count
+ virtual ~CFCMutableArray();
+
+ CFIndex GetCount() const;
+ CFIndex GetCountOfValue(const void *value) const;
+ CFIndex GetCountOfValue(CFRange range, const void *value) const;
+ const void * GetValueAtIndex(CFIndex idx) const;
+ bool SetValueAtIndex(CFIndex idx, const void *value);
+ bool AppendValue(const void *value, bool can_create = true); // Appends value and optionally creates a CFCMutableArray if this class doesn't contain one
+ bool AppendCStringAsCFString (const char *cstr,
+ CFStringEncoding encoding = kCFStringEncodingUTF8,
+ bool can_create = true);
+ bool AppendFileSystemRepresentationAsCFString (const char *s,
+ bool can_create = true);
+};
+
+#endif // #ifndef CoreFoundationCPP_CFMutableArray_h_
diff --git a/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp b/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp
new file mode 100644
index 0000000000000..bce023bfd616e
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp
@@ -0,0 +1,529 @@
+//===-- CFCMutableDictionary.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCMutableDictionary.h"
+#include "CFCString.h"
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCMutableDictionary::CFCMutableDictionary(CFMutableDictionaryRef s) :
+ CFCReleaser<CFMutableDictionaryRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableDictionary copy constructor
+//----------------------------------------------------------------------
+CFCMutableDictionary::CFCMutableDictionary(const CFCMutableDictionary& rhs) :
+ CFCReleaser<CFMutableDictionaryRef> (rhs)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableDictionary copy constructor
+//----------------------------------------------------------------------
+const CFCMutableDictionary&
+CFCMutableDictionary::operator=(const CFCMutableDictionary& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCMutableDictionary::~CFCMutableDictionary()
+{
+}
+
+
+CFIndex
+CFCMutableDictionary::GetCount() const
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetCount (dict);
+ return 0;
+}
+
+CFIndex
+CFCMutableDictionary::GetCountOfKey(const void *key) const
+
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetCountOfKey (dict, key);
+ return 0;
+}
+
+CFIndex
+CFCMutableDictionary::GetCountOfValue(const void *value) const
+
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetCountOfValue (dict, value);
+ return 0;
+}
+
+void
+CFCMutableDictionary::GetKeysAndValues(const void **keys, const void **values) const
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryGetKeysAndValues (dict, keys, values);
+}
+
+
+const void *
+CFCMutableDictionary::GetValue(const void *key) const
+
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetValue (dict, key);
+ return NULL;
+}
+
+Boolean
+CFCMutableDictionary::GetValueIfPresent(const void *key, const void **value_handle) const
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ return ::CFDictionaryGetValueIfPresent (dict, key, value_handle);
+ return false;
+}
+
+
+CFMutableDictionaryRef
+CFCMutableDictionary::Dictionary(bool can_create)
+{
+ CFMutableDictionaryRef dict = get();
+ if (can_create && dict == NULL)
+ {
+ dict = ::CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ reset ( dict );
+ }
+ return dict;
+}
+
+bool
+CFCMutableDictionary::AddValue(CFStringRef key, const void *value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValue(CFStringRef key, const void *value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, value);
+ return true;
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt8(CFStringRef key, int8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt8Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt8(CFStringRef key, int8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt8Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt16(CFStringRef key, int16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt16(CFStringRef key, int16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt32(CFStringRef key, int32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt32(CFStringRef key, int32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueSInt64(CFStringRef key, int64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueSInt64(CFStringRef key, int64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueUInt8(CFStringRef key, uint8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int16_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueUInt8(CFStringRef key, uint8_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int16_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt16Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableDictionary::AddValueUInt16(CFStringRef key, uint16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int32_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueUInt16(CFStringRef key, uint16_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int32_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueUInt32(CFStringRef key, uint32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int64_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueUInt32(CFStringRef key, uint32_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // Have to promote to the next size type so things don't appear negative of the MSBit is set...
+ int64_t sval = value;
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &sval));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableDictionary::AddValueUInt64(CFStringRef key, uint64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+CFCMutableDictionary::SetValueUInt64(CFStringRef key, uint64_t value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueDouble(CFStringRef key, double value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberDoubleType, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueDouble(CFStringRef key, double value, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ // The number may appear negative if the MSBit is set in "value". Due to a limitation of
+ // CFNumber, there isn't a way to have it show up otherwise as of this writing.
+ CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberDoubleType, &value));
+ if (cf_number.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_number.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::AddValueCString(CFStringRef key, const char *cstr, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCString cf_str(cstr, kCFStringEncodingUTF8);
+ if (cf_str.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionaryAddValue (dict, key, cf_str.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+CFCMutableDictionary::SetValueCString(CFStringRef key, const char *cstr, bool can_create)
+{
+ CFMutableDictionaryRef dict = Dictionary(can_create);
+ if (dict != NULL)
+ {
+ CFCString cf_str(cstr, kCFStringEncodingUTF8);
+ if (cf_str.get())
+ {
+ // Let the dictionary own the CFNumber
+ ::CFDictionarySetValue (dict, key, cf_str.get());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void
+CFCMutableDictionary::RemoveAllValues()
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryRemoveAllValues(dict);
+}
+
+void
+CFCMutableDictionary::RemoveValue(const void *value)
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryRemoveValue(dict, value);
+}
+void
+CFCMutableDictionary::ReplaceValue(const void *key, const void *value)
+{
+ CFMutableDictionaryRef dict = get();
+ if (dict)
+ ::CFDictionaryReplaceValue (dict, key, value);
+}
+
diff --git a/source/Host/macosx/cfcpp/CFCMutableDictionary.h b/source/Host/macosx/cfcpp/CFCMutableDictionary.h
new file mode 100644
index 0000000000000..a1cfb68f569e1
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableDictionary.h
@@ -0,0 +1,79 @@
+//===-- CFCMutableDictionary.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFMutableDictionary_h_
+#define CoreFoundationCPP_CFMutableDictionary_h_
+
+#include "CFCReleaser.h"
+
+class CFCMutableDictionary : public CFCReleaser<CFMutableDictionaryRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCMutableDictionary(CFMutableDictionaryRef s = NULL);
+ CFCMutableDictionary(const CFCMutableDictionary& rhs);
+ virtual ~CFCMutableDictionary();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const CFCMutableDictionary&
+ operator=(const CFCMutableDictionary& rhs);
+
+
+ CFIndex GetCount() const;
+ CFIndex GetCountOfKey(const void *value) const;
+ CFIndex GetCountOfValue(const void *value) const;
+ void GetKeysAndValues(const void **keys, const void **values) const;
+ const void * GetValue(const void *key) const;
+ Boolean GetValueIfPresent(const void *key, const void **value_handle) const;
+ bool AddValue(CFStringRef key, const void *value, bool can_create = false);
+ bool SetValue(CFStringRef key, const void *value, bool can_create = false);
+ bool AddValueSInt8(CFStringRef key, int8_t value, bool can_create = false);
+ bool SetValueSInt8(CFStringRef key, int8_t value, bool can_create = false);
+ bool AddValueSInt16(CFStringRef key, int16_t value, bool can_create = false);
+ bool SetValueSInt16(CFStringRef key, int16_t value, bool can_create = false);
+ bool AddValueSInt32(CFStringRef key, int32_t value, bool can_create = false);
+ bool SetValueSInt32(CFStringRef key, int32_t value, bool can_create = false);
+ bool AddValueSInt64(CFStringRef key, int64_t value, bool can_create = false);
+ bool SetValueSInt64(CFStringRef key, int64_t value, bool can_create = false);
+ bool AddValueUInt8(CFStringRef key, uint8_t value, bool can_create = false);
+ bool SetValueUInt8(CFStringRef key, uint8_t value, bool can_create = false);
+ bool AddValueUInt16(CFStringRef key, uint16_t value, bool can_create = false);
+ bool SetValueUInt16(CFStringRef key, uint16_t value, bool can_create = false);
+ bool AddValueUInt32(CFStringRef key, uint32_t value, bool can_create = false);
+ bool SetValueUInt32(CFStringRef key, uint32_t value, bool can_create = false);
+ bool AddValueUInt64(CFStringRef key, uint64_t value, bool can_create = false);
+ bool SetValueUInt64(CFStringRef key, uint64_t value, bool can_create = false);
+ bool AddValueDouble(CFStringRef key, double value, bool can_create = false);
+ bool SetValueDouble(CFStringRef key, double value, bool can_create = false);
+ bool AddValueCString(CFStringRef key, const char *cstr, bool can_create = false);
+ bool SetValueCString(CFStringRef key, const char *cstr, bool can_create = false);
+ void RemoveValue(const void *value);
+ void ReplaceValue(const void *key, const void *value);
+ void RemoveAllValues();
+ CFMutableDictionaryRef Dictionary(bool can_create);
+
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFCMutableDictionary can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For CFCMutableDictionary only
+ //------------------------------------------------------------------
+
+};
+
+
+#endif // CoreFoundationCPP_CFMutableDictionary_h_
diff --git a/source/Host/macosx/cfcpp/CFCMutableSet.cpp b/source/Host/macosx/cfcpp/CFCMutableSet.cpp
new file mode 100644
index 0000000000000..afc09e180b6b6
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableSet.cpp
@@ -0,0 +1,114 @@
+//===-- CFCMutableSet.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCMutableSet.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCMutableSet::CFCMutableSet(CFMutableSetRef s) :
+ CFCReleaser<CFMutableSetRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableSet copy constructor
+//----------------------------------------------------------------------
+CFCMutableSet::CFCMutableSet(const CFCMutableSet& rhs) :
+ CFCReleaser<CFMutableSetRef> (rhs)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCMutableSet copy constructor
+//----------------------------------------------------------------------
+const CFCMutableSet&
+CFCMutableSet::operator=(const CFCMutableSet& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCMutableSet::~CFCMutableSet()
+{
+}
+
+
+CFIndex
+CFCMutableSet::GetCount() const
+{
+ CFMutableSetRef set = get();
+ if (set)
+ return ::CFSetGetCount (set);
+ return 0;
+}
+
+CFIndex
+CFCMutableSet::GetCountOfValue(const void *value) const
+{
+ CFMutableSetRef set = get();
+ if (set)
+ return ::CFSetGetCountOfValue (set, value);
+ return 0;
+}
+
+const void *
+CFCMutableSet::GetValue(const void *value) const
+{
+ CFMutableSetRef set = get();
+ if (set)
+ return ::CFSetGetValue(set, value);
+ return NULL;
+}
+
+
+const void *
+CFCMutableSet::AddValue(const void *value, bool can_create)
+{
+ CFMutableSetRef set = get();
+ if (set == NULL)
+ {
+ if (can_create == false)
+ return NULL;
+ set = ::CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
+ reset ( set );
+ }
+ if (set != NULL)
+ {
+ ::CFSetAddValue(set, value);
+ return value;
+ }
+ return NULL;
+}
+
+void
+CFCMutableSet::RemoveValue(const void *value)
+{
+ CFMutableSetRef set = get();
+ if (set)
+ ::CFSetRemoveValue(set, value);
+}
+
+void
+CFCMutableSet::RemoveAllValues()
+{
+ CFMutableSetRef set = get();
+ if (set)
+ ::CFSetRemoveAllValues(set);
+}
+
diff --git a/source/Host/macosx/cfcpp/CFCMutableSet.h b/source/Host/macosx/cfcpp/CFCMutableSet.h
new file mode 100644
index 0000000000000..78f7a8be81d20
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCMutableSet.h
@@ -0,0 +1,53 @@
+//===-- CFCMutableSet.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFMutableSet_h_
+#define CoreFoundationCPP_CFMutableSet_h_
+
+#include "CFCReleaser.h"
+
+class CFCMutableSet : public CFCReleaser<CFMutableSetRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCMutableSet(CFMutableSetRef s = NULL);
+ CFCMutableSet(const CFCMutableSet& rhs);
+ virtual ~CFCMutableSet();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const CFCMutableSet&
+ operator=(const CFCMutableSet& rhs);
+
+
+ CFIndex GetCount() const;
+ CFIndex GetCountOfValue(const void *value) const;
+ const void * GetValue(const void *value) const;
+ const void * AddValue(const void *value, bool can_create);
+ void RemoveValue(const void *value);
+ void RemoveAllValues();
+
+
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CFCMutableSet can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For CFCMutableSet only
+ //------------------------------------------------------------------
+
+};
+
+#endif // CoreFoundationCPP_CFMutableSet_h_
diff --git a/source/Host/macosx/cfcpp/CFCReleaser.h b/source/Host/macosx/cfcpp/CFCReleaser.h
new file mode 100644
index 0000000000000..67dd2ead57990
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCReleaser.h
@@ -0,0 +1,158 @@
+//===-- CFCReleaser.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFReleaser_h_
+#define CoreFoundationCPP_CFReleaser_h_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef __cplusplus
+
+#include <assert.h>
+
+//----------------------------------------------------------------------
+// Templatized CF helper class that can own any CF pointer and will
+// call CFRelease() on any valid pointer it owns unless that pointer is
+// explicitly released using the release() member function. This class
+// is designed to mimic the std::auto_ptr<T> class and has all of the
+// same functions. The one thing to watch out for is the
+// CFCReleaser<T>::release() function won't actually CFRelease any owned
+// pointer, it is designed to relinquish ownership of the pointer just
+// like std:auto_ptr<T>::release() does.
+//----------------------------------------------------------------------
+template <class T>
+class CFCReleaser
+{
+public:
+ //----------------------------------------------------------
+ // Constructor that takes a pointer to a CF object that is
+ // to be released when this object goes out of scope
+ //----------------------------------------------------------
+ CFCReleaser(T ptr = NULL) :
+ _ptr(ptr)
+ {
+ }
+
+ //----------------------------------------------------------
+ // Copy constructor
+ //
+ // Note that copying a CFCReleaser will not transfer
+ // ownership of the contained pointer, but it will bump its
+ // reference count. This is where this class differs from
+ // std::auto_ptr.
+ //----------------------------------------------------------
+ CFCReleaser(const CFCReleaser& rhs) :
+ _ptr(rhs.get())
+ {
+ if (get())
+ ::CFRetain(get());
+ }
+
+
+ //----------------------------------------------------------
+ // The destructor will release the pointer that it contains
+ // if it has a valid pointer.
+ //----------------------------------------------------------
+ virtual ~CFCReleaser()
+ {
+ reset();
+ }
+
+ //----------------------------------------------------------
+ // Assignment operator.
+ //
+ // Note that assigning one CFCReleaser to another will
+ // not transfer ownership of the contained pointer, but it
+ // will bump its reference count. This is where this class
+ // differs from std::auto_ptr.
+ //----------------------------------------------------------
+ CFCReleaser&
+ operator= (const CFCReleaser<T>& rhs)
+ {
+ if (this != &rhs)
+ {
+ // Replace our owned pointer with the new one
+ reset(rhs.get());
+ // Retain the current pointer that we own
+ if (get())
+ ::CFRetain(get());
+ }
+ return *this;
+ }
+
+ //----------------------------------------------------------
+ // Get the address of the contained type in case it needs
+ // to be passed to a function that will fill in a pointer
+ // value. The function currently will assert if _ptr is not
+ // NULL because the only time this method should be used is
+ // if another function will modify the contents, and we
+ // could leak a pointer if this is not NULL. If the
+ // assertion fires, check the offending code, or call
+ // reset() prior to using the "ptr_address()" member to make
+ // sure any owned objects has CFRelease called on it.
+ // I had to add the "enforce_null" bool here because some
+ // API's require the pointer address even though they don't change it.
+ //----------------------------------------------------------
+ T*
+ ptr_address(bool enforce_null = true)
+ {
+ if (enforce_null)
+ assert (_ptr == NULL);
+ return &_ptr;
+ }
+
+ //----------------------------------------------------------
+ // Access the pointer itself
+ //----------------------------------------------------------
+ T
+ get()
+ {
+ return _ptr;
+ }
+
+ const T
+ get() const
+ {
+ return _ptr;
+ }
+
+
+ //----------------------------------------------------------
+ // Set a new value for the pointer and CFRelease our old
+ // value if we had a valid one.
+ //----------------------------------------------------------
+ void
+ reset(T ptr = NULL)
+ {
+ if ((_ptr != NULL) && (ptr != _ptr))
+ ::CFRelease(_ptr);
+ _ptr = ptr;
+ }
+
+ //----------------------------------------------------------
+ // Release ownership without calling CFRelease. This class
+ // is designed to mimic std::auto_ptr<T>, so the release
+ // method releases ownership of the contained pointer
+ // and does NOT call CFRelease.
+ //----------------------------------------------------------
+ T
+ release()
+ {
+ T tmp = _ptr;
+ _ptr = NULL;
+ return tmp;
+ }
+
+private:
+ T _ptr;
+};
+
+#endif // #ifdef __cplusplus
+#endif // #ifndef CoreFoundationCPP_CFReleaser_h_
+
diff --git a/source/Host/macosx/cfcpp/CFCString.cpp b/source/Host/macosx/cfcpp/CFCString.cpp
new file mode 100644
index 0000000000000..81a96b824999c
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCString.cpp
@@ -0,0 +1,195 @@
+//===-- CFCString.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CFCString.h"
+#include <string>
+#include <glob.h>
+
+//----------------------------------------------------------------------
+// CFCString constructor
+//----------------------------------------------------------------------
+CFCString::CFCString(CFStringRef s) :
+ CFCReleaser<CFStringRef> (s)
+{
+}
+
+//----------------------------------------------------------------------
+// CFCString copy constructor
+//----------------------------------------------------------------------
+CFCString::CFCString(const CFCString& rhs) :
+ CFCReleaser<CFStringRef> (rhs)
+{
+
+}
+
+//----------------------------------------------------------------------
+// CFCString copy constructor
+//----------------------------------------------------------------------
+CFCString&
+CFCString::operator=(const CFCString& rhs)
+{
+ if (this != &rhs)
+ *this = rhs;
+ return *this;
+}
+
+CFCString::CFCString (const char *cstr, CFStringEncoding cstr_encoding) :
+ CFCReleaser<CFStringRef> ()
+{
+ if (cstr && cstr[0])
+ {
+ reset(::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding));
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CFCString::~CFCString()
+{
+}
+
+const char *
+CFCString::GetFileSystemRepresentation(std::string& s)
+{
+ return CFCString::FileSystemRepresentation(get(), s);
+}
+
+CFStringRef
+CFCString::SetFileSystemRepresentation (const char *path)
+{
+ CFStringRef new_value = NULL;
+ if (path && path[0])
+ new_value = ::CFStringCreateWithFileSystemRepresentation (kCFAllocatorDefault, path);
+ reset(new_value);
+ return get();
+}
+
+
+CFStringRef
+CFCString::SetFileSystemRepresentationFromCFType (CFTypeRef cf_type)
+{
+ CFStringRef new_value = NULL;
+ if (cf_type != NULL)
+ {
+ CFTypeID cf_type_id = ::CFGetTypeID(cf_type);
+
+ if (cf_type_id == ::CFStringGetTypeID())
+ {
+ // Retain since we are using the existing object
+ new_value = (CFStringRef)::CFRetain(cf_type);
+ }
+ else if (cf_type_id == ::CFURLGetTypeID())
+ {
+ new_value = ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle);
+ }
+ }
+ reset(new_value);
+ return get();
+}
+
+CFStringRef
+CFCString::SetFileSystemRepresentationAndExpandTilde (const char *path)
+{
+ std::string expanded_path;
+ if (CFCString::ExpandTildeInPath(path, expanded_path))
+ SetFileSystemRepresentation(expanded_path.c_str());
+ else
+ reset();
+ return get();
+}
+
+const char *
+CFCString::UTF8(std::string& str)
+{
+ return CFCString::UTF8(get(), str);
+}
+
+// Static function that puts a copy of the UTF8 contents of CF_STR into STR
+// and returns the C string pointer that is contained in STR when successful, else
+// NULL is returned. This allows the std::string parameter to own the extracted string,
+// and also allows that string to be returned as a C string pointer that can be used.
+
+const char *
+CFCString::UTF8 (CFStringRef cf_str, std::string& str)
+{
+ if (cf_str)
+ {
+ const CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFIndex max_utf8_str_len = CFStringGetLength (cf_str);
+ max_utf8_str_len = CFStringGetMaximumSizeForEncoding (max_utf8_str_len, encoding);
+ if (max_utf8_str_len > 0)
+ {
+ str.resize(max_utf8_str_len);
+ if (!str.empty())
+ {
+ if (CFStringGetCString (cf_str, &str[0], str.size(), encoding))
+ {
+ str.resize(strlen(str.c_str()));
+ return str.c_str();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+const char*
+CFCString::ExpandTildeInPath(const char* path, std::string &expanded_path)
+{
+ glob_t globbuf;
+ if (::glob (path, GLOB_TILDE, NULL, &globbuf) == 0)
+ {
+ expanded_path = globbuf.gl_pathv[0];
+ ::globfree (&globbuf);
+ }
+ else
+ expanded_path.clear();
+
+ return expanded_path.c_str();
+}
+
+// Static function that puts a copy of the file system representation of CF_STR
+// into STR and returns the C string pointer that is contained in STR when
+// successful, else NULL is returned. This allows the std::string parameter
+// to own the extracted string, and also allows that string to be returned as
+// a C string pointer that can be used.
+
+const char *
+CFCString::FileSystemRepresentation (CFStringRef cf_str, std::string& str)
+{
+ if (cf_str)
+ {
+ CFIndex max_length = ::CFStringGetMaximumSizeOfFileSystemRepresentation (cf_str);
+ if (max_length > 0)
+ {
+ str.resize(max_length);
+ if (!str.empty())
+ {
+ if (::CFStringGetFileSystemRepresentation (cf_str, &str[0], str.size()))
+ {
+ str.erase(::strlen(str.c_str()));
+ return str.c_str();
+ }
+ }
+ }
+ }
+ str.erase();
+ return NULL;
+}
+
+
+CFIndex
+CFCString::GetLength() const
+{
+ CFStringRef str = get();
+ if (str)
+ return CFStringGetLength (str);
+ return 0;
+}
diff --git a/source/Host/macosx/cfcpp/CFCString.h b/source/Host/macosx/cfcpp/CFCString.h
new file mode 100644
index 0000000000000..27c090313ece6
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CFCString.h
@@ -0,0 +1,41 @@
+//===-- CFCString.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CoreFoundationCPP_CFString_h_
+#define CoreFoundationCPP_CFString_h_
+
+#include <iosfwd>
+
+#include "CFCReleaser.h"
+
+class CFCString : public CFCReleaser<CFStringRef>
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CFCString (CFStringRef cf_str = NULL);
+ CFCString (const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8);
+ CFCString (const CFCString& rhs);
+ CFCString& operator= (const CFCString& rhs);
+ virtual ~CFCString ();
+
+ const char * GetFileSystemRepresentation (std::string& str);
+ CFStringRef SetFileSystemRepresentation (const char *path);
+ CFStringRef SetFileSystemRepresentationFromCFType (CFTypeRef cf_type);
+ CFStringRef SetFileSystemRepresentationAndExpandTilde (const char *path);
+ const char * UTF8 (std::string& str);
+ CFIndex GetLength() const;
+ static const char *UTF8 (CFStringRef cf_str, std::string& str);
+ static const char *FileSystemRepresentation (CFStringRef cf_str, std::string& str);
+ static const char *ExpandTildeInPath(const char* path, std::string &expanded_path);
+
+};
+
+#endif // #ifndef CoreFoundationCPP_CFString_h_
diff --git a/source/Host/macosx/cfcpp/CoreFoundationCPP.h b/source/Host/macosx/cfcpp/CoreFoundationCPP.h
new file mode 100644
index 0000000000000..6843e2649cdab
--- /dev/null
+++ b/source/Host/macosx/cfcpp/CoreFoundationCPP.h
@@ -0,0 +1,30 @@
+//===-- CoreFoundationCPP.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//----------------------------------------------------------------------
+//
+// CoreFoundationCPP.h
+// CoreFoundationCPP
+//
+// Created by Greg Clayton on 4/23/09.
+//
+//
+//----------------------------------------------------------------------
+
+#ifndef CoreFoundationCPP_CoreFoundationCPP_H_
+#define CoreFoundationCPP_CoreFoundationCPP_H_
+
+#include <CoreFoundationCPP/CFCBundle.h>
+#include <CoreFoundationCPP/CFCData.h>
+#include <CoreFoundationCPP/CFCReleaser.h>
+#include <CoreFoundationCPP/CFCMutableArray.h>
+#include <CoreFoundationCPP/CFCMutableDictionary.h>
+#include <CoreFoundationCPP/CFCMutableSet.h>
+#include <CoreFoundationCPP/CFCString.h>
+
+#endif // CoreFoundationCPP_CoreFoundationCPP_H_