]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Plugins / LanguageRuntime / ObjC / AppleObjCRuntime / AppleThreadPlanStepThroughObjCTrampoline.cpp
1 //===-- AppleThreadPlanStepThroughObjCTrampoline.cpp
2 //--------------------------*- C++ -*-===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10
11 #include "AppleThreadPlanStepThroughObjCTrampoline.h"
12 #include "AppleObjCTrampolineHandler.h"
13 #include "lldb/Expression/DiagnosticManager.h"
14 #include "lldb/Expression/FunctionCaller.h"
15 #include "lldb/Expression/UtilityFunction.h"
16 #include "lldb/Target/ExecutionContext.h"
17 #include "lldb/Target/ObjCLanguageRuntime.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Thread.h"
20 #include "lldb/Target/ThreadPlanRunToAddress.h"
21 #include "lldb/Target/ThreadPlanStepOut.h"
22 #include "lldb/Utility/Log.h"
23
24 using namespace lldb;
25 using namespace lldb_private;
26
27 //----------------------------------------------------------------------
28 // ThreadPlanStepThroughObjCTrampoline constructor
29 //----------------------------------------------------------------------
30 AppleThreadPlanStepThroughObjCTrampoline::
31     AppleThreadPlanStepThroughObjCTrampoline(
32         Thread &thread, AppleObjCTrampolineHandler *trampoline_handler,
33         ValueList &input_values, lldb::addr_t isa_addr, lldb::addr_t sel_addr,
34         bool stop_others)
35     : ThreadPlan(ThreadPlan::eKindGeneric,
36                  "MacOSX Step through ObjC Trampoline", thread, eVoteNoOpinion,
37                  eVoteNoOpinion),
38       m_trampoline_handler(trampoline_handler),
39       m_args_addr(LLDB_INVALID_ADDRESS), m_input_values(input_values),
40       m_isa_addr(isa_addr), m_sel_addr(sel_addr), m_impl_function(NULL),
41       m_stop_others(stop_others) {}
42
43 //----------------------------------------------------------------------
44 // Destructor
45 //----------------------------------------------------------------------
46 AppleThreadPlanStepThroughObjCTrampoline::
47     ~AppleThreadPlanStepThroughObjCTrampoline() {}
48
49 void AppleThreadPlanStepThroughObjCTrampoline::DidPush() {
50   // Setting up the memory space for the called function text might require
51   // allocations, i.e. a nested function call.  This needs to be done as a
52   // PreResumeAction.
53   m_thread.GetProcess()->AddPreResumeAction(PreResumeInitializeFunctionCaller,
54                                             (void *)this);
55 }
56
57 bool AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller() {
58   if (!m_func_sp) {
59     DiagnosticManager diagnostics;
60     m_args_addr =
61         m_trampoline_handler->SetupDispatchFunction(m_thread, m_input_values);
62
63     if (m_args_addr == LLDB_INVALID_ADDRESS) {
64       return false;
65     }
66     m_impl_function =
67         m_trampoline_handler->GetLookupImplementationFunctionCaller();
68     ExecutionContext exc_ctx;
69     EvaluateExpressionOptions options;
70     options.SetUnwindOnError(true);
71     options.SetIgnoreBreakpoints(true);
72     options.SetStopOthers(m_stop_others);
73     m_thread.CalculateExecutionContext(exc_ctx);
74     m_func_sp = m_impl_function->GetThreadPlanToCallFunction(
75         exc_ctx, m_args_addr, options, diagnostics);
76     m_func_sp->SetOkayToDiscard(true);
77     m_thread.QueueThreadPlan(m_func_sp, false);
78   }
79   return true;
80 }
81
82 bool AppleThreadPlanStepThroughObjCTrampoline::
83     PreResumeInitializeFunctionCaller(void *void_myself) {
84   AppleThreadPlanStepThroughObjCTrampoline *myself =
85       static_cast<AppleThreadPlanStepThroughObjCTrampoline *>(void_myself);
86   return myself->InitializeFunctionCaller();
87 }
88
89 void AppleThreadPlanStepThroughObjCTrampoline::GetDescription(
90     Stream *s, lldb::DescriptionLevel level) {
91   if (level == lldb::eDescriptionLevelBrief)
92     s->Printf("Step through ObjC trampoline");
93   else {
94     s->Printf("Stepping to implementation of ObjC method - obj: 0x%llx, isa: "
95               "0x%" PRIx64 ", sel: 0x%" PRIx64,
96               m_input_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
97               m_isa_addr, m_sel_addr);
98   }
99 }
100
101 bool AppleThreadPlanStepThroughObjCTrampoline::ValidatePlan(Stream *error) {
102   return true;
103 }
104
105 bool AppleThreadPlanStepThroughObjCTrampoline::DoPlanExplainsStop(
106     Event *event_ptr) {
107   // If we get asked to explain the stop it will be because something went
108   // wrong (like the implementation for selector function crashed...  We're
109   // going to figure out what to do about that, so we do explain the stop.
110   return true;
111 }
112
113 lldb::StateType AppleThreadPlanStepThroughObjCTrampoline::GetPlanRunState() {
114   return eStateRunning;
115 }
116
117 bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) {
118   // First stage: we are still handling the "call a function to get the target
119   // of the dispatch"
120   if (m_func_sp) {
121     if (!m_func_sp->IsPlanComplete()) {
122       return false;
123     } else {
124       if (!m_func_sp->PlanSucceeded()) {
125         SetPlanComplete(false);
126         return true;
127       }
128       m_func_sp.reset();
129     }
130   }
131
132   // Second stage, if all went well with the function calling, then fetch the
133   // target address, and queue up a "run to that address" plan.
134   if (!m_run_to_sp) {
135     Value target_addr_value;
136     ExecutionContext exc_ctx;
137     m_thread.CalculateExecutionContext(exc_ctx);
138     m_impl_function->FetchFunctionResults(exc_ctx, m_args_addr,
139                                           target_addr_value);
140     m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr);
141     lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong();
142     Address target_so_addr;
143     target_so_addr.SetOpcodeLoadAddress(target_addr, exc_ctx.GetTargetPtr());
144     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
145     if (target_addr == 0) {
146       if (log)
147         log->Printf("Got target implementation of 0x0, stopping.");
148       SetPlanComplete();
149       return true;
150     }
151     if (m_trampoline_handler->AddrIsMsgForward(target_addr)) {
152       if (log)
153         log->Printf(
154             "Implementation lookup returned msgForward function: 0x%" PRIx64
155             ", stopping.",
156             target_addr);
157
158       SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(
159           eSymbolContextEverything);
160       Status status;
161       const bool abort_other_plans = false;
162       const bool first_insn = true;
163       const uint32_t frame_idx = 0;
164       m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(
165           abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion,
166           eVoteNoOpinion, frame_idx, status);
167       if (m_run_to_sp && status.Success())
168         m_run_to_sp->SetPrivate(true);
169       return false;
170     }
171
172     if (log)
173       log->Printf("Running to ObjC method implementation: 0x%" PRIx64,
174                   target_addr);
175
176     ObjCLanguageRuntime *objc_runtime =
177         GetThread().GetProcess()->GetObjCLanguageRuntime();
178     assert(objc_runtime != NULL);
179     objc_runtime->AddToMethodCache(m_isa_addr, m_sel_addr, target_addr);
180     if (log)
181       log->Printf("Adding {isa-addr=0x%" PRIx64 ", sel-addr=0x%" PRIx64
182                   "} = addr=0x%" PRIx64 " to cache.",
183                   m_isa_addr, m_sel_addr, target_addr);
184
185     // Extract the target address from the value:
186
187     m_run_to_sp.reset(
188         new ThreadPlanRunToAddress(m_thread, target_so_addr, m_stop_others));
189     m_thread.QueueThreadPlan(m_run_to_sp, false);
190     m_run_to_sp->SetPrivate(true);
191     return false;
192   } else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) {
193     // Third stage, work the run to target plan.
194     SetPlanComplete();
195     return true;
196   }
197   return false;
198 }
199
200 // The base class MischiefManaged does some cleanup - so you have to call it in
201 // your MischiefManaged derived class.
202 bool AppleThreadPlanStepThroughObjCTrampoline::MischiefManaged() {
203   return IsPlanComplete();
204 }
205
206 bool AppleThreadPlanStepThroughObjCTrampoline::WillStop() { return true; }