LLDB  mainline
AppleThreadPlanStepThroughObjCTrampoline.cpp
Go to the documentation of this file.
1 //===-- AppleThreadPlanStepThroughObjCTrampoline.cpp
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 
17 #include "lldb/Target/Process.h"
18 #include "lldb/Target/Thread.h"
21 #include "lldb/Utility/Log.h"
22 
23 #include <memory>
24 
25 using namespace lldb;
26 using namespace lldb_private;
27 
28 // ThreadPlanStepThroughObjCTrampoline constructor
29 AppleThreadPlanStepThroughObjCTrampoline::
30  AppleThreadPlanStepThroughObjCTrampoline(
31  Thread &thread, AppleObjCTrampolineHandler *trampoline_handler,
32  ValueList &input_values, lldb::addr_t isa_addr, lldb::addr_t sel_addr,
33  bool stop_others)
34  : ThreadPlan(ThreadPlan::eKindGeneric,
35  "MacOSX Step through ObjC Trampoline", thread, eVoteNoOpinion,
37  m_trampoline_handler(trampoline_handler),
38  m_args_addr(LLDB_INVALID_ADDRESS), m_input_values(input_values),
39  m_isa_addr(isa_addr), m_sel_addr(sel_addr), m_impl_function(NULL),
40  m_stop_others(stop_others) {}
41 
42 // Destructor
45 
47  // Setting up the memory space for the called function text might require
48  // allocations, i.e. a nested function call. This needs to be done as a
49  // PreResumeAction.
51  (void *)this);
52 }
53 
54 bool AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller() {
55  if (!m_func_sp) {
56  DiagnosticManager diagnostics;
57  m_args_addr =
58  m_trampoline_handler->SetupDispatchFunction(m_thread, m_input_values);
59 
60  if (m_args_addr == LLDB_INVALID_ADDRESS) {
61  return false;
62  }
63  m_impl_function =
64  m_trampoline_handler->GetLookupImplementationFunctionCaller();
65  ExecutionContext exc_ctx;
67  options.SetUnwindOnError(true);
68  options.SetIgnoreBreakpoints(true);
69  options.SetStopOthers(m_stop_others);
71  m_func_sp = m_impl_function->GetThreadPlanToCallFunction(
72  exc_ctx, m_args_addr, options, diagnostics);
73  m_func_sp->SetOkayToDiscard(true);
74  m_thread.QueueThreadPlan(m_func_sp, false);
75  }
76  return true;
77 }
78 
82  static_cast<AppleThreadPlanStepThroughObjCTrampoline *>(void_myself);
83  return myself->InitializeFunctionCaller();
84 }
85 
87  Stream *s, lldb::DescriptionLevel level) {
88  if (level == lldb::eDescriptionLevelBrief)
89  s->Printf("Step through ObjC trampoline");
90  else {
91  s->Printf("Stepping to implementation of ObjC method - obj: 0x%llx, isa: "
92  "0x%" PRIx64 ", sel: 0x%" PRIx64,
93  m_input_values.GetValueAtIndex(0)->GetScalar().ULongLong(),
94  m_isa_addr, m_sel_addr);
95  }
96 }
97 
99  return true;
100 }
101 
103  Event *event_ptr) {
104  // If we get asked to explain the stop it will be because something went
105  // wrong (like the implementation for selector function crashed... We're
106  // going to figure out what to do about that, so we do explain the stop.
107  return true;
108 }
109 
111  return eStateRunning;
112 }
113 
115  // First stage: we are still handling the "call a function to get the target
116  // of the dispatch"
117  if (m_func_sp) {
118  if (!m_func_sp->IsPlanComplete()) {
119  return false;
120  } else {
121  if (!m_func_sp->PlanSucceeded()) {
122  SetPlanComplete(false);
123  return true;
124  }
125  m_func_sp.reset();
126  }
127  }
128 
129  // Second stage, if all went well with the function calling, then fetch the
130  // target address, and queue up a "run to that address" plan.
131  if (!m_run_to_sp) {
132  Value target_addr_value;
133  ExecutionContext exc_ctx;
135  m_impl_function->FetchFunctionResults(exc_ctx, m_args_addr,
136  target_addr_value);
137  m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr);
138  lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong();
139  Address target_so_addr;
140  target_so_addr.SetOpcodeLoadAddress(target_addr, exc_ctx.GetTargetPtr());
142  if (target_addr == 0) {
143  if (log)
144  log->Printf("Got target implementation of 0x0, stopping.");
145  SetPlanComplete();
146  return true;
147  }
148  if (m_trampoline_handler->AddrIsMsgForward(target_addr)) {
149  if (log)
150  log->Printf(
151  "Implementation lookup returned msgForward function: 0x%" PRIx64
152  ", stopping.",
153  target_addr);
154 
155  SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(
156  eSymbolContextEverything);
157  Status status;
158  const bool abort_other_plans = false;
159  const bool first_insn = true;
160  const uint32_t frame_idx = 0;
162  abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion,
163  eVoteNoOpinion, frame_idx, status);
164  if (m_run_to_sp && status.Success())
165  m_run_to_sp->SetPrivate(true);
166  return false;
167  }
168 
169  if (log)
170  log->Printf("Running to ObjC method implementation: 0x%" PRIx64,
171  target_addr);
172 
173  ObjCLanguageRuntime *objc_runtime =
174  GetThread().GetProcess()->GetObjCLanguageRuntime();
175  assert(objc_runtime != NULL);
176  objc_runtime->AddToMethodCache(m_isa_addr, m_sel_addr, target_addr);
177  if (log)
178  log->Printf("Adding {isa-addr=0x%" PRIx64 ", sel-addr=0x%" PRIx64
179  "} = addr=0x%" PRIx64 " to cache.",
180  m_isa_addr, m_sel_addr, target_addr);
181 
182  // Extract the target address from the value:
183 
184  m_run_to_sp = std::make_shared<ThreadPlanRunToAddress>(
185  m_thread, target_so_addr, m_stop_others);
186  m_thread.QueueThreadPlan(m_run_to_sp, false);
187  m_run_to_sp->SetPrivate(true);
188  return false;
189  } else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) {
190  // Third stage, work the run to target plan.
191  SetPlanComplete();
192  return true;
193  }
194  return false;
195 }
196 
197 // The base class MischiefManaged does some cleanup - so you have to call it in
198 // your MischiefManaged derived class.
200  return IsPlanComplete();
201 }
202 
bool SetOpcodeLoadAddress(lldb::addr_t load_addr, Target *target, AddressClass addr_class=AddressClass::eInvalid, bool allow_section_end=false)
Definition: Address.cpp:360
void SetIgnoreBreakpoints(bool ignore=false)
Definition: Target.h:289
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
void DeallocateFunctionResults(ExecutionContext &exe_ctx, lldb::addr_t args_addr)
Deallocate the arguments structure.
virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop(bool abort_other_plans, SymbolContext *addr_context, bool first_insn, bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx, Status &status, bool continue_to_next_branch=false)
Queue the plan used to step out of the function at the current PC of a thread.
Definition: Thread.cpp:1454
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
Defines a symbol context baton that can be handed other debug core functions.
Definition: SymbolContext.h:33
void SetUnwindOnError(bool unwind=false)
Definition: Target.h:285
lldb::addr_t SetupDispatchFunction(Thread &thread, ValueList &dispatch_values)
void CalculateExecutionContext(ExecutionContext &exe_ctx) override
Reconstruct the object&#39;s execution context into sc.
Definition: Thread.cpp:1598
Value * GetValueAtIndex(size_t idx)
Definition: Value.cpp:701
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
bool FetchFunctionResults(ExecutionContext &exe_ctx, lldb::addr_t args_addr, Value &ret_value)
Get the result of the function from its struct.
bool ValidatePlan(Stream *error) override
Returns whether this plan could be successfully created.
Target * GetTargetPtr() const
Returns a pointer to the target object.
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
Log * GetLogIfAllCategoriesSet(uint32_t mask)
Definition: Logging.cpp:57
bool IsThreadPlanDone(ThreadPlan *plan)
Checks whether the given plan is in the completed plans for this stop.
Definition: Thread.cpp:1133
unsigned long long ULongLong(unsigned long long fail_value=0) const
Definition: Scalar.cpp:1566
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
bool Success() const
Test for success condition.
Definition: Status.cpp:287
lldb::ThreadPlanSP GetThreadPlanToCallFunction(ExecutionContext &exe_ctx, lldb::addr_t args_addr, const EvaluateExpressionOptions &options, DiagnosticManager &diagnostic_manager)
Get a thread plan to run the function this FunctionCaller was created with.
A section + offset based address class.
Definition: Address.h:80
void GetDescription(Stream *s, lldb::DescriptionLevel level) override
Print a description of this thread to the stream s.
void SetPlanComplete(bool success=true)
Definition: ThreadPlan.cpp:51
lldb::ProcessSP GetProcess() const
Definition: Thread.h:154
void SetStopOthers(bool stop_others=true)
Definition: Target.h:322
void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr)
Status QueueThreadPlan(lldb::ThreadPlanSP &plan_sp, bool abort_other_plans)
Queues a generic thread plan.
Definition: Thread.cpp:1179
uint64_t addr_t
Definition: lldb-types.h:83
Definition: SBAddress.h:15
const Scalar & GetScalar() const
Definition: Value.h:178
Thread & GetThread()
Returns the Thread that is using this thread plan.
Definition: ThreadPlan.h:372
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:395
#define LIBLLDB_LOG_STEP
Definition: Logging.h:21
void Printf(const char *format,...) __attribute__((format(printf
Definition: Log.cpp:113
An error handling class.
Definition: Status.h:44
Process or thread is running and can&#39;t be examined.