Files
clang-p2996/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/ThreadPlanStepThroughObjCTrampoline.cpp
Jim Ingham b01e742af7 Two changes in this checkin. Added a ThreadPlanKind so that I can do some reasoning based on the kind of thread plan
without having to use RTTI.
Removed the ThreadPlanContinue and replaced with a ShouldAutoContinue query that serves the same purpose.  Having to push
another plan to assert that if there's no other indication the target should continue when this plan is popped was flakey
and error prone.  This method is more stable, and fixed problems we were having with thread specific breakpoints.

llvm-svn: 106378
2010-06-19 04:45:32 +00:00

152 lines
4.8 KiB
C++

//===-- ThreadPlanStepThroughObjCTrampoline.cpp --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "ThreadPlanStepThroughObjCTrampoline.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"
#include "lldb/Expression/ClangExpression.h"
#include "lldb/Expression/ClangFunction.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"
#include "lldb/Core/Log.h"
using namespace lldb_private;
//----------------------------------------------------------------------
// ThreadPlanStepThroughObjCTrampoline constructor
//----------------------------------------------------------------------
ThreadPlanStepThroughObjCTrampoline::ThreadPlanStepThroughObjCTrampoline(
Thread &thread,
ObjCTrampolineHandler *trampoline_handler,
lldb::addr_t args_addr,
lldb::addr_t object_ptr,
lldb::addr_t class_ptr,
lldb::addr_t sel_ptr,
bool stop_others) :
ThreadPlan (ThreadPlan::eKindGeneric, "MacOSX Step through ObjC Trampoline", thread, eVoteNoOpinion, eVoteNoOpinion),
m_objc_trampoline_handler (trampoline_handler),
m_impl_function (trampoline_handler->GetLookupImplementationWrapperFunction()),
m_args_addr (args_addr),
m_object_ptr (object_ptr),
m_class_ptr (class_ptr),
m_sel_ptr (sel_ptr),
m_stop_others (stop_others)
{
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
ThreadPlanStepThroughObjCTrampoline::~ThreadPlanStepThroughObjCTrampoline()
{
}
void
ThreadPlanStepThroughObjCTrampoline::DidPush ()
{
StreamString errors;
ExecutionContext exc_context;
m_thread.Calculate(exc_context);
m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_context, m_args_addr, errors, m_stop_others));
m_func_sp->SetPrivate(true);
m_thread.QueueThreadPlan (m_func_sp, false);
}
void
ThreadPlanStepThroughObjCTrampoline::GetDescription (Stream *s,
lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
s->Printf("Step through ObjC trampoline");
else
{
s->Printf ("Stepping to implementation of ObjC method - obj: 0x%llx class: 0x%llx selector: 0x%llx",
m_object_ptr, m_class_ptr, m_sel_ptr);
}
}
bool
ThreadPlanStepThroughObjCTrampoline::ValidatePlan (Stream *error)
{
return true;
}
bool
ThreadPlanStepThroughObjCTrampoline::PlanExplainsStop ()
{
// This plan should actually never stop when it is on the top of the plan
// stack, since it does all it's running in client plans.
return false;
}
lldb::StateType
ThreadPlanStepThroughObjCTrampoline::RunState ()
{
return eStateRunning;
}
bool
ThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr)
{
if (m_func_sp.get() == NULL || m_thread.IsThreadPlanDone(m_func_sp.get()))
{
m_func_sp.reset();
if (!m_run_to_sp)
{
Value target_addr_value;
ExecutionContext exc_context;
m_thread.Calculate(exc_context);
m_impl_function->FetchFunctionResults (exc_context, m_args_addr, target_addr_value);
m_impl_function->DeallocateFunctionResults(exc_context, m_args_addr);
lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong();
Address target_address(NULL, target_addr);
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
if (log)
log->Printf("Running to ObjC method implementation: 0x%llx", target_addr);
m_objc_trampoline_handler->AddToCache (m_class_ptr, m_sel_ptr, target_addr);
// Extract the target address from the value:
m_run_to_sp.reset(new ThreadPlanRunToAddress(m_thread, target_address, m_stop_others));
m_thread.QueueThreadPlan(m_run_to_sp, false);
m_run_to_sp->SetPrivate(true);
return false;
}
else if (m_thread.IsThreadPlanDone(m_run_to_sp.get()))
{
SetPlanComplete();
return true;
}
}
return false;
}
// The base class MischiefManaged does some cleanup - so you have to call it
// in your MischiefManaged derived class.
bool
ThreadPlanStepThroughObjCTrampoline::MischiefManaged ()
{
if (IsPlanComplete())
return true;
else
return false;
}
bool
ThreadPlanStepThroughObjCTrampoline::WillStop()
{
return true;
}