AppleThreadPlanStepThroughObjCTrampoline.cpp revision 293116
1293116Semaste//===-- AppleThreadPlanStepThroughObjCTrampoline.cpp --------------------------*- C++ -*-===// 2293116Semaste// 3293116Semaste// The LLVM Compiler Infrastructure 4293116Semaste// 5293116Semaste// This file is distributed under the University of Illinois Open Source 6293116Semaste// License. See LICENSE.TXT for details. 7293116Semaste// 8293116Semaste//===----------------------------------------------------------------------===// 9293116Semaste 10293116Semaste// C Includes 11293116Semaste// C++ Includes 12293116Semaste// Other libraries and framework includes 13293116Semaste// Project includes 14293116Semaste#include "AppleThreadPlanStepThroughObjCTrampoline.h" 15293116Semaste#include "AppleObjCTrampolineHandler.h" 16293116Semaste#include "lldb/Target/Process.h" 17293116Semaste#include "lldb/Target/Thread.h" 18293116Semaste#include "lldb/Expression/FunctionCaller.h" 19293116Semaste#include "lldb/Expression/UtilityFunction.h" 20293116Semaste#include "lldb/Target/ExecutionContext.h" 21293116Semaste#include "lldb/Target/ObjCLanguageRuntime.h" 22293116Semaste#include "lldb/Target/ThreadPlanRunToAddress.h" 23293116Semaste#include "lldb/Target/ThreadPlanStepOut.h" 24293116Semaste#include "lldb/Core/Log.h" 25293116Semaste 26293116Semaste 27293116Semasteusing namespace lldb; 28293116Semasteusing namespace lldb_private; 29293116Semaste 30293116Semaste//---------------------------------------------------------------------- 31293116Semaste// ThreadPlanStepThroughObjCTrampoline constructor 32293116Semaste//---------------------------------------------------------------------- 33293116SemasteAppleThreadPlanStepThroughObjCTrampoline::AppleThreadPlanStepThroughObjCTrampoline 34293116Semaste( 35293116Semaste Thread &thread, 36293116Semaste AppleObjCTrampolineHandler *trampoline_handler, 37293116Semaste ValueList &input_values, 38293116Semaste lldb::addr_t isa_addr, 39293116Semaste lldb::addr_t sel_addr, 40293116Semaste bool stop_others 41293116Semaste) : 42293116Semaste ThreadPlan (ThreadPlan::eKindGeneric, 43293116Semaste "MacOSX Step through ObjC Trampoline", 44293116Semaste thread, 45293116Semaste eVoteNoOpinion, 46293116Semaste eVoteNoOpinion), 47293116Semaste m_trampoline_handler (trampoline_handler), 48293116Semaste m_args_addr (LLDB_INVALID_ADDRESS), 49293116Semaste m_input_values (input_values), 50293116Semaste m_isa_addr(isa_addr), 51293116Semaste m_sel_addr(sel_addr), 52293116Semaste m_impl_function (NULL), 53293116Semaste m_stop_others (stop_others) 54293116Semaste{ 55293116Semaste 56293116Semaste} 57293116Semaste 58293116Semaste//---------------------------------------------------------------------- 59293116Semaste// Destructor 60293116Semaste//---------------------------------------------------------------------- 61293116SemasteAppleThreadPlanStepThroughObjCTrampoline::~AppleThreadPlanStepThroughObjCTrampoline() 62293116Semaste{ 63293116Semaste} 64293116Semaste 65293116Semastevoid 66293116SemasteAppleThreadPlanStepThroughObjCTrampoline::DidPush () 67293116Semaste{ 68293116Semaste // Setting up the memory space for the called function text might require allocations, 69293116Semaste // i.e. a nested function call. This needs to be done as a PreResumeAction. 70293116Semaste m_thread.GetProcess()->AddPreResumeAction (PreResumeInitializeFunctionCaller, (void *) this); 71293116Semaste} 72293116Semaste 73293116Semastebool 74293116SemasteAppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller () 75293116Semaste{ 76293116Semaste if (!m_func_sp) 77293116Semaste { 78293116Semaste StreamString errors; 79293116Semaste m_args_addr = m_trampoline_handler->SetupDispatchFunction(m_thread, m_input_values); 80293116Semaste 81293116Semaste if (m_args_addr == LLDB_INVALID_ADDRESS) 82293116Semaste { 83293116Semaste return false; 84293116Semaste } 85293116Semaste m_impl_function = m_trampoline_handler->GetLookupImplementationFunctionCaller(); 86293116Semaste ExecutionContext exc_ctx; 87293116Semaste EvaluateExpressionOptions options; 88293116Semaste options.SetUnwindOnError(true); 89293116Semaste options.SetIgnoreBreakpoints(true); 90293116Semaste options.SetStopOthers(m_stop_others); 91293116Semaste m_thread.CalculateExecutionContext(exc_ctx); 92293116Semaste m_func_sp = m_impl_function->GetThreadPlanToCallFunction (exc_ctx, 93293116Semaste m_args_addr, 94293116Semaste options, 95293116Semaste errors); 96293116Semaste m_func_sp->SetOkayToDiscard(true); 97293116Semaste m_thread.QueueThreadPlan (m_func_sp, false); 98293116Semaste } 99293116Semaste return true; 100293116Semaste} 101293116Semaste 102293116Semastebool 103293116SemasteAppleThreadPlanStepThroughObjCTrampoline::PreResumeInitializeFunctionCaller(void *void_myself) 104293116Semaste{ 105293116Semaste AppleThreadPlanStepThroughObjCTrampoline *myself = static_cast<AppleThreadPlanStepThroughObjCTrampoline *>(void_myself); 106293116Semaste return myself->InitializeFunctionCaller(); 107293116Semaste} 108293116Semaste 109293116Semastevoid 110293116SemasteAppleThreadPlanStepThroughObjCTrampoline::GetDescription (Stream *s, 111293116Semaste lldb::DescriptionLevel level) 112293116Semaste{ 113293116Semaste if (level == lldb::eDescriptionLevelBrief) 114293116Semaste s->Printf("Step through ObjC trampoline"); 115293116Semaste else 116293116Semaste { 117293116Semaste s->Printf ("Stepping to implementation of ObjC method - obj: 0x%llx, isa: 0x%" PRIx64 ", sel: 0x%" PRIx64, 118293116Semaste m_input_values.GetValueAtIndex(0)->GetScalar().ULongLong(), m_isa_addr, m_sel_addr); 119293116Semaste } 120293116Semaste} 121293116Semaste 122293116Semastebool 123293116SemasteAppleThreadPlanStepThroughObjCTrampoline::ValidatePlan (Stream *error) 124293116Semaste{ 125293116Semaste return true; 126293116Semaste} 127293116Semaste 128293116Semastebool 129293116SemasteAppleThreadPlanStepThroughObjCTrampoline::DoPlanExplainsStop (Event *event_ptr) 130293116Semaste{ 131293116Semaste // If we get asked to explain the stop it will be because something went 132293116Semaste // wrong (like the implementation for selector function crashed... We're going 133293116Semaste // to figure out what to do about that, so we do explain the stop. 134293116Semaste return true; 135293116Semaste} 136293116Semaste 137293116Semastelldb::StateType 138293116SemasteAppleThreadPlanStepThroughObjCTrampoline::GetPlanRunState () 139293116Semaste{ 140293116Semaste return eStateRunning; 141293116Semaste} 142293116Semaste 143293116Semastebool 144293116SemasteAppleThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr) 145293116Semaste{ 146293116Semaste // First stage: we are still handling the "call a function to get the target of the dispatch" 147293116Semaste if (m_func_sp) 148293116Semaste { 149293116Semaste if (!m_func_sp->IsPlanComplete()) 150293116Semaste { 151293116Semaste return false; 152293116Semaste } 153293116Semaste else 154293116Semaste { 155293116Semaste if (!m_func_sp->PlanSucceeded()) 156293116Semaste { 157293116Semaste SetPlanComplete(false); 158293116Semaste return true; 159293116Semaste } 160293116Semaste m_func_sp.reset(); 161293116Semaste } 162293116Semaste } 163293116Semaste 164293116Semaste // Second stage, if all went well with the function calling, then fetch the target address, and 165293116Semaste // queue up a "run to that address" plan. 166293116Semaste if (!m_run_to_sp) 167293116Semaste { 168293116Semaste Value target_addr_value; 169293116Semaste ExecutionContext exc_ctx; 170293116Semaste m_thread.CalculateExecutionContext(exc_ctx); 171293116Semaste m_impl_function->FetchFunctionResults (exc_ctx, m_args_addr, target_addr_value); 172293116Semaste m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr); 173293116Semaste lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong(); 174293116Semaste Address target_so_addr; 175293116Semaste target_so_addr.SetOpcodeLoadAddress(target_addr, exc_ctx.GetTargetPtr()); 176293116Semaste Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 177293116Semaste if (target_addr == 0) 178293116Semaste { 179293116Semaste if (log) 180293116Semaste log->Printf("Got target implementation of 0x0, stopping."); 181293116Semaste SetPlanComplete(); 182293116Semaste return true; 183293116Semaste } 184293116Semaste if (m_trampoline_handler->AddrIsMsgForward(target_addr)) 185293116Semaste { 186293116Semaste if (log) 187293116Semaste log->Printf ("Implementation lookup returned msgForward function: 0x%" PRIx64 ", stopping.", target_addr); 188293116Semaste 189293116Semaste SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(eSymbolContextEverything); 190293116Semaste const bool abort_other_plans = false; 191293116Semaste const bool first_insn = true; 192293116Semaste const uint32_t frame_idx = 0; 193293116Semaste m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop (abort_other_plans, 194293116Semaste &sc, 195293116Semaste first_insn, 196293116Semaste m_stop_others, 197293116Semaste eVoteNoOpinion, 198293116Semaste eVoteNoOpinion, 199293116Semaste frame_idx); 200293116Semaste m_run_to_sp->SetPrivate(true); 201293116Semaste return false; 202293116Semaste } 203293116Semaste 204293116Semaste if (log) 205293116Semaste log->Printf("Running to ObjC method implementation: 0x%" PRIx64, target_addr); 206293116Semaste 207293116Semaste ObjCLanguageRuntime *objc_runtime = GetThread().GetProcess()->GetObjCLanguageRuntime(); 208293116Semaste assert (objc_runtime != NULL); 209293116Semaste objc_runtime->AddToMethodCache (m_isa_addr, m_sel_addr, target_addr); 210293116Semaste if (log) 211293116Semaste log->Printf("Adding {isa-addr=0x%" PRIx64 ", sel-addr=0x%" PRIx64 "} = addr=0x%" PRIx64 " to cache.", m_isa_addr, m_sel_addr, target_addr); 212293116Semaste 213293116Semaste // Extract the target address from the value: 214293116Semaste 215293116Semaste m_run_to_sp.reset(new ThreadPlanRunToAddress(m_thread, target_so_addr, m_stop_others)); 216293116Semaste m_thread.QueueThreadPlan(m_run_to_sp, false); 217293116Semaste m_run_to_sp->SetPrivate(true); 218293116Semaste return false; 219293116Semaste } 220293116Semaste else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) 221293116Semaste { 222293116Semaste // Third stage, work the run to target plan. 223293116Semaste SetPlanComplete(); 224293116Semaste return true; 225293116Semaste } 226293116Semaste return false; 227293116Semaste} 228293116Semaste 229293116Semaste// The base class MischiefManaged does some cleanup - so you have to call it 230293116Semaste// in your MischiefManaged derived class. 231293116Semastebool 232293116SemasteAppleThreadPlanStepThroughObjCTrampoline::MischiefManaged () 233293116Semaste{ 234293116Semaste if (IsPlanComplete()) 235293116Semaste return true; 236293116Semaste else 237293116Semaste return false; 238293116Semaste} 239293116Semaste 240293116Semastebool 241293116SemasteAppleThreadPlanStepThroughObjCTrampoline::WillStop() 242293116Semaste{ 243293116Semaste return true; 244293116Semaste} 245