diff options
author | Chris Lattner <sabre@nondot.org> | 2010-06-08 16:52:24 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-06-08 16:52:24 +0000 |
commit | 30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c (patch) | |
tree | f70013106f6a461a14abcd71c65f48a95a2979a6 /lldb/source/Host | |
parent | 312c4c799da215b337f790fda330f70c4aa757cf (diff) | |
download | bcm5719-llvm-30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c.tar.gz bcm5719-llvm-30fdc8d841c9d24ac5f3d452b6ece84ee0ac991c.zip |
Initial checkin of lldb code from internal Apple repo.
llvm-svn: 105619
Diffstat (limited to 'lldb/source/Host')
19 files changed, 3354 insertions, 0 deletions
diff --git a/lldb/source/Host/macosx/Condition.cpp b/lldb/source/Host/macosx/Condition.cpp new file mode 100644 index 00000000000..4e93db766db --- /dev/null +++ b/lldb/source/Host/macosx/Condition.cpp @@ -0,0 +1,106 @@ +//===-- Condition.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <errno.h> + +#include "lldb/Host/Condition.h" +#include "lldb/Host/TimeValue.h" + + +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Default constructor +// +// The default constructor will initialize a new pthread condition +// and maintain the condition in the object state. +//---------------------------------------------------------------------- +Condition::Condition () : + m_condition() +{ + ::pthread_cond_init (&m_condition, NULL); +} + +//---------------------------------------------------------------------- +// Destructor +// +// Destroys the pthread condition that the object owns. +//---------------------------------------------------------------------- +Condition::~Condition () +{ + ::pthread_cond_destroy (&m_condition); +} + +//---------------------------------------------------------------------- +// Unblock all threads waiting for a condition variable +//---------------------------------------------------------------------- +int +Condition::Broadcast () +{ + return ::pthread_cond_broadcast (&m_condition); +} + +//---------------------------------------------------------------------- +// Get accessor to the pthread condition object +//---------------------------------------------------------------------- +pthread_cond_t * +Condition::GetCondition () +{ + return &m_condition; +} + +//---------------------------------------------------------------------- +// Unblocks one thread waiting for the condition variable +//---------------------------------------------------------------------- +int +Condition::Signal () +{ + return ::pthread_cond_signal (&m_condition); +} + +//---------------------------------------------------------------------- +// The Wait() function atomically blocks the current thread +// waiting on the owend condition variable, and unblocks the mutex +// specified by "mutex". The waiting thread unblocks only after +// another thread calls Signal(), or Broadcast() with the same +// condition variable, or if "abstime" is valid (non-NULL) this +// function will return when the system time reaches the time +// specified in "abstime". If "abstime" is NULL this function will +// wait for an infinite amount of time for the condition variable +// to be signaled or broadcasted. +// +// The current thread re-acquires the lock on "mutex". +//---------------------------------------------------------------------- +int +Condition::Wait (pthread_mutex_t *mutex, const TimeValue *abstime, bool *timed_out) +{ + int err = 0; + do + { + if (abstime && abstime->IsValid()) + { + struct timespec abstime_ts = abstime->GetAsTimeSpec(); + err = ::pthread_cond_timedwait (&m_condition, mutex, &abstime_ts); + } + else + err = ::pthread_cond_wait (&m_condition, mutex); + } while (err == EINTR); + + if (timed_out != NULL) + { + if (err == ETIMEDOUT) + *timed_out = true; + else + *timed_out = false; + } + + + return err; +} + diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm new file mode 100644 index 00000000000..a18d45efe81 --- /dev/null +++ b/lldb/source/Host/macosx/Host.mm @@ -0,0 +1,803 @@ +//===-- 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 <dlfcn.h> +#include <libgen.h> +#include <mach/mach.h> +#include <mach-o/dyld.h> +#include <signal.h> +#include <stddef.h> +#include <sys/sysctl.h> +#include <unistd.h> + +#include <map> +#include <string> + +#include <objc/objc-auto.h> + +#include <Foundation/Foundation.h> + +#include "CFCBundle.h" +#include "CFCReleaser.h" +#include "CFCString.h" + +#include "lldb/Host/Host.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/FileSpec.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/TargetList.h" +#include "lldb/lldb-private-log.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------ +// Return the size in bytes of a page on the host system +//------------------------------------------------------------------ +size_t +Host::GetPageSize() +{ + return ::getpagesize(); +} + + +//------------------------------------------------------------------ +// Returns true if the host system is Big Endian. +//------------------------------------------------------------------ +ByteOrder +Host::GetByteOrder() +{ + union EndianTest + { + uint32_t num; + uint8_t bytes[sizeof(uint32_t)]; + } endian = { (uint16_t)0x11223344 }; + switch (endian.bytes[0]) + { + case 0x11: return eByteOrderLittle; + case 0x44: return eByteOrderBig; + case 0x33: return eByteOrderPDP; + } + return eByteOrderInvalid; +} + +lldb::pid_t +Host::GetCurrentProcessID() +{ + return ::getpid(); +} + +lldb::pid_t +Host::GetCurrentThreadID() +{ + return ::mach_thread_self(); +} + + +const ArchSpec & +Host::GetArchitecture () +{ + static ArchSpec g_host_arch; + if (!g_host_arch.IsValid()) + { + uint32_t cputype, cpusubtype; + uint32_t is_64_bit_capable; + size_t len = sizeof(cputype); + if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0) + { + len = sizeof(cpusubtype); + if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0) + g_host_arch.SetArch(cputype, cpusubtype); + + len = sizeof (is_64_bit_capable); + if (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0) + { + if (is_64_bit_capable) + { + if (cputype == CPU_TYPE_I386 && cpusubtype == CPU_SUBTYPE_486) + cpusubtype = CPU_SUBTYPE_I386_ALL; + + cputype |= CPU_ARCH_ABI64; + } + } + } + } + return g_host_arch; +} + +const ConstString & +Host::GetVendorString() +{ + static ConstString g_vendor; + if (!g_vendor) + { + char ostype[64]; + size_t len = sizeof(ostype); + if (::sysctlbyname("kern.ostype", &ostype, &len, NULL, 0) == 0) + g_vendor.SetCString (ostype); + } + return g_vendor; +} + +const ConstString & +Host::GetOSString() +{ + static ConstString g_os_string("apple"); + return g_os_string; +} + +const ConstString & +Host::GetTargetTriple() +{ + static ConstString g_host_triple; + if (!(g_host_triple)) + { + StreamString triple; + triple.Printf("%s-%s-%s", + GetArchitecture ().AsCString(), + GetVendorString().AsCString("apple"), + GetOSString().AsCString("darwin")); + + std::transform (triple.GetString().begin(), + triple.GetString().end(), + triple.GetString().begin(), + ::tolower); + + g_host_triple.SetCString(triple.GetString().c_str()); + } + return g_host_triple; +} + +class MacOSXDarwinThread +{ +public: + MacOSXDarwinThread(const char *thread_name) : + 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 SnowLoepard and later we just call the thread registration function. + objc_registerThreadWithCollector(); +#endif + } + else + { + m_pool = [[NSAutoreleasePool alloc] init]; + } + + + Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name); + } + + ~MacOSXDarwinThread() + { + if (m_pool) + [m_pool release]; + } + + static void PThreadDestructor (void *v) + { + delete (MacOSXDarwinThread*)v; + } + +protected: + NSAutoreleasePool * m_pool; +private: + DISALLOW_COPY_AND_ASSIGN (MacOSXDarwinThread); +}; + +static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT; +static pthread_key_t g_thread_create_key = 0; + +static void +InitThreadCreated() +{ + ::pthread_key_create (&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor); +} + +typedef struct HostThreadCreateInfo +{ + std::string thread_name; + thread_func_t thread_fptr; + thread_arg_t thread_arg; + + HostThreadCreateInfo (const char *name, thread_func_t fptr, thread_arg_t arg) : + thread_name (name ? name : ""), + thread_fptr (fptr), + thread_arg (arg) + { + } +}; + +static thread_result_t +ThreadCreateTrampoline (thread_arg_t arg) +{ + HostThreadCreateInfo *info = (HostThreadCreateInfo *)arg; + Host::ThreadCreated (info->thread_name.c_str()); + thread_func_t thread_fptr = info->thread_fptr; + thread_arg_t thread_arg = info->thread_arg; + + Log * log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); + if (log) + log->Printf("thread created"); + + delete info; + return thread_fptr (thread_arg); +} + +lldb::thread_t +Host::ThreadCreate +( + const char *thread_name, + thread_func_t thread_fptr, + thread_arg_t thread_arg, + Error *error +) +{ + lldb::thread_t thread = LLDB_INVALID_HOST_THREAD; + + // Host::ThreadCreateTrampoline will delete this pointer for us. + HostThreadCreateInfo *info_ptr = new HostThreadCreateInfo (thread_name, thread_fptr, thread_arg); + + int err = ::pthread_create (&thread, NULL, ThreadCreateTrampoline, info_ptr); + if (err == 0) + { + if (error) + error->Clear(); + return thread; + } + + if (error) + error->SetError (err, eErrorTypePOSIX); + + return LLDB_INVALID_HOST_THREAD; +} + +bool +Host::ThreadCancel (lldb::thread_t thread, Error *error) +{ + + int err = ::pthread_cancel (thread); + if (error) + error->SetError(err, eErrorTypePOSIX); + return err == 0; +} + +bool +Host::ThreadDetach (lldb::thread_t thread, Error *error) +{ + int err = ::pthread_detach (thread); + if (error) + error->SetError(err, eErrorTypePOSIX); + return err == 0; +} + +bool +Host::ThreadJoin (lldb::thread_t thread, thread_result_t *thread_result_ptr, Error *error) +{ + int err = ::pthread_join (thread, thread_result_ptr); + if (error) + error->SetError(err, eErrorTypePOSIX); + return err == 0; +} + +void +Host::ThreadCreated (const char *thread_name) +{ + ::pthread_once (&g_thread_create_once, InitThreadCreated); + if (g_thread_create_key) + { + ::pthread_setspecific (g_thread_create_key, new MacOSXDarwinThread(thread_name)); + } +} + +//------------------------------------------------------------------ +// Control access to a static file thread name map using a single +// static function to avoid a static constructor. +//------------------------------------------------------------------ +static const char * +ThreadNameAccessor (bool get, lldb::pid_t pid, lldb::tid_t tid, const char *name) +{ + + uint64_t pid_tid = ((uint64_t)pid << 32) | (uint64_t)tid; + + static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; + Mutex::Locker locker(&g_mutex); + + typedef std::map<uint64_t, std::string> thread_name_map; + static thread_name_map g_thread_names; + + if (get) + { + // See if the thread name exists in our thread name pool + thread_name_map::iterator pos = g_thread_names.find(pid_tid); + if (pos != g_thread_names.end()) + return pos->second.c_str(); + } + else + { + // Set the thread name + g_thread_names[pid_tid] = name; + } + return NULL; +} + + + +const char * +Host::GetSignalAsCString (int signo) +{ + switch (signo) + { + case SIGHUP: return "SIGHUP"; // 1 hangup + case SIGINT: return "SIGINT"; // 2 interrupt + case SIGQUIT: return "SIGQUIT"; // 3 quit + case SIGILL: return "SIGILL"; // 4 illegal instruction (not reset when caught) + case SIGTRAP: return "SIGTRAP"; // 5 trace trap (not reset when caught) + case SIGABRT: return "SIGABRT"; // 6 abort() +#if defined(_POSIX_C_SOURCE) + case SIGPOLL: return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported) +#else // !_POSIX_C_SOURCE + case SIGEMT: return "SIGEMT"; // 7 EMT instruction +#endif // !_POSIX_C_SOURCE + case SIGFPE: return "SIGFPE"; // 8 floating point exception + case SIGKILL: return "SIGKILL"; // 9 kill (cannot be caught or ignored) + case SIGBUS: return "SIGBUS"; // 10 bus error + case SIGSEGV: return "SIGSEGV"; // 11 segmentation violation + case SIGSYS: return "SIGSYS"; // 12 bad argument to system call + case SIGPIPE: return "SIGPIPE"; // 13 write on a pipe with no one to read it + case SIGALRM: return "SIGALRM"; // 14 alarm clock + case SIGTERM: return "SIGTERM"; // 15 software termination signal from kill + case SIGURG: return "SIGURG"; // 16 urgent condition on IO channel + case SIGSTOP: return "SIGSTOP"; // 17 sendable stop signal not from tty + case SIGTSTP: return "SIGTSTP"; // 18 stop signal from tty + case SIGCONT: return "SIGCONT"; // 19 continue a stopped process + case SIGCHLD: return "SIGCHLD"; // 20 to parent on child stop or exit + case SIGTTIN: return "SIGTTIN"; // 21 to readers pgrp upon background tty read + case SIGTTOU: return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local<OSTOP) +#if !defined(_POSIX_C_SOURCE) + case SIGIO: return "SIGIO"; // 23 input/output possible signal +#endif + case SIGXCPU: return "SIGXCPU"; // 24 exceeded CPU time limit + case SIGXFSZ: return "SIGXFSZ"; // 25 exceeded file size limit + case SIGVTALRM: return "SIGVTALRM"; // 26 virtual time alarm + case SIGPROF: return "SIGPROF"; // 27 profiling time alarm +#if !defined(_POSIX_C_SOURCE) + case SIGWINCH: return "SIGWINCH"; // 28 window size changes + case SIGINFO: return "SIGINFO"; // 29 information request +#endif + case SIGUSR1: return "SIGUSR1"; // 30 user defined signal 1 + case SIGUSR2: return "SIGUSR2"; // 31 user defined signal 2 + default: + break; + } + return NULL; +} + +const char * +Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid) +{ + const char *name = ThreadNameAccessor (true, pid, tid, NULL); + if (name == NULL) + { + // We currently can only get the name of a thread in the current process. +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 + if (pid == Host::GetCurrentProcessID()) + { + char pthread_name[1024]; + if (::pthread_getname_np (::pthread_from_mach_thread_np (tid), pthread_name, sizeof(pthread_name)) == 0) + { + if (pthread_name[0]) + { + // Set the thread in our string pool + ThreadNameAccessor (false, pid, tid, pthread_name); + // Get our copy of the thread name string + name = ThreadNameAccessor (true, pid, tid, NULL); + } + } + } +#endif + } + return name; +} + +void +Host::SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name) +{ + lldb::pid_t curr_pid = Host::GetCurrentProcessID(); + lldb::tid_t curr_tid = Host::GetCurrentThreadID(); + if (pid == LLDB_INVALID_PROCESS_ID) + pid = curr_pid; + + if (tid == LLDB_INVALID_THREAD_ID) + tid = curr_tid; + +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5 + // Set the pthread name if possible + if (pid == curr_pid && tid == curr_tid) + { + ::pthread_setname_np (name) == 0; + } +#endif + ThreadNameAccessor (false, pid, tid, name); +} + +FileSpec +Host::GetProgramFileSpec () +{ + static FileSpec g_program_filepsec; + if (!g_program_filepsec) + { + std::string program_fullpath; + program_fullpath.resize (PATH_MAX); + // If DST is NULL, then return the number of bytes needed. + uint32_t len = program_fullpath.size(); + int err = _NSGetExecutablePath ((char *)program_fullpath.data(), &len); + if (err < 0) + { + // The path didn't fit in the buffer provided, increase its size + // and try again + program_fullpath.resize(len); + len = program_fullpath.size(); + err = _NSGetExecutablePath ((char *)program_fullpath.data(), &len); + } + if (err == 0) + g_program_filepsec.SetFile(program_fullpath.data()); + } + return g_program_filepsec; +} + + +FileSpec +Host::GetModuleFileSpecForHostAddress (const void *host_addr) +{ + FileSpec module_filespec; + Dl_info info; + if (::dladdr (host_addr, &info)) + { + if (info.dli_fname) + module_filespec.SetFile(info.dli_fname); + } + return module_filespec; +} + + +bool +Host::ResolveExecutableInBundle (FileSpec *file) +{ + 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); + return true; + } + } + } + } + return false; +} + +typedef struct MonitorInfo +{ + int handle; + pthread_t thread; + Host::MonitorChildProcessCallback callback; + void *callback_baton; + bool monitor_signals; +}; + +typedef std::multimap<lldb::pid_t, MonitorInfo> MonitorInfoMap; +static pthread_mutex_t g_monitor_map_mutex = PTHREAD_MUTEX_INITIALIZER; +typedef lldb::SharedPtr<MonitorInfoMap>::Type MonitorInfoMapSP; + +static MonitorInfoMapSP& +GetMonitorMap (bool can_create) +{ + static MonitorInfoMapSP g_monitor_map_sp; + if (can_create && g_monitor_map_sp.get() == NULL) + { + g_monitor_map_sp.reset (new MonitorInfoMap); + } + return g_monitor_map_sp; +} + +static Predicate<bool>& +GetChildProcessPredicate () +{ + static Predicate<bool> g_has_child_processes; + return g_has_child_processes; +} + +static void * +MonitorChildProcessThreadFunction (void *arg); + +static pthread_t g_monitor_thread; + +uint32_t +Host::StartMonitoringChildProcess +( + MonitorChildProcessCallback callback, + void *callback_baton, + lldb::pid_t pid, + bool monitor_signals +) +{ + static uint32_t g_handle = 0; + if (callback) + { + Mutex::Locker locker(&g_monitor_map_mutex); + if (!g_monitor_thread) + { + pid_t wait_pid = -1; + g_monitor_thread = ThreadCreate ("<lldb.host.wait4>", + MonitorChildProcessThreadFunction, + &wait_pid, + NULL); + if (g_monitor_thread) + { + //Host::ThreadDetach (g_monitor_thread, NULL); + } + } + + if (g_monitor_thread) + { + MonitorInfo info = { ++g_handle, 0, callback, callback_baton, monitor_signals }; + MonitorInfoMapSP monitor_map_sp (GetMonitorMap (true)); + if (monitor_map_sp) + { + monitor_map_sp->insert(std::make_pair(pid, info)); + GetChildProcessPredicate ().SetValue (true, eBroadcastOnChange); + return info.handle; + } + } + } + return 0; +} + +bool +Host::StopMonitoringChildProcess (uint32_t handle) +{ + Mutex::Locker locker(&g_monitor_map_mutex); + MonitorInfoMapSP monitor_map_sp (GetMonitorMap (false)); + if (monitor_map_sp) + { + MonitorInfoMap::iterator pos, end = monitor_map_sp->end(); + for (pos = monitor_map_sp->end(); pos != end; ++pos) + { + if (pos->second.handle == handle) + { + monitor_map_sp->erase(pos); + return true; + } + } + } + return false; +} + + +//------------------------------------------------------------------ +// Scoped class that will disable thread canceling when it is +// constructed, and exception safely restore the previous value it +// when it goes out of scope. +//------------------------------------------------------------------ +class ScopedPThreadCancelDisabler +{ +public: + + ScopedPThreadCancelDisabler() + { + // Disable the ability for this thread to be cancelled + int err = ::pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &m_old_state); + if (err != 0) + m_old_state = -1; + + } + + ~ScopedPThreadCancelDisabler() + { + // Restore the ability for this thread to be cancelled to what it + // previously was. + if (m_old_state != -1) + ::pthread_setcancelstate (m_old_state, 0); + } +private: + int m_old_state; // Save the old cancelability state. +}; + + + +static void * +MonitorChildProcessThreadFunction (void *arg) +{ + Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS); + const char *function = __FUNCTION__; + if (log) + log->Printf ("%s (arg = %p) thread starting...", function, arg); + + const pid_t wait_pid = -1;//*((pid_t*)arg); + int status = -1; + const int options = 0; + struct rusage *rusage = NULL; + while (1) + { + if (log) + log->Printf("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p)...", function, wait_pid, options, rusage); + + // Wait for all child processes + ::pthread_testcancel (); + lldb::pid_t pid = ::wait4 (wait_pid, &status, options, rusage); + ::pthread_testcancel (); + + if (pid < 0) + { + // No child processes to watch wait for the mutex to be cleared + + // Scope for "locker" + { + ScopedPThreadCancelDisabler pthread_cancel_disabler; + + // First clear out all monitor entries since we have no processes + // to watch. + Mutex::Locker locker(&g_monitor_map_mutex); + // Since we don't have any child processes, we can safely clear + // anyone with a valid pid. + MonitorInfoMapSP monitor_map_sp(GetMonitorMap (false)); + if (monitor_map_sp) + { + MonitorInfoMap::iterator pos = monitor_map_sp->begin(); + while (pos != monitor_map_sp->end()) + { + // pid value of 0 and -1 are special (see man page on wait4...) + if (pos->first > 0) + { + MonitorInfoMap::iterator next_pos = pos; ++next_pos; + monitor_map_sp->erase (pos, next_pos); + pos = next_pos; + } + else + ++pos; + } + } + } + + if (log) + log->Printf("%s no child processes, wait for some...", function); + GetChildProcessPredicate ().SetValue (false, eBroadcastNever); + ::pthread_testcancel(); + GetChildProcessPredicate ().WaitForValueEqualTo (true); + if (log) + log->Printf("%s resuming monitoring of child processes.", function); + + } + else + { + ScopedPThreadCancelDisabler pthread_cancel_disabler; + bool exited = false; + 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 ("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_state = %i", + function, + wait_pid, + options, + rusage, + pid, + status, + status_cstr, + signal, + exit_status); + + // Scope for mutex locker + { + // Notify anyone listening to this process + Mutex::Locker locker(&g_monitor_map_mutex); + MonitorInfoMapSP monitor_map_sp(GetMonitorMap (false)); + if (monitor_map_sp) + { + std::pair<MonitorInfoMap::iterator, MonitorInfoMap::iterator> range; + range = monitor_map_sp->equal_range(pid); + MonitorInfoMap::iterator pos; + for (pos = range.first; pos != range.second; ++pos) + { + if (exited || (signal != 0 && pos->second.monitor_signals)) + { + bool callback_return = pos->second.callback (pos->second.callback_baton, pid, signal, exit_status); + + if (exited || callback_return) + { + // Make this entry as needing to be removed by + // setting its handle to zero + pos->second.handle = 0; + } + } + } + + // Remove any entries that requested to be removed or any + // entries for child processes that did exit. We know this + // because we changed the handles to an invalid value. + pos = monitor_map_sp->begin(); + while (pos != monitor_map_sp->end()) + { + if (pos->second.handle == 0) + { + MonitorInfoMap::iterator next_pos = pos; ++next_pos; + monitor_map_sp->erase (pos, next_pos); + pos = next_pos; + } + else + ++pos; + } + } + } + } + } + + if (log) + log->Printf ("ProcessMacOSX::%s (arg = %p) thread exiting...", __FUNCTION__, arg); + + g_monitor_thread = NULL; + return NULL; +} + +void +Host::WillTerminate () +{ + if (g_monitor_thread != NULL) + { + ThreadCancel (g_monitor_thread, NULL); + GetChildProcessPredicate ().SetValue (true, eBroadcastAlways); + ThreadJoin(g_monitor_thread, NULL, NULL); + g_monitor_thread = NULL; + } +} + diff --git a/lldb/source/Host/macosx/Mutex.cpp b/lldb/source/Host/macosx/Mutex.cpp new file mode 100644 index 00000000000..ab0b67aa051 --- /dev/null +++ b/lldb/source/Host/macosx/Mutex.cpp @@ -0,0 +1,244 @@ +//===-- Mutex.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/Mutex.h" +#include "lldb/Core/Log.h" + +#if 0 +#include "lldb/Host/Host.h" +#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define DEBUG_LOG(fmt, ...) +#endif + +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Default constructor. +// +// This will create a scoped mutex locking object that doesn't have +// a mutex to lock. One will need to be provided using the Reset() +// method. +//---------------------------------------------------------------------- +Mutex::Locker::Locker () : + m_mutex_ptr(NULL) +{ +} + +//---------------------------------------------------------------------- +// Constructor with a Mutex object. +// +// This will create a scoped mutex locking object that extracts the +// mutex owned by "m" and locks it. +//---------------------------------------------------------------------- +Mutex::Locker::Locker (Mutex& m) : + m_mutex_ptr(m.GetMutex()) +{ + if (m_mutex_ptr) + Mutex::Lock (m_mutex_ptr); +} + +//---------------------------------------------------------------------- +// Constructor with a Mutex object pointer. +// +// This will create a scoped mutex locking object that extracts the +// mutex owned by "m" and locks it. +//---------------------------------------------------------------------- +Mutex::Locker::Locker (Mutex* m) : + m_mutex_ptr(m ? m->GetMutex() : NULL) +{ + if (m_mutex_ptr) + Mutex::Lock (m_mutex_ptr); +} + +//---------------------------------------------------------------------- +// Constructor with a raw pthread mutex object pointer. +// +// This will create a scoped mutex locking object that locks "mutex" +//---------------------------------------------------------------------- +Mutex::Locker::Locker (pthread_mutex_t *mutex_ptr) : + m_mutex_ptr(mutex_ptr) +{ + if (m_mutex_ptr) + Mutex::Lock (m_mutex_ptr); +} + +//---------------------------------------------------------------------- +// Desstructor +// +// Unlocks any owned mutex object (if it is valid). +//---------------------------------------------------------------------- +Mutex::Locker::~Locker () +{ + if (m_mutex_ptr) + Mutex::Unlock (m_mutex_ptr); +} + +//---------------------------------------------------------------------- +// Unlock the current mutex in this object (if this owns a valid +// mutex) and lock the new "mutex" object if it is non-NULL. +//---------------------------------------------------------------------- +void +Mutex::Locker::Reset (pthread_mutex_t *mutex_ptr) +{ + if (m_mutex_ptr) + Mutex::Unlock (m_mutex_ptr); + + m_mutex_ptr = mutex_ptr; + if (m_mutex_ptr) + Mutex::Lock (m_mutex_ptr); +} + +bool +Mutex::Locker::TryLock (pthread_mutex_t *mutex_ptr) +{ + if (m_mutex_ptr) + Mutex::Unlock (m_mutex_ptr); + m_mutex_ptr = NULL; + if (mutex_ptr) + { + if (Mutex::TryLock (mutex_ptr) == 0) + m_mutex_ptr = mutex_ptr; + } + return m_mutex_ptr != NULL; +} + +//---------------------------------------------------------------------- +// Default constructor. +// +// Creates a pthread mutex with no attributes. +//---------------------------------------------------------------------- +Mutex::Mutex () : + m_mutex() +{ + int err; + err = ::pthread_mutex_init (&m_mutex, NULL); + assert(err == 0); +} + +//---------------------------------------------------------------------- +// Default constructor. +// +// Creates a pthread mutex with "type" as the mutex type. +//---------------------------------------------------------------------- +Mutex::Mutex (Mutex::Type type) : + m_mutex() +{ + int err; + ::pthread_mutexattr_t attr; + err = ::pthread_mutexattr_init (&attr); + assert(err == 0); + switch (type) + { + case eMutexTypeNormal: + err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL); + break; + + case eMutexTypeRecursive: + err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); + break; + + default: + err = -1; + break; + } + assert(err == 0); + err = ::pthread_mutex_init (&m_mutex, &attr); + assert(err == 0); + err = ::pthread_mutexattr_destroy (&attr); + assert(err == 0); +} + +//---------------------------------------------------------------------- +// Destructor. +// +// Destroys the mutex owned by this object. +//---------------------------------------------------------------------- +Mutex::~Mutex() +{ + int err; + err = ::pthread_mutex_destroy (&m_mutex); +} + +//---------------------------------------------------------------------- +// Mutex get accessor. +//---------------------------------------------------------------------- +pthread_mutex_t * +Mutex::GetMutex() +{ + return &m_mutex; +} + +int +Mutex::Lock (pthread_mutex_t *mutex_ptr) +{ + DEBUG_LOG ("[%4.4x/%4.4x] pthread_mutex_lock (%p)...\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), mutex_ptr); + int err = ::pthread_mutex_lock (mutex_ptr); + DEBUG_LOG ("[%4.4x/%4.4x] pthread_mutex_lock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), mutex_ptr, err); + return err; +} + +int +Mutex::TryLock (pthread_mutex_t *mutex_ptr) +{ + int err = ::pthread_mutex_trylock (mutex_ptr); + DEBUG_LOG ("[%4.4x/%4.4x] pthread_mutex_trylock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), mutex_ptr, err); + return err; +} + +int +Mutex::Unlock (pthread_mutex_t *mutex_ptr) +{ + int err = ::pthread_mutex_unlock (mutex_ptr); + DEBUG_LOG ("[%4.4x/%4.4x] pthread_mutex_unlock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), mutex_ptr, err); + return err; +} + +//---------------------------------------------------------------------- +// Locks the mutex owned by this object, if the mutex is already +// locked, the calling thread will block until the mutex becomes +// available. +// +// RETURNS +// The error code from the pthread_mutex_lock() function call. +//---------------------------------------------------------------------- +int +Mutex::Lock() +{ + return Mutex::Lock (&m_mutex); +} + +//---------------------------------------------------------------------- +// Attempts to lock the mutex owned by this object without blocking. +// If the mutex is already locked, TryLock() will not block waiting +// for the mutex, but will return an error condition. +// +// RETURNS +// The error code from the pthread_mutex_trylock() function call. +//---------------------------------------------------------------------- +int +Mutex::TryLock() +{ + return Mutex::TryLock (&m_mutex); +} + +//---------------------------------------------------------------------- +// If the current thread holds the lock on the owned mutex, then +// Unlock() will unlock the mutex. Calling Unlock() on this object +// that the calling thread does not hold will result in undefined +// behavior. +// +// RETURNS +// The error code from the pthread_mutex_unlock() function call. +//---------------------------------------------------------------------- +int +Mutex::Unlock() +{ + return Mutex::Unlock (&m_mutex); +} diff --git a/lldb/source/Host/macosx/Symbols.cpp b/lldb/source/Host/macosx/Symbols.cpp new file mode 100644 index 00000000000..ff28157258b --- /dev/null +++ b/lldb/source/Host/macosx/Symbols.cpp @@ -0,0 +1,462 @@ +//===-- 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 <mach-o/loader.h> +#include <mach-o/fat.h> + +// C++ Includes +// Other libraries and framework includes +#include <CoreFoundation/CoreFoundation.h> + +// Project includes +#include "CFCReleaser.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/DataBuffer.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Timer.h" +#include "lldb/Core/UUID.h" + +using namespace lldb; +using namespace lldb_private; + +extern "C" { +CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url); +CFDictionaryRef DBGCopyDSYMPropertyLists (CFURLRef dsym_url); +}; + +static bool +SkinnyMachOFileContainsArchAndUUID +( + const FileSpec &file_spec, + const ArchSpec *arch, + const UUID *uuid, // the UUID we are looking for + off_t file_offset, + DataExtractor& data, + uint32_t data_offset, + const uint32_t magic +) +{ + assert(magic == MH_CIGAM || magic == MH_MAGIC || magic == MH_CIGAM_64 || magic == MH_MAGIC_64); + if (magic == MH_MAGIC || magic == MH_MAGIC_64) + data.SetByteOrder (eByteOrderHost); + else if (eByteOrderHost == eByteOrderBig) + data.SetByteOrder (eByteOrderLittle); + else + data.SetByteOrder (eByteOrderBig); + + uint32_t i; + const uint32_t cputype = data.GetU32(&data_offset); // cpu specifier + const uint32_t cpusubtype = data.GetU32(&data_offset); // machine specifier + data_offset+=4; // Skip mach file type + const uint32_t ncmds = data.GetU32(&data_offset); // number of load commands + const uint32_t sizeofcmds = data.GetU32(&data_offset); // the size of all the load commands + data_offset+=4; // Skip flags + + // Check the architecture if we have a valid arch pointer + if (arch) + { + ArchSpec file_arch(cputype, cpusubtype); + + if (file_arch != *arch) + return false; + } + + // The file exists, and if a valid arch pointer was passed in we know + // if already matches, so we can return if we aren't looking for a specific + // UUID + if (uuid == NULL) + return true; + + if (magic == MH_CIGAM_64 || magic == MH_MAGIC_64) + data_offset += 4; // Skip reserved field for in mach_header_64 + + // Make sure we have enough data for all the load commands + if (magic == MH_CIGAM_64 || magic == MH_MAGIC_64) + { + if (data.GetByteSize() < sizeof(struct mach_header_64) + sizeofcmds) + { + DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header_64) + sizeofcmds)); + data.SetData (data_buffer_sp); + } + } + else + { + if (data.GetByteSize() < sizeof(struct mach_header) + sizeofcmds) + { + DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, sizeof(struct mach_header) + sizeofcmds)); + data.SetData (data_buffer_sp); + } + } + + for (i=0; i<ncmds; i++) + { + const uint32_t cmd_offset = data_offset; // Save this data_offset in case parsing of the segment goes awry! + uint32_t cmd = data.GetU32(&data_offset); + uint32_t cmd_size = data.GetU32(&data_offset); + if (cmd == LC_UUID) + { + UUID file_uuid (data.GetData(&data_offset, 16), 16); + return file_uuid == *uuid; + } + data_offset = cmd_offset + cmd_size; + } + return false; +} + +bool +UniversalMachOFileContainsArchAndUUID +( + const FileSpec &file_spec, + const ArchSpec *arch, + const UUID *uuid, + off_t file_offset, + DataExtractor& data, + uint32_t data_offset, + const uint32_t magic +) +{ + assert(magic == FAT_CIGAM || magic == FAT_MAGIC); + + // Universal mach-o files always have their headers encoded as BIG endian + data.SetByteOrder(eByteOrderBig); + + uint32_t i; + const uint32_t nfat_arch = data.GetU32(&data_offset); // number of structs that follow + const uint32_t fat_header_and_arch_size = sizeof(struct fat_header) + nfat_arch * sizeof(struct fat_arch); + if (data.GetByteSize() < fat_header_and_arch_size) + { + DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, fat_header_and_arch_size)); + data.SetData (data_buffer_sp); + } + + for (i=0; i<nfat_arch; i++) + { + cpu_type_t arch_cputype = data.GetU32(&data_offset); // cpu specifier (int) + cpu_subtype_t arch_cpusubtype = data.GetU32(&data_offset); // machine specifier (int) + uint32_t arch_offset = data.GetU32(&data_offset); // file offset to this object file + // uint32_t arch_size = data.GetU32(&data_offset); // size of this object file + // uint32_t arch_align = data.GetU32(&data_offset); // alignment as a power of 2 + data_offset += 8; // Skip size and align as we don't need those + // Only process this slice if the cpu type/subtype matches + if (arch) + { + ArchSpec fat_arch(arch_cputype, arch_cpusubtype); + if (fat_arch != *arch) + continue; + } + + // Create a buffer with only the arch slice date in it + DataExtractor arch_data; + DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset + arch_offset, 0x1000)); + arch_data.SetData(data_buffer_sp); + uint32_t arch_data_offset = 0; + uint32_t arch_magic = arch_data.GetU32(&arch_data_offset); + + switch (arch_magic) + { + case MH_CIGAM: // 32 bit mach-o file + case MH_MAGIC: // 32 bit mach-o file + case MH_CIGAM_64: // 64 bit mach-o file + case MH_MAGIC_64: // 64 bit mach-o file + if (SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset + arch_offset, arch_data, arch_data_offset, arch_magic)) + return true; + break; + } + } + return false; +} + +static bool +FileAtPathContainsArchAndUUID +( + const FileSpec &file_spec, + const ArchSpec *arch, + const UUID *uuid +) +{ + DataExtractor data; + off_t file_offset = 0; + DataBufferSP data_buffer_sp (file_spec.ReadFileContents (file_offset, 0x1000)); + + if (data_buffer_sp && data_buffer_sp->GetByteSize() > 0) + { + data.SetData(data_buffer_sp); + + uint32_t data_offset = 0; + uint32_t magic = data.GetU32(&data_offset); + + switch (magic) + { + // 32 bit mach-o file + case MH_CIGAM: + case MH_MAGIC: + case MH_CIGAM_64: + case MH_MAGIC_64: + return SkinnyMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic); + + // fat mach-o file + case FAT_CIGAM: + case FAT_MAGIC: + return UniversalMachOFileContainsArchAndUUID (file_spec, arch, uuid, file_offset, data, data_offset, magic); + + default: + break; + } + } + return false; +} + +static FileSpec +LocateDSYMMachFileInDSYMBundle +( + const FileSpec& dsym_bundle_fspec, + const 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); + + DIR* dirp = ::opendir(path); + if (dirp != NULL) + { + const size_t path_len = strlen(path); + const int bytes_left = sizeof(path) - path_len - 1; + struct dirent* dp; + while ((dp = readdir(dirp)) != 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) + { + ::strncpy (&path[path_len], dp->d_name, bytes_left); + + dsym_fspec.SetFile(path); + if (FileAtPathContainsArchAndUUID (dsym_fspec, arch, uuid)) + return dsym_fspec; + } + } + } + } + dsym_fspec.Clear(); + return dsym_fspec; +} + +static int +LocateMacOSXFilesUsingDebugSymbols +( + const FileSpec *exec_fspec, // An executable path that may or may not be correct if UUID is specified + const ArchSpec* arch, // Limit the search to files with this architecture if non-NULL + const UUID *uuid, // Match the UUID value if non-NULL, + FileSpec *out_exec_fspec, // If non-NULL, try and find the executable + FileSpec *out_dsym_fspec // If non-NULL try and find the debug symbol file +) +{ + int items_found = 0; + + if (out_exec_fspec) + out_exec_fspec->Clear(); + + if (out_dsym_fspec) + out_dsym_fspec->Clear(); + + 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; + + 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 (out_dsym_fspec) + { + if (::CFURLGetFileSystemRepresentation (dsym_url.get(), true, (UInt8*)path, sizeof(path)-1)) + { + out_dsym_fspec->SetFile(path); + + if (out_dsym_fspec->GetFileType () == FileSpec::eFileTypeDirectory) + { + *out_dsym_fspec = LocateDSYMMachFileInDSYMBundle (*out_dsym_fspec, uuid, arch); + if (*out_dsym_fspec) + ++items_found; + } + else + { + ++items_found; + } + } + } + + if (out_exec_fspec) + { + CFCReleaser<CFDictionaryRef> dict(::DBGCopyDSYMPropertyLists (dsym_url.get()));; + if (dict.get()) + { + CFStringRef exec_cf_path = static_cast<CFStringRef>(::CFDictionaryGetValue (dict.get(), CFSTR("DBGSymbolRichExecutable"))); + if (exec_cf_path && ::CFStringGetFileSystemRepresentation (exec_cf_path, path, sizeof(path))) + { + ++items_found; + out_dsym_fspec->SetFile(path); + } + } + } + } + } + } + } + return items_found; +} + +static bool +LocateDSYMInVincinityOfExecutable (const FileSpec *exec_fspec, const ArchSpec* arch, const UUID *uuid, FileSpec &dsym_fspec) +{ + if (exec_fspec) + { + char path[PATH_MAX]; + if (exec_fspec->GetPath(path, sizeof(path))) + { + // Make sure the module isn't already just a dSYM file... + if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) + { + size_t obj_file_path_length = strlen(path); + strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path)); + strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path)); + + dsym_fspec.SetFile(path); + + if (FileAtPathContainsArchAndUUID (dsym_fspec, arch, uuid)) + { + return true; + } + else + { + path[obj_file_path_length] = '\0'; + + char *last_dot = strrchr(path, '.'); + while (last_dot != NULL && last_dot[0]) + { + char *next_slash = strchr(last_dot, '/'); + if (next_slash != NULL) + { + *next_slash = '\0'; + strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path)); + strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path)); + dsym_fspec.SetFile(path); + if (dsym_fspec.Exists()) + return true; + else + { + *last_dot = '\0'; + char *prev_slash = strrchr(path, '/'); + if (prev_slash != NULL) + *prev_slash = '\0'; + else + break; + } + } + else + { + break; + } + } + } + } + } + } + dsym_fspec.Clear(); + return false; +} + +FileSpec +Symbols::LocateExecutableObjectFile (const FileSpec *exec_fspec, const ArchSpec* arch, const UUID *uuid) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", + exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>", + arch ? arch->AsCString() : "<NULL>", + uuid); + + FileSpec objfile_fspec; + if (exec_fspec && FileAtPathContainsArchAndUUID (*exec_fspec, arch, uuid)) + objfile_fspec = *exec_fspec; + else + LocateMacOSXFilesUsingDebugSymbols (exec_fspec, arch, uuid, &objfile_fspec, NULL); + return objfile_fspec; +} + +FileSpec +Symbols::LocateExecutableSymbolFile (const FileSpec *exec_fspec, const ArchSpec* arch, const UUID *uuid) +{ + Timer scoped_timer (__PRETTY_FUNCTION__, + "LocateExecutableSymbolFile (file = %s, arch = %s, uuid = %p)", + exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>", + arch ? arch->AsCString() : "<NULL>", + uuid); + + FileSpec symbol_fspec; + // First try and find the dSYM in the same directory as the executable or in + // an appropriate parent directory + if (LocateDSYMInVincinityOfExecutable (exec_fspec, arch, uuid, symbol_fspec) == false) + { + // We failed to easily find the dSYM above, so use DebugSymbols + LocateMacOSXFilesUsingDebugSymbols (exec_fspec, arch, uuid, NULL, &symbol_fspec); + } + return symbol_fspec; +} diff --git a/lldb/source/Host/macosx/TimeValue.cpp b/lldb/source/Host/macosx/TimeValue.cpp new file mode 100644 index 00000000000..27aad5f7bc7 --- /dev/null +++ b/lldb/source/Host/macosx/TimeValue.cpp @@ -0,0 +1,179 @@ +//===-- TimeValue.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TimeValue.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +#define NSEC_PER_USEC 1000ull +#define USEC_PER_SEC 1000000ull +#define NSEC_PER_SEC 1000000000ull + +using namespace lldb_private; + +//---------------------------------------------------------------------- +// TimeValue constructor +//---------------------------------------------------------------------- +TimeValue::TimeValue() : + m_nano_seconds (0) +{ +} + +//---------------------------------------------------------------------- +// TimeValue copy constructor +//---------------------------------------------------------------------- +TimeValue::TimeValue(const TimeValue& rhs) : + m_nano_seconds (rhs.m_nano_seconds) +{ +} + +TimeValue::TimeValue(const struct timespec& ts) : + m_nano_seconds (ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec) +{ +} + +TimeValue::TimeValue(const struct timeval& tv) : + m_nano_seconds (tv.tv_sec * NSEC_PER_SEC + tv.tv_usec * NSEC_PER_USEC) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +TimeValue::~TimeValue() +{ +} + + +uint64_t +TimeValue::GetAsNanoSecondsSinceJan1_1970() const +{ + return m_nano_seconds; +} + +uint64_t +TimeValue::GetAsMicroSecondsSinceJan1_1970() const +{ + return m_nano_seconds / NSEC_PER_USEC; +} + +struct timespec +TimeValue::GetAsTimeSpec () const +{ + struct timespec ts; + ts.tv_sec = m_nano_seconds / NSEC_PER_SEC; + ts.tv_nsec = m_nano_seconds % NSEC_PER_SEC; + return ts; +} + +struct timeval +TimeValue::GetAsTimeVal () const +{ + struct timeval tv; + tv.tv_sec = m_nano_seconds / NSEC_PER_SEC; + tv.tv_usec = (m_nano_seconds % NSEC_PER_SEC) / NSEC_PER_USEC; + return tv; +} + +void +TimeValue::Clear () +{ + m_nano_seconds = 0; +} + +bool +TimeValue::IsValid () const +{ + return m_nano_seconds != 0; +} + +void +TimeValue::OffsetWithSeconds (uint32_t sec) +{ + m_nano_seconds += sec * NSEC_PER_SEC; +} + +void +TimeValue::OffsetWithMicroSeconds (uint32_t usec) +{ + m_nano_seconds += usec * NSEC_PER_USEC; +} + +void +TimeValue::OffsetWithNanoSeconds (uint32_t nsec) +{ + m_nano_seconds += nsec; +} + +TimeValue +TimeValue::Now() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + TimeValue now(tv); + return now; +} + +//---------------------------------------------------------------------- +// TimeValue assignment operator +//---------------------------------------------------------------------- +const TimeValue& +TimeValue::operator=(const TimeValue& rhs) +{ + m_nano_seconds = rhs.m_nano_seconds; + return *this; +} + + +bool +lldb_private::operator == (const TimeValue &lhs, const TimeValue &rhs) +{ + return lhs.GetAsNanoSecondsSinceJan1_1970() == rhs.GetAsNanoSecondsSinceJan1_1970(); +} + +bool +lldb_private::operator != (const TimeValue &lhs, const TimeValue &rhs) +{ + return lhs.GetAsNanoSecondsSinceJan1_1970() != rhs.GetAsNanoSecondsSinceJan1_1970(); +} + +bool +lldb_private::operator < (const TimeValue &lhs, const TimeValue &rhs) +{ + return lhs.GetAsNanoSecondsSinceJan1_1970() < rhs.GetAsNanoSecondsSinceJan1_1970(); +} + +bool +lldb_private::operator <= (const TimeValue &lhs, const TimeValue &rhs) +{ + return lhs.GetAsNanoSecondsSinceJan1_1970() <= rhs.GetAsNanoSecondsSinceJan1_1970(); +} + +bool +lldb_private::operator > (const TimeValue &lhs, const TimeValue &rhs) +{ + return lhs.GetAsNanoSecondsSinceJan1_1970() > rhs.GetAsNanoSecondsSinceJan1_1970(); +} + +bool +lldb_private::operator >= (const TimeValue &lhs, const TimeValue &rhs) +{ + return lhs.GetAsNanoSecondsSinceJan1_1970() >= rhs.GetAsNanoSecondsSinceJan1_1970(); +} + +uint64_t +lldb_private::operator - (const TimeValue &lhs, const TimeValue &rhs) +{ + return lhs.GetAsNanoSecondsSinceJan1_1970() - rhs.GetAsNanoSecondsSinceJan1_1970(); +} + + diff --git a/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp b/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp new file mode 100644 index 00000000000..6e68af5c597 --- /dev/null +++ b/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp @@ -0,0 +1,83 @@ +//===-- 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; +} + +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/lldb/source/Host/macosx/cfcpp/CFCBundle.h b/lldb/source/Host/macosx/cfcpp/CFCBundle.h new file mode 100644 index 00000000000..c07a48cb055 --- /dev/null +++ b/lldb/source/Host/macosx/cfcpp/CFCBundle.h @@ -0,0 +1,47 @@ +//===-- 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 + 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/lldb/source/Host/macosx/cfcpp/CFCData.cpp b/lldb/source/Host/macosx/cfcpp/CFCData.cpp new file mode 100644 index 00000000000..4f49368ad8a --- /dev/null +++ b/lldb/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/lldb/source/Host/macosx/cfcpp/CFCData.h b/lldb/source/Host/macosx/cfcpp/CFCData.h new file mode 100644 index 00000000000..6a718f54c05 --- /dev/null +++ b/lldb/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/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp b/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp new file mode 100644 index 00000000000..3b92f03fa61 --- /dev/null +++ b/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp @@ -0,0 +1,123 @@ +//===-- 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" + +//---------------------------------------------------------------------- +// 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; +} diff --git a/lldb/source/Host/macosx/cfcpp/CFCMutableArray.h b/lldb/source/Host/macosx/cfcpp/CFCMutableArray.h new file mode 100644 index 00000000000..eaadb8d5590 --- /dev/null +++ b/lldb/source/Host/macosx/cfcpp/CFCMutableArray.h @@ -0,0 +1,34 @@ +//===-- 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 +}; + +#endif // #ifndef CoreFoundationCPP_CFMutableArray_h_ diff --git a/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp b/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp new file mode 100644 index 00000000000..963221adb4a --- /dev/null +++ b/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp @@ -0,0 +1,491 @@ +//===-- 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::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/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.h b/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.h new file mode 100644 index 00000000000..de32ead3103 --- /dev/null +++ b/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.h @@ -0,0 +1,77 @@ +//===-- 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 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/lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp b/lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp new file mode 100644 index 00000000000..cd253704e2d --- /dev/null +++ b/lldb/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 false; + 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/lldb/source/Host/macosx/cfcpp/CFCMutableSet.h b/lldb/source/Host/macosx/cfcpp/CFCMutableSet.h new file mode 100644 index 00000000000..78f7a8be81d --- /dev/null +++ b/lldb/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/lldb/source/Host/macosx/cfcpp/CFCReleaser.h b/lldb/source/Host/macosx/cfcpp/CFCReleaser.h new file mode 100644 index 00000000000..cd35de6d665 --- /dev/null +++ b/lldb/source/Host/macosx/cfcpp/CFCReleaser.h @@ -0,0 +1,155 @@ +//===-- 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 ownwership 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. + //---------------------------------------------------------- + T* + ptr_address() + { + 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/lldb/source/Host/macosx/cfcpp/CFCString.cpp b/lldb/source/Host/macosx/cfcpp/CFCString.cpp new file mode 100644 index 00000000000..81a96b82499 --- /dev/null +++ b/lldb/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/lldb/source/Host/macosx/cfcpp/CFCString.h b/lldb/source/Host/macosx/cfcpp/CFCString.h new file mode 100644 index 00000000000..521d2c0a51b --- /dev/null +++ b/lldb/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); + 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/lldb/source/Host/macosx/cfcpp/CoreFoundationCPP.h b/lldb/source/Host/macosx/cfcpp/CoreFoundationCPP.h new file mode 100644 index 00000000000..6843e2649cd --- /dev/null +++ b/lldb/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_ |