AppleThreadPlanStepThroughObjCTrampoline.cpp revision 309124
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" 16309124Sdim#include "lldb/Core/Log.h" 17309124Sdim#include "lldb/Expression/DiagnosticManager.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" 22309124Sdim#include "lldb/Target/Process.h" 23309124Sdim#include "lldb/Target/Thread.h" 24293116Semaste#include "lldb/Target/ThreadPlanRunToAddress.h" 25293116Semaste#include "lldb/Target/ThreadPlanStepOut.h" 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 { 78309124Sdim DiagnosticManager diagnostics; 79293116Semaste m_args_addr = m_trampoline_handler->SetupDispatchFunction(m_thread, m_input_values); 80309124Sdim 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); 92309124Sdim m_func_sp = m_impl_function->GetThreadPlanToCallFunction(exc_ctx, m_args_addr, options, diagnostics); 93293116Semaste m_func_sp->SetOkayToDiscard(true); 94309124Sdim m_thread.QueueThreadPlan(m_func_sp, false); 95293116Semaste } 96293116Semaste return true; 97293116Semaste} 98293116Semaste 99293116Semastebool 100293116SemasteAppleThreadPlanStepThroughObjCTrampoline::PreResumeInitializeFunctionCaller(void *void_myself) 101293116Semaste{ 102293116Semaste AppleThreadPlanStepThroughObjCTrampoline *myself = static_cast<AppleThreadPlanStepThroughObjCTrampoline *>(void_myself); 103293116Semaste return myself->InitializeFunctionCaller(); 104293116Semaste} 105293116Semaste 106293116Semastevoid 107293116SemasteAppleThreadPlanStepThroughObjCTrampoline::GetDescription (Stream *s, 108293116Semaste lldb::DescriptionLevel level) 109293116Semaste{ 110293116Semaste if (level == lldb::eDescriptionLevelBrief) 111293116Semaste s->Printf("Step through ObjC trampoline"); 112293116Semaste else 113293116Semaste { 114293116Semaste s->Printf ("Stepping to implementation of ObjC method - obj: 0x%llx, isa: 0x%" PRIx64 ", sel: 0x%" PRIx64, 115293116Semaste m_input_values.GetValueAtIndex(0)->GetScalar().ULongLong(), m_isa_addr, m_sel_addr); 116293116Semaste } 117293116Semaste} 118293116Semaste 119293116Semastebool 120293116SemasteAppleThreadPlanStepThroughObjCTrampoline::ValidatePlan (Stream *error) 121293116Semaste{ 122293116Semaste return true; 123293116Semaste} 124293116Semaste 125293116Semastebool 126293116SemasteAppleThreadPlanStepThroughObjCTrampoline::DoPlanExplainsStop (Event *event_ptr) 127293116Semaste{ 128293116Semaste // If we get asked to explain the stop it will be because something went 129293116Semaste // wrong (like the implementation for selector function crashed... We're going 130293116Semaste // to figure out what to do about that, so we do explain the stop. 131293116Semaste return true; 132293116Semaste} 133293116Semaste 134293116Semastelldb::StateType 135293116SemasteAppleThreadPlanStepThroughObjCTrampoline::GetPlanRunState () 136293116Semaste{ 137293116Semaste return eStateRunning; 138293116Semaste} 139293116Semaste 140293116Semastebool 141293116SemasteAppleThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr) 142293116Semaste{ 143293116Semaste // First stage: we are still handling the "call a function to get the target of the dispatch" 144293116Semaste if (m_func_sp) 145293116Semaste { 146293116Semaste if (!m_func_sp->IsPlanComplete()) 147293116Semaste { 148293116Semaste return false; 149293116Semaste } 150293116Semaste else 151293116Semaste { 152293116Semaste if (!m_func_sp->PlanSucceeded()) 153293116Semaste { 154293116Semaste SetPlanComplete(false); 155293116Semaste return true; 156293116Semaste } 157293116Semaste m_func_sp.reset(); 158293116Semaste } 159293116Semaste } 160293116Semaste 161293116Semaste // Second stage, if all went well with the function calling, then fetch the target address, and 162293116Semaste // queue up a "run to that address" plan. 163293116Semaste if (!m_run_to_sp) 164293116Semaste { 165293116Semaste Value target_addr_value; 166293116Semaste ExecutionContext exc_ctx; 167293116Semaste m_thread.CalculateExecutionContext(exc_ctx); 168293116Semaste m_impl_function->FetchFunctionResults (exc_ctx, m_args_addr, target_addr_value); 169293116Semaste m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr); 170293116Semaste lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong(); 171293116Semaste Address target_so_addr; 172293116Semaste target_so_addr.SetOpcodeLoadAddress(target_addr, exc_ctx.GetTargetPtr()); 173293116Semaste Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 174293116Semaste if (target_addr == 0) 175293116Semaste { 176293116Semaste if (log) 177293116Semaste log->Printf("Got target implementation of 0x0, stopping."); 178293116Semaste SetPlanComplete(); 179293116Semaste return true; 180293116Semaste } 181293116Semaste if (m_trampoline_handler->AddrIsMsgForward(target_addr)) 182293116Semaste { 183293116Semaste if (log) 184293116Semaste log->Printf ("Implementation lookup returned msgForward function: 0x%" PRIx64 ", stopping.", target_addr); 185293116Semaste 186293116Semaste SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(eSymbolContextEverything); 187293116Semaste const bool abort_other_plans = false; 188293116Semaste const bool first_insn = true; 189293116Semaste const uint32_t frame_idx = 0; 190293116Semaste m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop (abort_other_plans, 191293116Semaste &sc, 192293116Semaste first_insn, 193293116Semaste m_stop_others, 194293116Semaste eVoteNoOpinion, 195293116Semaste eVoteNoOpinion, 196293116Semaste frame_idx); 197293116Semaste m_run_to_sp->SetPrivate(true); 198293116Semaste return false; 199293116Semaste } 200293116Semaste 201293116Semaste if (log) 202293116Semaste log->Printf("Running to ObjC method implementation: 0x%" PRIx64, target_addr); 203293116Semaste 204293116Semaste ObjCLanguageRuntime *objc_runtime = GetThread().GetProcess()->GetObjCLanguageRuntime(); 205293116Semaste assert (objc_runtime != NULL); 206293116Semaste objc_runtime->AddToMethodCache (m_isa_addr, m_sel_addr, target_addr); 207293116Semaste if (log) 208293116Semaste log->Printf("Adding {isa-addr=0x%" PRIx64 ", sel-addr=0x%" PRIx64 "} = addr=0x%" PRIx64 " to cache.", m_isa_addr, m_sel_addr, target_addr); 209293116Semaste 210293116Semaste // Extract the target address from the value: 211293116Semaste 212293116Semaste m_run_to_sp.reset(new ThreadPlanRunToAddress(m_thread, target_so_addr, m_stop_others)); 213293116Semaste m_thread.QueueThreadPlan(m_run_to_sp, false); 214293116Semaste m_run_to_sp->SetPrivate(true); 215293116Semaste return false; 216293116Semaste } 217293116Semaste else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) 218293116Semaste { 219293116Semaste // Third stage, work the run to target plan. 220293116Semaste SetPlanComplete(); 221293116Semaste return true; 222293116Semaste } 223293116Semaste return false; 224293116Semaste} 225293116Semaste 226293116Semaste// The base class MischiefManaged does some cleanup - so you have to call it 227293116Semaste// in your MischiefManaged derived class. 228293116Semastebool 229293116SemasteAppleThreadPlanStepThroughObjCTrampoline::MischiefManaged () 230293116Semaste{ 231293116Semaste if (IsPlanComplete()) 232293116Semaste return true; 233293116Semaste else 234293116Semaste return false; 235293116Semaste} 236293116Semaste 237293116Semastebool 238293116SemasteAppleThreadPlanStepThroughObjCTrampoline::WillStop() 239293116Semaste{ 240293116Semaste return true; 241293116Semaste} 242