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