15ffd83dbSDimitry Andric //===-- ThreadPlanCallFunction.cpp ----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanCallFunction.h"
100b57cec5SDimitry Andric #include "lldb/Breakpoint/Breakpoint.h"
110b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
120b57cec5SDimitry Andric #include "lldb/Core/Address.h"
130b57cec5SDimitry Andric #include "lldb/Core/DumpRegisterValue.h"
140b57cec5SDimitry Andric #include "lldb/Core/Module.h"
150b57cec5SDimitry Andric #include "lldb/Symbol/ObjectFile.h"
160b57cec5SDimitry Andric #include "lldb/Target/ABI.h"
170b57cec5SDimitry Andric #include "lldb/Target/LanguageRuntime.h"
180b57cec5SDimitry Andric #include "lldb/Target/Process.h"
190b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
200b57cec5SDimitry Andric #include "lldb/Target/StopInfo.h"
210b57cec5SDimitry Andric #include "lldb/Target/Target.h"
220b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
230b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanRunToAddress.h"
2481ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
250b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
260b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #include <memory>
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric using namespace lldb;
310b57cec5SDimitry Andric using namespace lldb_private;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric // ThreadPlanCallFunction: Plan to call a single function
ConstructorSetup(Thread & thread,ABI * & abi,lldb::addr_t & start_load_addr,lldb::addr_t & function_load_addr)340b57cec5SDimitry Andric bool ThreadPlanCallFunction::ConstructorSetup(
350b57cec5SDimitry Andric     Thread &thread, ABI *&abi, lldb::addr_t &start_load_addr,
360b57cec5SDimitry Andric     lldb::addr_t &function_load_addr) {
37349cc55cSDimitry Andric   SetIsControllingPlan(true);
380b57cec5SDimitry Andric   SetOkayToDiscard(false);
390b57cec5SDimitry Andric   SetPrivate(true);
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric   ProcessSP process_sp(thread.GetProcess());
420b57cec5SDimitry Andric   if (!process_sp)
430b57cec5SDimitry Andric     return false;
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   abi = process_sp->GetABI().get();
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   if (!abi)
480b57cec5SDimitry Andric     return false;
490b57cec5SDimitry Andric 
5081ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   SetBreakpoints();
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
550b57cec5SDimitry Andric   // If we can't read memory at the point of the process where we are planning
560b57cec5SDimitry Andric   // to put our function, we're not going to get any further...
570b57cec5SDimitry Andric   Status error;
580b57cec5SDimitry Andric   process_sp->ReadUnsignedIntegerFromMemory(m_function_sp, 4, 0, error);
590b57cec5SDimitry Andric   if (!error.Success()) {
600b57cec5SDimitry Andric     m_constructor_errors.Printf(
610b57cec5SDimitry Andric         "Trying to put the stack in unreadable memory at: 0x%" PRIx64 ".",
620b57cec5SDimitry Andric         m_function_sp);
639dba64beSDimitry Andric     LLDB_LOGF(log, "ThreadPlanCallFunction(%p): %s.", static_cast<void *>(this),
640b57cec5SDimitry Andric               m_constructor_errors.GetData());
650b57cec5SDimitry Andric     return false;
660b57cec5SDimitry Andric   }
670b57cec5SDimitry Andric 
689dba64beSDimitry Andric   llvm::Expected<Address> start_address = GetTarget().GetEntryPointAddress();
699dba64beSDimitry Andric   if (!start_address) {
700b57cec5SDimitry Andric     m_constructor_errors.Printf(
719dba64beSDimitry Andric         "%s", llvm::toString(start_address.takeError()).c_str());
729dba64beSDimitry Andric     LLDB_LOGF(log, "ThreadPlanCallFunction(%p): %s.", static_cast<void *>(this),
730b57cec5SDimitry Andric               m_constructor_errors.GetData());
740b57cec5SDimitry Andric     return false;
750b57cec5SDimitry Andric   }
760b57cec5SDimitry Andric 
779dba64beSDimitry Andric   m_start_addr = *start_address;
780b57cec5SDimitry Andric   start_load_addr = m_start_addr.GetLoadAddress(&GetTarget());
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   // Checkpoint the thread state so we can restore it later.
810b57cec5SDimitry Andric   if (log && log->GetVerbose())
820b57cec5SDimitry Andric     ReportRegisterState("About to checkpoint thread before function call.  "
830b57cec5SDimitry Andric                         "Original register state was:");
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   if (!thread.CheckpointThreadState(m_stored_thread_state)) {
860b57cec5SDimitry Andric     m_constructor_errors.Printf("Setting up ThreadPlanCallFunction, failed to "
870b57cec5SDimitry Andric                                 "checkpoint thread state.");
889dba64beSDimitry Andric     LLDB_LOGF(log, "ThreadPlanCallFunction(%p): %s.", static_cast<void *>(this),
890b57cec5SDimitry Andric               m_constructor_errors.GetData());
900b57cec5SDimitry Andric     return false;
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric   function_load_addr = m_function_addr.GetLoadAddress(&GetTarget());
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   return true;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
ThreadPlanCallFunction(Thread & thread,const Address & function,const CompilerType & return_type,llvm::ArrayRef<addr_t> args,const EvaluateExpressionOptions & options)970b57cec5SDimitry Andric ThreadPlanCallFunction::ThreadPlanCallFunction(
980b57cec5SDimitry Andric     Thread &thread, const Address &function, const CompilerType &return_type,
990b57cec5SDimitry Andric     llvm::ArrayRef<addr_t> args, const EvaluateExpressionOptions &options)
1000b57cec5SDimitry Andric     : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread,
1010b57cec5SDimitry Andric                  eVoteNoOpinion, eVoteNoOpinion),
1020b57cec5SDimitry Andric       m_valid(false), m_stop_other_threads(options.GetStopOthers()),
1030b57cec5SDimitry Andric       m_unwind_on_error(options.DoesUnwindOnError()),
1040b57cec5SDimitry Andric       m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
1050b57cec5SDimitry Andric       m_debug_execution(options.GetDebug()),
1060b57cec5SDimitry Andric       m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function),
107972a253aSDimitry Andric       m_start_addr(), m_function_sp(0), m_subplan_sp(),
108972a253aSDimitry Andric       m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr),
109972a253aSDimitry Andric       m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(),
110972a253aSDimitry Andric       m_return_valobj_sp(), m_takedown_done(false),
1110b57cec5SDimitry Andric       m_should_clear_objc_exception_bp(false),
1120b57cec5SDimitry Andric       m_should_clear_cxx_exception_bp(false),
1130b57cec5SDimitry Andric       m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) {
1140b57cec5SDimitry Andric   lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS;
1150b57cec5SDimitry Andric   lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS;
1160b57cec5SDimitry Andric   ABI *abi = nullptr;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr))
1190b57cec5SDimitry Andric     return;
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr,
1220b57cec5SDimitry Andric                                start_load_addr, args))
1230b57cec5SDimitry Andric     return;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric   ReportRegisterState("Function call was set up.  Register state was:");
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   m_valid = true;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
ThreadPlanCallFunction(Thread & thread,const Address & function,const EvaluateExpressionOptions & options)1300b57cec5SDimitry Andric ThreadPlanCallFunction::ThreadPlanCallFunction(
1310b57cec5SDimitry Andric     Thread &thread, const Address &function,
1320b57cec5SDimitry Andric     const EvaluateExpressionOptions &options)
1330b57cec5SDimitry Andric     : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread,
1340b57cec5SDimitry Andric                  eVoteNoOpinion, eVoteNoOpinion),
1350b57cec5SDimitry Andric       m_valid(false), m_stop_other_threads(options.GetStopOthers()),
1360b57cec5SDimitry Andric       m_unwind_on_error(options.DoesUnwindOnError()),
1370b57cec5SDimitry Andric       m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
1380b57cec5SDimitry Andric       m_debug_execution(options.GetDebug()),
1390b57cec5SDimitry Andric       m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function),
140972a253aSDimitry Andric       m_start_addr(), m_function_sp(0), m_subplan_sp(),
141972a253aSDimitry Andric       m_cxx_language_runtime(nullptr), m_objc_language_runtime(nullptr),
142972a253aSDimitry Andric       m_stored_thread_state(), m_real_stop_info_sp(), m_constructor_errors(),
143972a253aSDimitry Andric       m_return_valobj_sp(), m_takedown_done(false),
1440b57cec5SDimitry Andric       m_should_clear_objc_exception_bp(false),
1450b57cec5SDimitry Andric       m_should_clear_cxx_exception_bp(false),
1460b57cec5SDimitry Andric       m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(CompilerType()) {}
1470b57cec5SDimitry Andric 
~ThreadPlanCallFunction()1480b57cec5SDimitry Andric ThreadPlanCallFunction::~ThreadPlanCallFunction() {
1490b57cec5SDimitry Andric   DoTakedown(PlanSucceeded());
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
ReportRegisterState(const char * message)1520b57cec5SDimitry Andric void ThreadPlanCallFunction::ReportRegisterState(const char *message) {
15381ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
1540b57cec5SDimitry Andric   if (log && log->GetVerbose()) {
1550b57cec5SDimitry Andric     StreamString strm;
1565ffd83dbSDimitry Andric     RegisterContext *reg_ctx = GetThread().GetRegisterContext().get();
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric     log->PutCString(message);
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric     RegisterValue reg_value;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric     for (uint32_t reg_idx = 0, num_registers = reg_ctx->GetRegisterCount();
1630b57cec5SDimitry Andric          reg_idx < num_registers; ++reg_idx) {
1640b57cec5SDimitry Andric       const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_idx);
1650b57cec5SDimitry Andric       if (reg_ctx->ReadRegister(reg_info, reg_value)) {
166fe013be4SDimitry Andric         DumpRegisterValue(reg_value, strm, *reg_info, true, false,
1670b57cec5SDimitry Andric                           eFormatDefault);
1680b57cec5SDimitry Andric         strm.EOL();
1690b57cec5SDimitry Andric       }
1700b57cec5SDimitry Andric     }
1710b57cec5SDimitry Andric     log->PutString(strm.GetString());
1720b57cec5SDimitry Andric   }
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
DoTakedown(bool success)1750b57cec5SDimitry Andric void ThreadPlanCallFunction::DoTakedown(bool success) {
17681ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   if (!m_valid) {
1790b57cec5SDimitry Andric     // Don't call DoTakedown if we were never valid to begin with.
1809dba64beSDimitry Andric     LLDB_LOGF(log,
1819dba64beSDimitry Andric               "ThreadPlanCallFunction(%p): Log called on "
1820b57cec5SDimitry Andric               "ThreadPlanCallFunction that was never valid.",
1830b57cec5SDimitry Andric               static_cast<void *>(this));
1840b57cec5SDimitry Andric     return;
1850b57cec5SDimitry Andric   }
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric   if (!m_takedown_done) {
1885ffd83dbSDimitry Andric     Thread &thread = GetThread();
1890b57cec5SDimitry Andric     if (success) {
1900b57cec5SDimitry Andric       SetReturnValue();
1910b57cec5SDimitry Andric     }
1929dba64beSDimitry Andric     LLDB_LOGF(log,
1939dba64beSDimitry Andric               "ThreadPlanCallFunction(%p): DoTakedown called for thread "
1940b57cec5SDimitry Andric               "0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n",
1955ffd83dbSDimitry Andric               static_cast<void *>(this), m_tid, m_valid, IsPlanComplete());
1960b57cec5SDimitry Andric     m_takedown_done = true;
1970b57cec5SDimitry Andric     m_stop_address =
1985ffd83dbSDimitry Andric         thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
1990b57cec5SDimitry Andric     m_real_stop_info_sp = GetPrivateStopInfo();
2005ffd83dbSDimitry Andric     if (!thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) {
2019dba64beSDimitry Andric       LLDB_LOGF(log,
2029dba64beSDimitry Andric                 "ThreadPlanCallFunction(%p): DoTakedown failed to restore "
2030b57cec5SDimitry Andric                 "register state",
2040b57cec5SDimitry Andric                 static_cast<void *>(this));
2050b57cec5SDimitry Andric     }
2060b57cec5SDimitry Andric     SetPlanComplete(success);
2070b57cec5SDimitry Andric     ClearBreakpoints();
2080b57cec5SDimitry Andric     if (log && log->GetVerbose())
2090b57cec5SDimitry Andric       ReportRegisterState("Restoring thread state after function call.  "
2100b57cec5SDimitry Andric                           "Restored register state:");
2110b57cec5SDimitry Andric   } else {
2129dba64beSDimitry Andric     LLDB_LOGF(log,
2139dba64beSDimitry Andric               "ThreadPlanCallFunction(%p): DoTakedown called as no-op for "
2140b57cec5SDimitry Andric               "thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n",
2155ffd83dbSDimitry Andric               static_cast<void *>(this), m_tid, m_valid, IsPlanComplete());
2160b57cec5SDimitry Andric   }
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
DidPop()219349cc55cSDimitry Andric void ThreadPlanCallFunction::DidPop() { DoTakedown(PlanSucceeded()); }
2200b57cec5SDimitry Andric 
GetDescription(Stream * s,DescriptionLevel level)2210b57cec5SDimitry Andric void ThreadPlanCallFunction::GetDescription(Stream *s, DescriptionLevel level) {
2220b57cec5SDimitry Andric   if (level == eDescriptionLevelBrief) {
2230b57cec5SDimitry Andric     s->Printf("Function call thread plan");
2240b57cec5SDimitry Andric   } else {
2250b57cec5SDimitry Andric     s->Printf("Thread plan to call 0x%" PRIx64,
2265ffd83dbSDimitry Andric               m_function_addr.GetLoadAddress(&GetTarget()));
2270b57cec5SDimitry Andric   }
2280b57cec5SDimitry Andric }
2290b57cec5SDimitry Andric 
ValidatePlan(Stream * error)2300b57cec5SDimitry Andric bool ThreadPlanCallFunction::ValidatePlan(Stream *error) {
2310b57cec5SDimitry Andric   if (!m_valid) {
2320b57cec5SDimitry Andric     if (error) {
2330b57cec5SDimitry Andric       if (m_constructor_errors.GetSize() > 0)
2340b57cec5SDimitry Andric         error->PutCString(m_constructor_errors.GetString());
2350b57cec5SDimitry Andric       else
2360b57cec5SDimitry Andric         error->PutCString("Unknown error");
2370b57cec5SDimitry Andric     }
2380b57cec5SDimitry Andric     return false;
2390b57cec5SDimitry Andric   }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric   return true;
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric 
ShouldReportStop(Event * event_ptr)2440b57cec5SDimitry Andric Vote ThreadPlanCallFunction::ShouldReportStop(Event *event_ptr) {
2450b57cec5SDimitry Andric   if (m_takedown_done || IsPlanComplete())
2460b57cec5SDimitry Andric     return eVoteYes;
2470b57cec5SDimitry Andric   else
2480b57cec5SDimitry Andric     return ThreadPlan::ShouldReportStop(event_ptr);
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
DoPlanExplainsStop(Event * event_ptr)2510b57cec5SDimitry Andric bool ThreadPlanCallFunction::DoPlanExplainsStop(Event *event_ptr) {
25281ad6265SDimitry Andric   Log *log(GetLog(LLDBLog::Step | LLDBLog::Process));
2530b57cec5SDimitry Andric   m_real_stop_info_sp = GetPrivateStopInfo();
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   // If our subplan knows why we stopped, even if it's done (which would
2560b57cec5SDimitry Andric   // forward the question to us) we answer yes.
2570b57cec5SDimitry Andric   if (m_subplan_sp && m_subplan_sp->PlanExplainsStop(event_ptr)) {
2580b57cec5SDimitry Andric     SetPlanComplete();
2590b57cec5SDimitry Andric     return true;
2600b57cec5SDimitry Andric   }
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric   // Check if the breakpoint is one of ours.
2630b57cec5SDimitry Andric 
2640b57cec5SDimitry Andric   StopReason stop_reason;
2650b57cec5SDimitry Andric   if (!m_real_stop_info_sp)
2660b57cec5SDimitry Andric     stop_reason = eStopReasonNone;
2670b57cec5SDimitry Andric   else
2680b57cec5SDimitry Andric     stop_reason = m_real_stop_info_sp->GetStopReason();
269e8d8bef9SDimitry Andric   LLDB_LOG(log,
270e8d8bef9SDimitry Andric            "ThreadPlanCallFunction::PlanExplainsStop: Got stop reason - {0}.",
271e8d8bef9SDimitry Andric            Thread::StopReasonAsString(stop_reason));
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric   if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop())
2740b57cec5SDimitry Andric     return true;
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   // One more quirk here.  If this event was from Halt interrupting the target,
2770b57cec5SDimitry Andric   // then we should not consider ourselves complete.  Return true to
2780b57cec5SDimitry Andric   // acknowledge the stop.
2790b57cec5SDimitry Andric   if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr)) {
2809dba64beSDimitry Andric     LLDB_LOGF(log, "ThreadPlanCallFunction::PlanExplainsStop: The event is an "
2810b57cec5SDimitry Andric                    "Interrupt, returning true.");
2820b57cec5SDimitry Andric     return true;
2830b57cec5SDimitry Andric   }
2840b57cec5SDimitry Andric   // We control breakpoints separately from other "stop reasons."  So first,
2850b57cec5SDimitry Andric   // check the case where we stopped for an internal breakpoint, in that case,
2860b57cec5SDimitry Andric   // continue on. If it is not an internal breakpoint, consult
2870b57cec5SDimitry Andric   // m_ignore_breakpoints.
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   if (stop_reason == eStopReasonBreakpoint) {
2900b57cec5SDimitry Andric     uint64_t break_site_id = m_real_stop_info_sp->GetValue();
2910b57cec5SDimitry Andric     BreakpointSiteSP bp_site_sp;
2925ffd83dbSDimitry Andric     bp_site_sp = m_process.GetBreakpointSiteList().FindByID(break_site_id);
2930b57cec5SDimitry Andric     if (bp_site_sp) {
294*c9157d92SDimitry Andric       uint32_t num_owners = bp_site_sp->GetNumberOfConstituents();
2950b57cec5SDimitry Andric       bool is_internal = true;
2960b57cec5SDimitry Andric       for (uint32_t i = 0; i < num_owners; i++) {
297*c9157d92SDimitry Andric         Breakpoint &bp = bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint();
2989dba64beSDimitry Andric         LLDB_LOGF(log,
2999dba64beSDimitry Andric                   "ThreadPlanCallFunction::PlanExplainsStop: hit "
3000b57cec5SDimitry Andric                   "breakpoint %d while calling function",
3010b57cec5SDimitry Andric                   bp.GetID());
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric         if (!bp.IsInternal()) {
3040b57cec5SDimitry Andric           is_internal = false;
3050b57cec5SDimitry Andric           break;
3060b57cec5SDimitry Andric         }
3070b57cec5SDimitry Andric       }
3080b57cec5SDimitry Andric       if (is_internal) {
3099dba64beSDimitry Andric         LLDB_LOGF(log, "ThreadPlanCallFunction::PlanExplainsStop hit an "
3100b57cec5SDimitry Andric                        "internal breakpoint, not stopping.");
3110b57cec5SDimitry Andric         return false;
3120b57cec5SDimitry Andric       }
3130b57cec5SDimitry Andric     }
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric     if (m_ignore_breakpoints) {
3169dba64beSDimitry Andric       LLDB_LOGF(log,
3179dba64beSDimitry Andric                 "ThreadPlanCallFunction::PlanExplainsStop: we are ignoring "
3180b57cec5SDimitry Andric                 "breakpoints, overriding breakpoint stop info ShouldStop, "
3190b57cec5SDimitry Andric                 "returning true");
3200b57cec5SDimitry Andric       m_real_stop_info_sp->OverrideShouldStop(false);
3210b57cec5SDimitry Andric       return true;
3220b57cec5SDimitry Andric     } else {
3239dba64beSDimitry Andric       LLDB_LOGF(log, "ThreadPlanCallFunction::PlanExplainsStop: we are not "
3240b57cec5SDimitry Andric                      "ignoring breakpoints, overriding breakpoint stop info "
3250b57cec5SDimitry Andric                      "ShouldStop, returning true");
3260b57cec5SDimitry Andric       m_real_stop_info_sp->OverrideShouldStop(true);
3270b57cec5SDimitry Andric       return false;
3280b57cec5SDimitry Andric     }
3290b57cec5SDimitry Andric   } else if (!m_unwind_on_error) {
3300b57cec5SDimitry Andric     // If we don't want to discard this plan, than any stop we don't understand
3310b57cec5SDimitry Andric     // should be propagated up the stack.
3320b57cec5SDimitry Andric     return false;
3330b57cec5SDimitry Andric   } else {
3340b57cec5SDimitry Andric     // If the subplan is running, any crashes are attributable to us. If we
3350b57cec5SDimitry Andric     // want to discard the plan, then we say we explain the stop but if we are
3360b57cec5SDimitry Andric     // going to be discarded, let whoever is above us explain the stop. But
3370b57cec5SDimitry Andric     // don't discard the plan if the stop would restart itself (for instance if
3380b57cec5SDimitry Andric     // it is a signal that is set not to stop.  Check that here first.  We just
3390b57cec5SDimitry Andric     // say we explain the stop but aren't done and everything will continue on
3400b57cec5SDimitry Andric     // from there.
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric     if (m_real_stop_info_sp &&
3430b57cec5SDimitry Andric         m_real_stop_info_sp->ShouldStopSynchronous(event_ptr)) {
3440b57cec5SDimitry Andric       SetPlanComplete(false);
3450b57cec5SDimitry Andric       return m_subplan_sp ? m_unwind_on_error : false;
3460b57cec5SDimitry Andric     } else
3470b57cec5SDimitry Andric       return true;
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
ShouldStop(Event * event_ptr)3510b57cec5SDimitry Andric bool ThreadPlanCallFunction::ShouldStop(Event *event_ptr) {
3520b57cec5SDimitry Andric   // We do some computation in DoPlanExplainsStop that may or may not set the
3530b57cec5SDimitry Andric   // plan as complete. We need to do that here to make sure our state is
3540b57cec5SDimitry Andric   // correct.
3550b57cec5SDimitry Andric   DoPlanExplainsStop(event_ptr);
3560b57cec5SDimitry Andric 
3570b57cec5SDimitry Andric   if (IsPlanComplete()) {
3580b57cec5SDimitry Andric     ReportRegisterState("Function completed.  Register state was:");
3590b57cec5SDimitry Andric     return true;
3600b57cec5SDimitry Andric   } else {
3610b57cec5SDimitry Andric     return false;
3620b57cec5SDimitry Andric   }
3630b57cec5SDimitry Andric }
3640b57cec5SDimitry Andric 
StopOthers()3650b57cec5SDimitry Andric bool ThreadPlanCallFunction::StopOthers() { return m_stop_other_threads; }
3660b57cec5SDimitry Andric 
GetPlanRunState()3670b57cec5SDimitry Andric StateType ThreadPlanCallFunction::GetPlanRunState() { return eStateRunning; }
3680b57cec5SDimitry Andric 
DidPush()3690b57cec5SDimitry Andric void ThreadPlanCallFunction::DidPush() {
3700b57cec5SDimitry Andric   //#define SINGLE_STEP_EXPRESSIONS
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric   // Now set the thread state to "no reason" so we don't run with whatever
3730b57cec5SDimitry Andric   // signal was outstanding... Wait till the plan is pushed so we aren't
3740b57cec5SDimitry Andric   // changing the stop info till we're about to run.
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric   GetThread().SetStopInfoToNothing();
3770b57cec5SDimitry Andric 
3780b57cec5SDimitry Andric #ifndef SINGLE_STEP_EXPRESSIONS
3795ffd83dbSDimitry Andric   Thread &thread = GetThread();
3805ffd83dbSDimitry Andric   m_subplan_sp = std::make_shared<ThreadPlanRunToAddress>(thread, m_start_addr,
3815ffd83dbSDimitry Andric                                                           m_stop_other_threads);
3820b57cec5SDimitry Andric 
3835ffd83dbSDimitry Andric   thread.QueueThreadPlan(m_subplan_sp, false);
3840b57cec5SDimitry Andric   m_subplan_sp->SetPrivate(true);
3850b57cec5SDimitry Andric #endif
3860b57cec5SDimitry Andric }
3870b57cec5SDimitry Andric 
WillStop()3880b57cec5SDimitry Andric bool ThreadPlanCallFunction::WillStop() { return true; }
3890b57cec5SDimitry Andric 
MischiefManaged()3900b57cec5SDimitry Andric bool ThreadPlanCallFunction::MischiefManaged() {
39181ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric   if (IsPlanComplete()) {
3949dba64beSDimitry Andric     LLDB_LOGF(log, "ThreadPlanCallFunction(%p): Completed call function plan.",
3950b57cec5SDimitry Andric               static_cast<void *>(this));
3960b57cec5SDimitry Andric 
3970b57cec5SDimitry Andric     ThreadPlan::MischiefManaged();
3980b57cec5SDimitry Andric     return true;
3990b57cec5SDimitry Andric   } else {
4000b57cec5SDimitry Andric     return false;
4010b57cec5SDimitry Andric   }
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric 
SetBreakpoints()4040b57cec5SDimitry Andric void ThreadPlanCallFunction::SetBreakpoints() {
4055ffd83dbSDimitry Andric   if (m_trap_exceptions) {
4060b57cec5SDimitry Andric     m_cxx_language_runtime =
4075ffd83dbSDimitry Andric         m_process.GetLanguageRuntime(eLanguageTypeC_plus_plus);
4085ffd83dbSDimitry Andric     m_objc_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeObjC);
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric     if (m_cxx_language_runtime) {
4110b57cec5SDimitry Andric       m_should_clear_cxx_exception_bp =
4120b57cec5SDimitry Andric           !m_cxx_language_runtime->ExceptionBreakpointsAreSet();
4130b57cec5SDimitry Andric       m_cxx_language_runtime->SetExceptionBreakpoints();
4140b57cec5SDimitry Andric     }
4150b57cec5SDimitry Andric     if (m_objc_language_runtime) {
4160b57cec5SDimitry Andric       m_should_clear_objc_exception_bp =
4170b57cec5SDimitry Andric           !m_objc_language_runtime->ExceptionBreakpointsAreSet();
4180b57cec5SDimitry Andric       m_objc_language_runtime->SetExceptionBreakpoints();
4190b57cec5SDimitry Andric     }
4200b57cec5SDimitry Andric   }
4210b57cec5SDimitry Andric }
4220b57cec5SDimitry Andric 
ClearBreakpoints()4230b57cec5SDimitry Andric void ThreadPlanCallFunction::ClearBreakpoints() {
4240b57cec5SDimitry Andric   if (m_trap_exceptions) {
4250b57cec5SDimitry Andric     if (m_cxx_language_runtime && m_should_clear_cxx_exception_bp)
4260b57cec5SDimitry Andric       m_cxx_language_runtime->ClearExceptionBreakpoints();
4270b57cec5SDimitry Andric     if (m_objc_language_runtime && m_should_clear_objc_exception_bp)
4280b57cec5SDimitry Andric       m_objc_language_runtime->ClearExceptionBreakpoints();
4290b57cec5SDimitry Andric   }
4300b57cec5SDimitry Andric }
4310b57cec5SDimitry Andric 
BreakpointsExplainStop()4320b57cec5SDimitry Andric bool ThreadPlanCallFunction::BreakpointsExplainStop() {
4330b57cec5SDimitry Andric   StopInfoSP stop_info_sp = GetPrivateStopInfo();
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   if (m_trap_exceptions) {
4360b57cec5SDimitry Andric     if ((m_cxx_language_runtime &&
4370b57cec5SDimitry Andric          m_cxx_language_runtime->ExceptionBreakpointsExplainStop(
4380b57cec5SDimitry Andric              stop_info_sp)) ||
4390b57cec5SDimitry Andric         (m_objc_language_runtime &&
4400b57cec5SDimitry Andric          m_objc_language_runtime->ExceptionBreakpointsExplainStop(
4410b57cec5SDimitry Andric              stop_info_sp))) {
44281ad6265SDimitry Andric       Log *log = GetLog(LLDBLog::Step);
4439dba64beSDimitry Andric       LLDB_LOGF(log, "ThreadPlanCallFunction::BreakpointsExplainStop - Hit an "
4440b57cec5SDimitry Andric                      "exception breakpoint, setting plan complete.");
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric       SetPlanComplete(false);
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric       // If the user has set the ObjC language breakpoint, it would normally
4490b57cec5SDimitry Andric       // get priority over our internal catcher breakpoint, but in this case we
4500b57cec5SDimitry Andric       // can't let that happen, so force the ShouldStop here.
4510b57cec5SDimitry Andric       stop_info_sp->OverrideShouldStop(true);
4520b57cec5SDimitry Andric       return true;
4530b57cec5SDimitry Andric     }
4540b57cec5SDimitry Andric   }
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric   return false;
4570b57cec5SDimitry Andric }
4580b57cec5SDimitry Andric 
SetStopOthers(bool new_value)4590b57cec5SDimitry Andric void ThreadPlanCallFunction::SetStopOthers(bool new_value) {
4600b57cec5SDimitry Andric   m_subplan_sp->SetStopOthers(new_value);
4610b57cec5SDimitry Andric }
4620b57cec5SDimitry Andric 
RestoreThreadState()463fe6060f1SDimitry Andric void ThreadPlanCallFunction::RestoreThreadState() {
464fe6060f1SDimitry Andric   GetThread().RestoreThreadStateFromCheckpoint(m_stored_thread_state);
4650b57cec5SDimitry Andric }
4660b57cec5SDimitry Andric 
SetReturnValue()4670b57cec5SDimitry Andric void ThreadPlanCallFunction::SetReturnValue() {
4685ffd83dbSDimitry Andric   const ABI *abi = m_process.GetABI().get();
4690b57cec5SDimitry Andric   if (abi && m_return_type.IsValid()) {
4700b57cec5SDimitry Andric     const bool persistent = false;
4710b57cec5SDimitry Andric     m_return_valobj_sp =
4725ffd83dbSDimitry Andric         abi->GetReturnValueObject(GetThread(), m_return_type, persistent);
4730b57cec5SDimitry Andric   }
4740b57cec5SDimitry Andric }
475