don't crash if we disable logging when some code already has a copy of the logger. Prior to this fix, logs were handed out as pointers and if they were held onto while a log got disabled, then it could cause a crash. Now all logs are handed out as shared pointers so this problem shouldn't happen anymore. We are also using our new shared pointers that put the shared pointer count and the object into the same allocation for a tad better performance. llvm-svn: 118319
710 lines
23 KiB
C++
710 lines
23 KiB
C++
//===-- 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/StopInfo.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"
|
|
#include "lldb/Target/Unwind.h"
|
|
#include "LibUnwindRegisterContext.h"
|
|
#include "UnwindLibUnwind.h"
|
|
#include "UnwindMacOSXFrameBackchain.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
|
|
|
|
|
|
StopInfoSP
|
|
ThreadMacOSX::GetPrivateStopReason ()
|
|
{
|
|
if (m_actual_stop_info_sp.get() == NULL || m_actual_stop_info_sp->IsValid() == false)
|
|
m_actual_stop_info_sp = GetStopException().GetStopInfo(*this);
|
|
return m_actual_stop_info_sp;
|
|
}
|
|
|
|
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];
|
|
addr_t dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
|
|
DataExtractor data(memory_buffer, sizeof(memory_buffer), m_process.GetByteOrder(), m_process.GetAddressByteSize());
|
|
static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
|
|
const Symbol *dispatch_queue_offsets_symbol = NULL;
|
|
ModuleSP module_sp(m_process.GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib", false)));
|
|
if (module_sp)
|
|
dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
|
|
|
|
if (dispatch_queue_offsets_symbol == NULL)
|
|
{
|
|
module_sp = m_process.GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libdispatch.dylib", false));
|
|
if (module_sp)
|
|
dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
|
|
}
|
|
if (dispatch_queue_offsets_symbol)
|
|
dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(&m_process.GetTarget());
|
|
|
|
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();
|
|
}
|
|
|
|
Unwind *
|
|
ThreadMacOSX::GetUnwinder ()
|
|
{
|
|
if (m_unwinder_ap.get() == NULL)
|
|
{
|
|
const ArchSpec target_arch (GetProcess().GetTarget().GetArchitecture ());
|
|
#if 0 // Not sure this is the right thing to do for native, but this will all go away with Jason's new
|
|
// unwinder anyway...
|
|
if (target_arch == ArchSpec("x86_64") || target_arch == ArchSpec("i386"))
|
|
{
|
|
m_unwinder_ap.reset (new UnwindLibUnwind (*this, GetGDBProcess().GetLibUnwindAddressSpace()));
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
m_unwinder_ap.reset (new UnwindMacOSXFrameBackchain (*this));
|
|
}
|
|
}
|
|
return m_unwinder_ap.get();
|
|
}
|
|
|
|
|
|
void
|
|
ThreadMacOSX::ClearStackFrames ()
|
|
{
|
|
m_fp_pc_pairs.clear();
|
|
Thread::ClearStackFrames();
|
|
}
|
|
|
|
|
|
|
|
int32_t
|
|
ThreadMacOSX::Suspend()
|
|
{
|
|
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD));
|
|
if (log && log->GetMask().Test(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++;
|
|
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
|
|
if (log || err.Fail())
|
|
err.PutToLog(log.get(), "::thread_suspend (%4.4x)", tid);
|
|
}
|
|
return GetSuspendCount();
|
|
}
|
|
|
|
int32_t
|
|
ThreadMacOSX::Resume()
|
|
{
|
|
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD));
|
|
if (log && log->GetMask().Test(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--;
|
|
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
|
|
if (log || err.Fail())
|
|
err.PutToLog(log.get(), "::thread_resume (%4.4x)", tid);
|
|
}
|
|
}
|
|
return GetSuspendCount();
|
|
}
|
|
|
|
bool
|
|
ThreadMacOSX::RestoreSuspendCount()
|
|
{
|
|
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD));
|
|
if (log && log->GetMask().Test(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;
|
|
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
|
|
if (log || err.Fail())
|
|
err.PutToLog(log.get(), "::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;
|
|
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
|
|
if (log || err.Fail())
|
|
err.PutToLog(log.get(), "::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);
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
//
|
|
|
|
|