summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp')
-rw-r--r--lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp769
1 files changed, 769 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp b/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp
new file mode 100644
index 00000000000..46d84a853d0
--- /dev/null
+++ b/lldb/source/Plugins/Process/MacOSX-User/source/ThreadMacOSX.cpp
@@ -0,0 +1,769 @@
+//===-- ThreadMacOSX.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadMacOSX.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessMacOSX.h"
+#include "ProcessMacOSXLog.h"
+#include "MachThreadContext.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Breakpoint/WatchpointLocation.h"
+#include "lldb/Core/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadMacOSX::ThreadMacOSX (ProcessMacOSX &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_fp_pc_pairs(),
+ m_basic_info(),
+ m_suspend_count(0),
+ m_stop_exception(),
+ m_context()
+{
+ ProcessMacOSX::CreateArchCalback create_arch_callback = process.GetArchCreateCallback();
+ assert(create_arch_callback != NULL);
+ m_context.reset(create_arch_callback(process.GetArchSpec(), *this));
+ assert(m_context.get() != NULL);
+ m_context->InitializeInstance();
+ ::bzero (&m_basic_info, sizeof (m_basic_info));
+ ::bzero (&m_ident_info, sizeof (m_ident_info));
+ ::bzero (&m_proc_threadinfo, sizeof (m_proc_threadinfo));
+ ProcessMacOSXLog::LogIf(PD_LOG_THREAD | PD_LOG_VERBOSE, "ThreadMacOSX::ThreadMacOSX ( pid = %i, tid = 0x%4.4x, )", m_process.GetID(), GetID());
+}
+
+ThreadMacOSX::~ThreadMacOSX ()
+{
+}
+
+#if defined (__i386__) || defined (__x86_64__)
+ #define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_I386_BPT
+ #define MACH_TRAP_DATA_0 EXC_I386_SGL
+#elif defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
+ #define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_PPC_BREAKPOINT
+
+#elif defined (__arm__)
+ #define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_ARM_BREAKPOINT
+#endif
+
+
+bool
+ThreadMacOSX::GetRawStopReason (Thread::StopInfo *stop_info )
+{
+ stop_info->SetThread(this);
+
+ bool success = GetStopException().GetStopInfo(stop_info);
+
+
+#if defined (MACH_SOFTWARE_BREAKPOINT_DATA_0) || defined (MACH_TRAP_DATA_0)
+ if (stop_info->GetStopReason() == eStopReasonException)
+ {
+ if (stop_info->GetExceptionType() == EXC_BREAKPOINT && stop_info->GetExceptionDataCount() == 2)
+ {
+ const lldb::addr_t data_0 = stop_info->GetExceptionDataAtIndex(0);
+#if defined (MACH_SOFTWARE_BREAKPOINT_DATA_0)
+ if (data_0 == MACH_SOFTWARE_BREAKPOINT_DATA_0)
+ {
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ lldb::user_id_t break_id = m_process.GetBreakpointSiteList().FindIDByAddress(pc);
+ if (break_id != LLDB_INVALID_BREAK_ID)
+ {
+ stop_info->Clear ();
+ stop_info->SetStopReasonWithBreakpointSiteID (break_id);
+ return success;
+ }
+ }
+#endif
+#if defined (MACH_TRAP_DATA_0)
+ if (data_0 == MACH_TRAP_DATA_0)
+ {
+ stop_info->Clear ();
+ stop_info->SetStopReasonToTrace ();
+ return success;
+ }
+#endif
+ }
+ }
+#endif
+
+ if (stop_info->GetStopReason() == eStopReasonException)
+ {
+ if (stop_info->GetExceptionType() == EXC_SOFTWARE &&
+ stop_info->GetExceptionDataCount() == 2 &&
+ stop_info->GetExceptionDataAtIndex(0) == EXC_SOFT_SIGNAL)
+ {
+ int signo = stop_info->GetExceptionDataAtIndex(1);
+ stop_info->Clear ();
+ stop_info->SetStopReasonWithSignal (signo);
+ }
+ }
+ else
+ {
+ stop_info->SetStopReasonToNone();
+ }
+
+ return success;
+}
+
+const char *
+ThreadMacOSX::GetInfo ()
+{
+ return GetBasicInfoAsString();
+}
+
+bool
+ThreadMacOSX::GetIdentifierInfo ()
+{
+#ifdef THREAD_IDENTIFIER_INFO_COUNT
+ if (m_ident_info.thread_id == 0)
+ {
+ mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
+ return ::thread_info (GetID(), THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count) == KERN_SUCCESS;
+ }
+#else
+ //m_error.SetErrorString("Thread_info doesn't support THREAD_IDENTIFIER_INFO.");
+#endif
+
+ return false;
+}
+
+const char *
+ThreadMacOSX::GetDispatchQueueName()
+{
+ if (GetIdentifierInfo ())
+ {
+ if (m_ident_info.dispatch_qaddr == 0)
+ return NULL;
+
+ uint8_t memory_buffer[8];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer), m_process.GetByteOrder(), m_process.GetAddressByteSize());
+ ModuleSP module_sp(m_process.GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib")));
+ if (module_sp.get() == NULL)
+ return NULL;
+
+ lldb::addr_t dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
+ const Symbol *dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (ConstString("dispatch_queue_offsets"), eSymbolTypeData);
+ if (dispatch_queue_offsets_symbol)
+ dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(&GetProcess());
+
+ if (dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ return NULL;
+
+ // Excerpt from src/queue_private.h
+ struct dispatch_queue_offsets_s
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label;
+ uint16_t dqo_label_size;
+ } dispatch_queue_offsets;
+
+ Error error;
+ if (m_process.ReadMemory (dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets), error) == sizeof(dispatch_queue_offsets))
+ {
+ uint32_t data_offset = 0;
+ if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t)))
+ {
+ if (m_process.ReadMemory (m_ident_info.dispatch_qaddr, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize())
+ {
+ data_offset = 0;
+ lldb::addr_t queue_addr = data.GetAddress(&data_offset);
+ lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label;
+ const size_t chunk_size = 32;
+ uint32_t label_pos = 0;
+ m_dispatch_queue_name.resize(chunk_size, '\0');
+ while (1)
+ {
+ size_t bytes_read = m_process.ReadMemory (label_addr + label_pos, &m_dispatch_queue_name[label_pos], chunk_size, error);
+
+ if (bytes_read <= 0)
+ break;
+
+ if (m_dispatch_queue_name.find('\0', label_pos) != std::string::npos)
+ break;
+ label_pos += bytes_read;
+ }
+ m_dispatch_queue_name.erase(m_dispatch_queue_name.find('\0'));
+ }
+ }
+ }
+ }
+
+ if (m_dispatch_queue_name.empty())
+ return NULL;
+ return m_dispatch_queue_name.c_str();
+}
+
+const char *
+ThreadMacOSX::GetName ()
+{
+ if (GetIdentifierInfo ())
+ ::proc_pidinfo (m_process.GetID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
+
+ // No thread name, lets return the queue name instead
+ if (m_proc_threadinfo.pth_name[0] == '\0')
+ return GetDispatchQueueName();
+
+ // Return the thread name if there was one
+ if (m_proc_threadinfo.pth_name[0])
+ return m_proc_threadinfo.pth_name;
+ return NULL;
+}
+
+bool
+ThreadMacOSX::WillResume (StateType resume_state)
+{
+ ThreadWillResume(resume_state);
+ Thread::WillResume(resume_state);
+ return true;
+}
+
+void
+ThreadMacOSX::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context
+ GetRegisterContext()->Invalidate();
+
+ m_context->RefreshStateAfterStop();
+
+ // We may have suspended this thread so the primary thread could step
+ // without worrying about race conditions, so lets restore our suspend
+ // count.
+ RestoreSuspendCount();
+
+ // Update the basic information for a thread for suspend count reasons.
+ ThreadMacOSX::GetBasicInfo(GetID(), &m_basic_info);
+ m_suspend_count = m_basic_info.suspend_count;
+ m_basic_info_string.clear();
+}
+
+uint32_t
+ThreadMacOSX::GetStackFrameCount()
+{
+ if (m_fp_pc_pairs.empty())
+ GetStackFrameData(m_fp_pc_pairs);
+ return m_fp_pc_pairs.size();
+}
+
+// Make sure that GetStackFrameAtIndex() does NOT call GetStackFrameCount() when
+// getting the stack frame at index zero! This way GetStackFrameCount() (via
+// GetStackFRameData()) can call this function to get the first frame in order
+// to provide the first frame to a lower call for efficiency sake (avoid
+// redundant lookups in the frame symbol context).
+lldb::StackFrameSP
+ThreadMacOSX::GetStackFrameAtIndex (uint32_t idx)
+{
+ StackFrameSP frame_sp(m_frames.GetFrameAtIndex(idx));
+
+ if (frame_sp)
+ return frame_sp;
+
+ // Don't try and fetch a frame while process is running
+ // Calling IsRunning isn't right here, because IsRunning reads the Public
+ // state but we need to be able to read the stack frames in the ShouldStop
+ // methods, which happen before the Public state has been updated.
+// if (m_process.IsRunning())
+// return frame_sp;
+
+ // Special case the first frame (idx == 0) so that we don't need to
+ // know how many stack frames there are to get it. If we need any other
+ // frames, then we do need to know if "idx" is a valid index.
+ if (idx == 0)
+ {
+ // If this is the first frame, we want to share the thread register
+ // context with the stack frame at index zero.
+ GetRegisterContext();
+ assert (m_reg_context_sp.get());
+ frame_sp.reset (new StackFrame (idx, *this, m_reg_context_sp, m_reg_context_sp->GetFP(), m_reg_context_sp->GetPC()));
+ }
+ else if (idx < GetStackFrameCount())
+ {
+ assert (idx < m_fp_pc_pairs.size());
+ frame_sp.reset (new StackFrame (idx, *this, m_fp_pc_pairs[idx].first, m_fp_pc_pairs[idx].second));
+ }
+ m_frames.SetFrameAtIndex(idx, frame_sp);
+ return frame_sp;
+}
+
+void
+ThreadMacOSX::ClearStackFrames ()
+{
+ m_fp_pc_pairs.clear();
+ Thread::ClearStackFrames();
+}
+
+
+
+int32_t
+ThreadMacOSX::Suspend()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ThreadMacOSX::%s ( )", __FUNCTION__);
+ lldb::tid_t tid = GetID ();
+ if (ThreadIDIsValid(tid))
+ {
+ Error err(::thread_suspend (tid), eErrorTypeMachKernel);
+ if (err.Success())
+ m_suspend_count++;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_suspend (%4.4x)", tid);
+ }
+ return GetSuspendCount();
+}
+
+int32_t
+ThreadMacOSX::Resume()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ThreadMacOSX::%s ()", __FUNCTION__);
+ lldb::tid_t tid = GetID ();
+ if (ThreadIDIsValid(tid))
+ {
+ while (m_suspend_count > 0)
+ {
+ Error err(::thread_resume (tid), eErrorTypeMachKernel);
+ if (err.Success())
+ m_suspend_count--;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_resume (%4.4x)", tid);
+ }
+ }
+ return GetSuspendCount();
+}
+
+bool
+ThreadMacOSX::RestoreSuspendCount()
+{
+ Log *log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
+ if (log && log->GetMask().IsSet(PD_LOG_VERBOSE))
+ log->Printf ("ThreadMacOSX::%s ( )", __FUNCTION__);
+ Error err;
+ lldb::tid_t tid = GetID ();
+ if (ThreadIDIsValid(tid) == false)
+ return false;
+ else if (m_suspend_count > m_basic_info.suspend_count)
+ {
+ while (m_suspend_count > m_basic_info.suspend_count)
+ {
+ err = ::thread_resume (tid);
+ if (err.Success())
+ --m_suspend_count;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_resume (%4.4x)", tid);
+ }
+ }
+ else if (m_suspend_count < m_basic_info.suspend_count)
+ {
+ while (m_suspend_count < m_basic_info.suspend_count)
+ {
+ err = ::thread_suspend (tid);
+ if (err.Success())
+ --m_suspend_count;
+ if (log || err.Fail())
+ err.PutToLog(log, "::thread_suspend (%4.4x)", tid);
+ }
+ }
+ return m_suspend_count == m_basic_info.suspend_count;
+}
+
+
+const char *
+ThreadMacOSX::GetBasicInfoAsString ()
+{
+ if (m_basic_info_string.empty())
+ {
+ StreamString sstr;
+ struct thread_basic_info basicInfo;
+
+ lldb::tid_t tid = GetID ();
+ if (GetBasicInfo(tid, &basicInfo))
+ {
+// char run_state_str[32];
+// size_t run_state_str_size = sizeof(run_state_str);
+// switch (basicInfo.run_state)
+// {
+// case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break;
+// case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break;
+// case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break;
+// case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
+// case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break;
+// default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ???
+// }
+ float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
+ float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
+ sstr.Printf("Thread 0x%4.4x: user=%f system=%f cpu=%d sleep_time=%d",
+ InferiorThreadID(),
+ user,
+ system,
+ basicInfo.cpu_usage,
+ basicInfo.sleep_time);
+ m_basic_info_string.assign (sstr.GetData(), sstr.GetSize());
+ }
+ }
+ if (m_basic_info_string.empty())
+ return NULL;
+ return m_basic_info_string.c_str();
+}
+
+
+//const uint8_t *
+//ThreadMacOSX::SoftwareBreakpointOpcode (size_t break_op_size) const
+//{
+// return m_context->SoftwareBreakpointOpcode(break_op_size);
+//}
+
+
+lldb::tid_t
+ThreadMacOSX::InferiorThreadID() const
+{
+ mach_msg_type_number_t i;
+ mach_port_name_array_t names;
+ mach_port_type_array_t types;
+ mach_msg_type_number_t ncount, tcount;
+ lldb::tid_t inferior_tid = LLDB_INVALID_THREAD_ID;
+ task_t my_task = ::mach_task_self();
+ task_t task = GetMacOSXProcess().Task().GetTaskPort();
+
+ kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
+ if (kret == KERN_SUCCESS)
+ {
+ lldb::tid_t tid = GetID ();
+
+ for (i = 0; i < ncount; i++)
+ {
+ mach_port_t my_name;
+ mach_msg_type_name_t my_type;
+
+ kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
+ if (kret == KERN_SUCCESS)
+ {
+ ::mach_port_deallocate (my_task, my_name);
+ if (my_name == tid)
+ {
+ inferior_tid = names[i];
+ break;
+ }
+ }
+ }
+ // Free up the names and types
+ ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
+ ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
+ }
+ return inferior_tid;
+}
+
+bool
+ThreadMacOSX::GetBasicInfo(lldb::tid_t thread, struct thread_basic_info *basicInfoPtr)
+{
+ if (ThreadIDIsValid(thread))
+ {
+ unsigned int info_count = THREAD_BASIC_INFO_COUNT;
+ kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
+ if (err == KERN_SUCCESS)
+ return true;
+ }
+ ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
+ return false;
+}
+
+
+bool
+ThreadMacOSX::ThreadIDIsValid (lldb::tid_t thread)
+{
+ return thread != 0;
+}
+
+void
+ThreadMacOSX::Dump(Log *log, uint32_t index)
+{
+ const char * thread_run_state = NULL;
+
+ switch (m_basic_info.run_state)
+ {
+ case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally
+ case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped
+ case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally
+ case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait
+ case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a
+ default: thread_run_state = "???"; break;
+ }
+
+ RegisterContext *reg_context = GetRegisterContext();
+ log->Printf ("thread[%u] %4.4x (%u): pc: 0x%8.8llx sp: 0x%8.8llx breakID: %d user: %d.%06.6d system: %d.%06.6d cpu: %d policy: %d run_state: %d (%s) flags: %d suspend_count: %d (current %d) sleep_time: %d",
+ index,
+ GetID (),
+ reg_context->GetPC (LLDB_INVALID_ADDRESS),
+ reg_context->GetSP (LLDB_INVALID_ADDRESS),
+ m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds,
+ m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds,
+ m_basic_info.cpu_usage,
+ m_basic_info.policy,
+ m_basic_info.run_state,
+ thread_run_state,
+ m_basic_info.flags,
+ m_basic_info.suspend_count, m_suspend_count,
+ m_basic_info.sleep_time);
+ //DumpRegisterState(0);
+}
+
+void
+ThreadMacOSX::ThreadWillResume (StateType resume_state)
+{
+ // Update the thread state to be the state we wanted when the task resumes
+ SetState (resume_state);
+ switch (resume_state)
+ {
+ case eStateSuspended:
+ Suspend();
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ Resume();
+ break;
+ }
+ m_context->ThreadWillResume();
+}
+
+void
+ThreadMacOSX::DidResume ()
+{
+ // TODO: cache current stack frames for next time in case we can match things up??
+ ClearStackFrames();
+ m_stop_exception.Clear();
+ Thread::DidResume();
+}
+
+bool
+ThreadMacOSX::ShouldStop(bool &step_more)
+{
+// TODO: REmove this after all is working, Process should be managing this
+// for us.
+//
+// // See if this thread is at a breakpoint?
+// lldb::user_id_t breakID = CurrentBreakpoint();
+//
+// if (LLDB_BREAK_ID_IS_VALID(breakID))
+// {
+// // This thread is sitting at a breakpoint, ask the breakpoint
+// // if we should be stopping here.
+// if (Process()->Breakpoints().ShouldStop(ProcessID(), ThreadID(), breakID))
+// return true;
+// else
+// {
+// // The breakpoint said we shouldn't stop, but we may have gotten
+// // a signal or the user may have requested to stop in some other
+// // way. Stop if we have a valid exception (this thread won't if
+// // another thread was the reason this process stopped) and that
+// // exception, is NOT a breakpoint exception (a common case would
+// // be a SIGINT signal).
+// if (GetStopException().IsValid() && !GetStopException().IsBreakpoint())
+// return true;
+// }
+// }
+// else
+// {
+ if (m_context->StepNotComplete())
+ {
+ step_more = true;
+ return false;
+ }
+// // The thread state is used to let us know what the thread was
+// // trying to do. ThreadMacOSX::ThreadWillResume() will set the
+// // thread state to various values depending if the thread was
+// // the current thread and if it was to be single stepped, or
+// // resumed.
+// if (GetState() == eStateRunning)
+// {
+// // If our state is running, then we should continue as we are in
+// // the process of stepping over a breakpoint.
+// return false;
+// }
+// else
+// {
+// // Stop if we have any kind of valid exception for this
+// // thread.
+// if (GetStopException().IsValid())
+// return true;
+// }
+// }
+// return false;
+ return true;
+}
+
+bool
+ThreadMacOSX::NotifyException(MachException::Data& exc)
+{
+ if (m_stop_exception.IsValid())
+ {
+ // We may have more than one exception for a thread, but we need to
+ // only remember the one that we will say is the reason we stopped.
+ // We may have been single stepping and also gotten a signal exception,
+ // so just remember the most pertinent one.
+ if (m_stop_exception.IsBreakpoint())
+ m_stop_exception = exc;
+ }
+ else
+ {
+ m_stop_exception = exc;
+ }
+// bool handled =
+ m_context->NotifyException(exc);
+// if (!handled)
+// {
+// handled = true;
+// lldb::addr_t pc = GetPC();
+// lldb::user_id_t breakID = m_process.Breakpoints().FindIDCyAddress(pc);
+// SetCurrentBreakpoint(breakID);
+// switch (exc.exc_type)
+// {
+// case EXC_BAD_ACCESS:
+// break;
+// case EXC_BAD_INSTRUCTION:
+// break;
+// case EXC_ARITHMETIC:
+// break;
+// case EXC_EMULATION:
+// break;
+// case EXC_SOFTWARE:
+// break;
+// case EXC_BREAKPOINT:
+// break;
+// case EXC_SYSCALL:
+// break;
+// case EXC_MACH_SYSCALL:
+// break;
+// case EXC_RPC_ALERT:
+// break;
+// }
+// }
+// return handled;
+ return true;
+}
+
+RegisterContext *
+ThreadMacOSX::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp.reset (CreateRegisterContextForFrame (NULL));
+ return m_reg_context_sp.get();
+}
+
+RegisterContext *
+ThreadMacOSX::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ return m_context->CreateRegisterContext (frame);
+}
+
+uint32_t
+ThreadMacOSX::SetHardwareBreakpoint (const BreakpointSite *bp)
+{
+ if (bp != NULL)
+ return GetRegisterContext()->SetHardwareBreakpoint(bp->GetLoadAddress(), bp->GetByteSize());
+ return LLDB_INVALID_INDEX32;
+}
+
+uint32_t
+ThreadMacOSX::SetHardwareWatchpoint (const WatchpointLocation *wp)
+{
+ if (wp != NULL)
+ return GetRegisterContext()->SetHardwareWatchpoint(wp->GetLoadAddress(), wp->GetByteSize(), wp->WatchpointRead(), wp->WatchpointWrite());
+ return LLDB_INVALID_INDEX32;
+}
+
+
+bool
+ThreadMacOSX::SaveFrameZeroState (RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ checkpoint.SetStackID(frame_sp->GetStackID());
+ return frame_sp->GetRegisterContext()->ReadAllRegisterValues (checkpoint.GetData());
+ }
+ return false;
+}
+
+bool
+ThreadMacOSX::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ bool ret = frame_sp->GetRegisterContext()->WriteAllRegisterValues (checkpoint.GetData());
+
+ // Clear out all stack frames as our world just changed.
+ ClearStackFrames();
+ frame_sp->GetRegisterContext()->Invalidate();
+
+ return ret;
+ }
+ return false;
+}
+
+bool
+ThreadMacOSX::ClearHardwareBreakpoint (const BreakpointSite *bp)
+{
+ if (bp != NULL && bp->IsHardware())
+ return GetRegisterContext()->ClearHardwareBreakpoint(bp->GetHardwareIndex());
+ return false;
+}
+
+bool
+ThreadMacOSX::ClearHardwareWatchpoint (const WatchpointLocation *wp)
+{
+ if (wp != NULL && wp->IsHardware())
+ return GetRegisterContext()->ClearHardwareWatchpoint(wp->GetHardwareIndex());
+ return false;
+}
+
+size_t
+ThreadMacOSX::GetStackFrameData(std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ return m_context->GetStackFrameData(frame_sp.get(), fp_pc_pairs);
+}
+
+
+//void
+//ThreadMacOSX::NotifyBreakpointChanged (const BreakpointSite *bp)
+//{
+// if (bp)
+// {
+// lldb::user_id_t breakID = bp->GetID();
+// if (bp->IsEnabled())
+// {
+// if (bp->Address() == GetPC())
+// {
+// SetCurrentBreakpoint(breakID);
+// }
+// }
+// else
+// {
+// if (CurrentBreakpoint() == breakID)
+// {
+// SetCurrentBreakpoint(LLDB_INVALID_BREAK_ID);
+// }
+// }
+// }
+//}
+//
+
+
OpenPOWER on IntegriCloud