1 //===-- AppleThreadPlanStepThroughObjCTrampoline.cpp --------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "AppleThreadPlanStepThroughObjCTrampoline.h" 15 #include "AppleObjCTrampolineHandler.h" 16 #include "lldb/Target/Process.h" 17 #include "lldb/Target/Thread.h" 18 #include "lldb/Expression/ClangExpression.h" 19 #include "lldb/Expression/ClangFunction.h" 20 #include "lldb/Target/ExecutionContext.h" 21 #include "lldb/Target/ObjCLanguageRuntime.h" 22 #include "lldb/Target/ThreadPlanRunToAddress.h" 23 #include "lldb/Target/ThreadPlanStepOut.h" 24 #include "lldb/Core/Log.h" 25 26 27 using namespace lldb; 28 using namespace lldb_private; 29 30 //---------------------------------------------------------------------- 31 // ThreadPlanStepThroughObjCTrampoline constructor 32 //---------------------------------------------------------------------- 33 AppleThreadPlanStepThroughObjCTrampoline::AppleThreadPlanStepThroughObjCTrampoline 34 ( 35 Thread &thread, 36 AppleObjCTrampolineHandler *trampoline_handler, 37 lldb::addr_t args_addr, 38 lldb::addr_t object_addr, 39 lldb::addr_t isa_addr, 40 lldb::addr_t sel_addr, 41 bool stop_others 42 ) : 43 ThreadPlan (ThreadPlan::eKindGeneric, 44 "MacOSX Step through ObjC Trampoline", 45 thread, 46 eVoteNoOpinion, 47 eVoteNoOpinion), 48 m_trampoline_handler (trampoline_handler), 49 m_args_addr (args_addr), 50 m_object_addr (object_addr), 51 m_isa_addr(isa_addr), 52 m_sel_addr(sel_addr), 53 m_impl_function (trampoline_handler->GetLookupImplementationWrapperFunction()), 54 m_stop_others (stop_others) 55 { 56 57 } 58 59 //---------------------------------------------------------------------- 60 // Destructor 61 //---------------------------------------------------------------------- 62 AppleThreadPlanStepThroughObjCTrampoline::~AppleThreadPlanStepThroughObjCTrampoline() 63 { 64 } 65 66 void 67 AppleThreadPlanStepThroughObjCTrampoline::DidPush () 68 { 69 StreamString errors; 70 ExecutionContext exc_ctx; 71 m_thread.CalculateExecutionContext(exc_ctx); 72 m_func_sp.reset(m_impl_function->GetThreadPlanToCallFunction (exc_ctx, m_args_addr, errors, m_stop_others)); 73 m_func_sp->SetPrivate(true); 74 m_thread.QueueThreadPlan (m_func_sp, false); 75 } 76 77 void 78 AppleThreadPlanStepThroughObjCTrampoline::GetDescription (Stream *s, 79 lldb::DescriptionLevel level) 80 { 81 if (level == lldb::eDescriptionLevelBrief) 82 s->Printf("Step through ObjC trampoline"); 83 else 84 { 85 s->Printf ("Stepping to implementation of ObjC method - obj: 0x%llx, isa: 0x%llx, sel: 0x%llx", 86 m_object_addr, m_isa_addr, m_sel_addr); 87 } 88 } 89 90 bool 91 AppleThreadPlanStepThroughObjCTrampoline::ValidatePlan (Stream *error) 92 { 93 return true; 94 } 95 96 bool 97 AppleThreadPlanStepThroughObjCTrampoline::PlanExplainsStop () 98 { 99 // This plan should actually never stop when it is on the top of the plan 100 // stack, since it does all it's running in client plans. 101 return false; 102 } 103 104 lldb::StateType 105 AppleThreadPlanStepThroughObjCTrampoline::GetPlanRunState () 106 { 107 return eStateRunning; 108 } 109 110 bool 111 AppleThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr) 112 { 113 if (m_func_sp.get() == NULL || m_thread.IsThreadPlanDone(m_func_sp.get())) 114 { 115 m_func_sp.reset(); 116 if (!m_run_to_sp) 117 { 118 Value target_addr_value; 119 ExecutionContext exc_ctx; 120 m_thread.CalculateExecutionContext(exc_ctx); 121 m_impl_function->FetchFunctionResults (exc_ctx, m_args_addr, target_addr_value); 122 m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr); 123 lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong(); 124 Address target_so_addr; 125 target_so_addr.SetOpcodeLoadAddress(target_addr, exc_ctx.GetTargetPtr()); 126 LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); 127 if (target_addr == 0) 128 { 129 if (log) 130 log->Printf("Got target implementation of 0x0, stopping."); 131 SetPlanComplete(); 132 return true; 133 } 134 if (m_trampoline_handler->AddrIsMsgForward(target_addr)) 135 { 136 if (log) 137 log->Printf ("Implementation lookup returned msgForward function: 0x%llx, stopping.", target_addr); 138 139 SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(eSymbolContextEverything); 140 m_run_to_sp.reset(new ThreadPlanStepOut (m_thread, 141 &sc, 142 true, 143 m_stop_others, 144 eVoteNoOpinion, 145 eVoteNoOpinion, 146 0)); 147 m_thread.QueueThreadPlan(m_run_to_sp, false); 148 m_run_to_sp->SetPrivate(true); 149 return false; 150 } 151 152 if (log) 153 log->Printf("Running to ObjC method implementation: 0x%llx", target_addr); 154 155 ObjCLanguageRuntime *objc_runtime = GetThread().GetProcess().GetObjCLanguageRuntime(); 156 assert (objc_runtime != NULL); 157 objc_runtime->AddToMethodCache (m_isa_addr, m_sel_addr, target_addr); 158 if (log) 159 log->Printf("Adding {isa-addr=0x%llx, sel-addr=0x%llx} = addr=0x%llx to cache.", m_isa_addr, m_sel_addr, target_addr); 160 161 // Extract the target address from the value: 162 163 m_run_to_sp.reset(new ThreadPlanRunToAddress(m_thread, target_so_addr, m_stop_others)); 164 m_thread.QueueThreadPlan(m_run_to_sp, false); 165 m_run_to_sp->SetPrivate(true); 166 return false; 167 } 168 else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) 169 { 170 SetPlanComplete(); 171 return true; 172 } 173 } 174 return false; 175 } 176 177 // The base class MischiefManaged does some cleanup - so you have to call it 178 // in your MischiefManaged derived class. 179 bool 180 AppleThreadPlanStepThroughObjCTrampoline::MischiefManaged () 181 { 182 if (IsPlanComplete()) 183 return true; 184 else 185 return false; 186 } 187 188 bool 189 AppleThreadPlanStepThroughObjCTrampoline::WillStop() 190 { 191 return true; 192 } 193