130fdc8d8SChris Lattner //===-- ThreadPlanCallFunction.cpp ------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanCallFunction.h"
1130fdc8d8SChris Lattner 
1230fdc8d8SChris Lattner // C Includes
1330fdc8d8SChris Lattner // C++ Includes
1430fdc8d8SChris Lattner // Other libraries and framework includes
156db73ca5SSean Callanan #include "llvm/Support/MachO.h"
1630fdc8d8SChris Lattner // Project includes
1730fdc8d8SChris Lattner #include "lldb/lldb-private-log.h"
1840d871faSJim Ingham #include "lldb/Breakpoint/Breakpoint.h"
1940d871faSJim Ingham #include "lldb/Breakpoint/BreakpointLocation.h"
2030fdc8d8SChris Lattner #include "lldb/Core/Address.h"
2130fdc8d8SChris Lattner #include "lldb/Core/Log.h"
2230fdc8d8SChris Lattner #include "lldb/Core/Stream.h"
23f211510fSSean Callanan #include "lldb/Target/LanguageRuntime.h"
2430fdc8d8SChris Lattner #include "lldb/Target/Process.h"
2530fdc8d8SChris Lattner #include "lldb/Target/RegisterContext.h"
2640d871faSJim Ingham #include "lldb/Target/StopInfo.h"
2730fdc8d8SChris Lattner #include "lldb/Target/Target.h"
2830fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
2930fdc8d8SChris Lattner #include "lldb/Target/ThreadPlanRunToAddress.h"
3030fdc8d8SChris Lattner 
3130fdc8d8SChris Lattner using namespace lldb;
3230fdc8d8SChris Lattner using namespace lldb_private;
3330fdc8d8SChris Lattner 
3430fdc8d8SChris Lattner //----------------------------------------------------------------------
3530fdc8d8SChris Lattner // ThreadPlanCallFunction: Plan to call a single function
3630fdc8d8SChris Lattner //----------------------------------------------------------------------
3730fdc8d8SChris Lattner 
3830fdc8d8SChris Lattner ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
3930fdc8d8SChris Lattner                                                 Address &function,
4030fdc8d8SChris Lattner                                                 lldb::addr_t arg,
4130fdc8d8SChris Lattner                                                 bool stop_other_threads,
42fc55f5d1SSean Callanan                                                 bool discard_on_error,
4317827830SSean Callanan                                                 lldb::addr_t *this_arg,
4417827830SSean Callanan                                                 lldb::addr_t *cmd_arg) :
45b01e742aSJim Ingham     ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
4630fdc8d8SChris Lattner     m_valid (false),
471ee0d4f7SBenjamin Kramer     m_stop_other_threads (stop_other_threads),
4830fdc8d8SChris Lattner     m_arg_addr (arg),
4930fdc8d8SChris Lattner     m_args (NULL),
501ee0d4f7SBenjamin Kramer     m_process (thread.GetProcess()),
519da3683cSJim Ingham     m_thread (thread),
52e359d9b7SSean Callanan     m_takedown_done (false),
53e359d9b7SSean Callanan     m_function_sp(NULL)
5430fdc8d8SChris Lattner {
5530fdc8d8SChris Lattner     SetOkayToDiscard (discard_on_error);
5630fdc8d8SChris Lattner 
5730fdc8d8SChris Lattner     Process& process = thread.GetProcess();
5830fdc8d8SChris Lattner     Target& target = process.GetTarget();
5931f1d2f5SGreg Clayton     const ABI *abi = process.GetABI().get();
6030fdc8d8SChris Lattner 
6130fdc8d8SChris Lattner     if (!abi)
6230fdc8d8SChris Lattner         return;
6330fdc8d8SChris Lattner 
6477787033SJim Ingham     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
6577787033SJim Ingham 
666db73ca5SSean Callanan     SetBreakpoints();
676db73ca5SSean Callanan 
68e359d9b7SSean Callanan     m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
6930fdc8d8SChris Lattner 
7030fdc8d8SChris Lattner     ModuleSP executableModuleSP (target.GetExecutableModule());
7130fdc8d8SChris Lattner 
72672e6f59SJim Ingham     if (!executableModuleSP)
73672e6f59SJim Ingham     {
74672e6f59SJim Ingham         log->Printf ("Can't execute code without an executable module.");
7530fdc8d8SChris Lattner         return;
76672e6f59SJim Ingham     }
77672e6f59SJim Ingham     else
78672e6f59SJim Ingham     {
79672e6f59SJim Ingham         ObjectFile *objectFile = executableModuleSP->GetObjectFile();
80672e6f59SJim Ingham         if (!objectFile)
81672e6f59SJim Ingham         {
82672e6f59SJim Ingham             log->Printf ("Could not find object file for module \"%s\".",
83672e6f59SJim Ingham                          executableModuleSP->GetFileSpec().GetFilename().AsCString());
84672e6f59SJim Ingham             return;
85672e6f59SJim Ingham         }
86672e6f59SJim Ingham         m_start_addr = objectFile->GetEntryPointAddress();
87672e6f59SJim Ingham         if (!m_start_addr.IsValid())
88672e6f59SJim Ingham         {
89672e6f59SJim Ingham             log->Printf ("Could not find entry point address for executable module \"%s\".",
90672e6f59SJim Ingham                          executableModuleSP->GetFileSpec().GetFilename().AsCString());
91672e6f59SJim Ingham             return;
92672e6f59SJim Ingham         }
93672e6f59SJim Ingham     }
9430fdc8d8SChris Lattner 
95f5e56de0SGreg Clayton     lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
9630fdc8d8SChris Lattner 
9777787033SJim Ingham     // Checkpoint the thread state so we can restore it later.
989da3683cSJim Ingham     if (log && log->GetVerbose())
999da3683cSJim Ingham         ReportRegisterState ("About to checkpoint thread before function call.  Original register state was:");
1009da3683cSJim Ingham 
10177787033SJim Ingham     if (!thread.CheckpointThreadState (m_stored_thread_state))
10277787033SJim Ingham     {
10377787033SJim Ingham         if (log)
10477787033SJim Ingham             log->Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state.");
10530fdc8d8SChris Lattner         return;
10677787033SJim Ingham     }
10777787033SJim Ingham     // Now set the thread state to "no reason" so we don't run with whatever signal was outstanding...
10877787033SJim Ingham     thread.SetStopInfoToNothing();
10930fdc8d8SChris Lattner 
11030fdc8d8SChris Lattner     m_function_addr = function;
111f5e56de0SGreg Clayton     lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
11230fdc8d8SChris Lattner 
113*fdeb1563SGreg Clayton     if (this_arg && cmd_arg)
114*fdeb1563SGreg Clayton     {
11530fdc8d8SChris Lattner         if (!abi->PrepareTrivialCall (thread,
116e359d9b7SSean Callanan                                       m_function_sp,
11730fdc8d8SChris Lattner                                       FunctionLoadAddr,
11830fdc8d8SChris Lattner                                       StartLoadAddr,
11917827830SSean Callanan                                       this_arg,
120*fdeb1563SGreg Clayton                                       cmd_arg,
121*fdeb1563SGreg Clayton                                       &m_arg_addr))
12230fdc8d8SChris Lattner             return;
123*fdeb1563SGreg Clayton     }
124*fdeb1563SGreg Clayton     else if (this_arg)
125*fdeb1563SGreg Clayton     {
126*fdeb1563SGreg Clayton         if (!abi->PrepareTrivialCall (thread,
127*fdeb1563SGreg Clayton                                       m_function_sp,
128*fdeb1563SGreg Clayton                                       FunctionLoadAddr,
129*fdeb1563SGreg Clayton                                       StartLoadAddr,
130*fdeb1563SGreg Clayton                                       this_arg,
131*fdeb1563SGreg Clayton                                       &m_arg_addr,
132*fdeb1563SGreg Clayton                                       NULL))
133*fdeb1563SGreg Clayton             return;
134*fdeb1563SGreg Clayton     }
135*fdeb1563SGreg Clayton     else
136*fdeb1563SGreg Clayton     {
137*fdeb1563SGreg Clayton         if (!abi->PrepareTrivialCall (thread,
138*fdeb1563SGreg Clayton                                       m_function_sp,
139*fdeb1563SGreg Clayton                                       FunctionLoadAddr,
140*fdeb1563SGreg Clayton                                       StartLoadAddr,
141*fdeb1563SGreg Clayton                                       &m_arg_addr,
142*fdeb1563SGreg Clayton                                       NULL,
143*fdeb1563SGreg Clayton                                       NULL))
144*fdeb1563SGreg Clayton             return;
145*fdeb1563SGreg Clayton     }
14630fdc8d8SChris Lattner 
1479da3683cSJim Ingham     ReportRegisterState ("Function call was set up.  Register state was:");
1489da3683cSJim Ingham 
1499da3683cSJim Ingham     m_valid = true;
1509da3683cSJim Ingham }
1519da3683cSJim Ingham 
1529da3683cSJim Ingham ThreadPlanCallFunction::~ThreadPlanCallFunction ()
1539da3683cSJim Ingham {
1549da3683cSJim Ingham }
1559da3683cSJim Ingham 
1569da3683cSJim Ingham void
1579da3683cSJim Ingham ThreadPlanCallFunction::ReportRegisterState (const char *message)
1589da3683cSJim Ingham {
1599da3683cSJim Ingham     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
160ece96492SSean Callanan     if (log)
161ece96492SSean Callanan     {
1625ccbd294SGreg Clayton         RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
163ece96492SSean Callanan 
1649da3683cSJim Ingham         log->PutCString(message);
165ece96492SSean Callanan 
166ece96492SSean Callanan         for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
167ece96492SSean Callanan              register_index < num_registers;
168ece96492SSean Callanan              ++register_index)
169ece96492SSean Callanan         {
170ece96492SSean Callanan             const char *register_name = reg_ctx->GetRegisterName(register_index);
171ece96492SSean Callanan             uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
172ece96492SSean Callanan 
173ece96492SSean Callanan             log->Printf("  %s = 0x%llx", register_name, register_value);
174ece96492SSean Callanan         }
175ece96492SSean Callanan     }
17610af7c43SSean Callanan }
17710af7c43SSean Callanan 
17810af7c43SSean Callanan void
17910af7c43SSean Callanan ThreadPlanCallFunction::DoTakedown ()
18010af7c43SSean Callanan {
1819da3683cSJim Ingham     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
1829da3683cSJim Ingham     if (!m_takedown_done)
18377787033SJim Ingham     {
1849da3683cSJim Ingham         if (log)
1859da3683cSJim Ingham             log->Printf ("DoTakedown called for thread 0x%4.4x, m_valid: %d complete: %d.\n", m_thread.GetID(), m_valid, IsPlanComplete());
1869da3683cSJim Ingham         m_takedown_done = true;
18777787033SJim Ingham         m_thread.RestoreThreadStateFromCheckpoint(m_stored_thread_state);
18810af7c43SSean Callanan         SetPlanComplete();
18910af7c43SSean Callanan         ClearBreakpoints();
1909da3683cSJim Ingham         if (log && log->GetVerbose())
1919da3683cSJim Ingham             ReportRegisterState ("Restoring thread state after function call.  Restored register state:");
1922c36439cSJim Ingham 
1939da3683cSJim Ingham     }
1949da3683cSJim Ingham     else
1959da3683cSJim Ingham     {
1969da3683cSJim Ingham         if (log)
1979da3683cSJim Ingham             log->Printf ("DoTakedown called as no-op for thread 0x%4.4x, m_valid: %d complete: %d.\n", m_thread.GetID(), m_valid, IsPlanComplete());
19830fdc8d8SChris Lattner     }
19977787033SJim Ingham }
20030fdc8d8SChris Lattner 
20130fdc8d8SChris Lattner void
202bda4e5ebSJim Ingham ThreadPlanCallFunction::WillPop ()
203bda4e5ebSJim Ingham {
204bda4e5ebSJim Ingham     DoTakedown();
205bda4e5ebSJim Ingham }
206bda4e5ebSJim Ingham 
207bda4e5ebSJim Ingham void
20830fdc8d8SChris Lattner ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
20930fdc8d8SChris Lattner {
21030fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
21130fdc8d8SChris Lattner     {
21230fdc8d8SChris Lattner         s->Printf("Function call thread plan");
21330fdc8d8SChris Lattner     }
21430fdc8d8SChris Lattner     else
21530fdc8d8SChris Lattner     {
21630fdc8d8SChris Lattner         if (m_args)
217f5e56de0SGreg Clayton             s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
21830fdc8d8SChris Lattner         else
219f5e56de0SGreg Clayton             s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
22030fdc8d8SChris Lattner     }
22130fdc8d8SChris Lattner }
22230fdc8d8SChris Lattner 
22330fdc8d8SChris Lattner bool
22430fdc8d8SChris Lattner ThreadPlanCallFunction::ValidatePlan (Stream *error)
22530fdc8d8SChris Lattner {
22630fdc8d8SChris Lattner     if (!m_valid)
22730fdc8d8SChris Lattner         return false;
22830fdc8d8SChris Lattner 
22930fdc8d8SChris Lattner     return true;
23030fdc8d8SChris Lattner }
23130fdc8d8SChris Lattner 
23230fdc8d8SChris Lattner bool
23330fdc8d8SChris Lattner ThreadPlanCallFunction::PlanExplainsStop ()
23430fdc8d8SChris Lattner {
23540d871faSJim Ingham     // If our subplan knows why we stopped, even if it's done (which would forward the question to us)
23640d871faSJim Ingham     // we answer yes.
23740d871faSJim Ingham     if(m_subplan_sp.get() != NULL && m_subplan_sp->PlanExplainsStop())
23840d871faSJim Ingham         return true;
2393e6fedcaSSean Callanan 
240c98aca60SSean Callanan     // Check if the breakpoint is one of ours.
241c98aca60SSean Callanan 
242c98aca60SSean Callanan     if (BreakpointsExplainStop())
243c98aca60SSean Callanan         return true;
244c98aca60SSean Callanan 
24540d871faSJim Ingham     // If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
24640d871faSJim Ingham     if (!OkayToDiscard())
24740d871faSJim Ingham         return false;
24840d871faSJim Ingham 
24940d871faSJim Ingham     // Otherwise, check the case where we stopped for an internal breakpoint, in that case, continue on.
25040d871faSJim Ingham     // If it is not an internal breakpoint, consult OkayToDiscard.
25140d871faSJim Ingham     lldb::StopInfoSP stop_info_sp = GetPrivateStopReason();
2526db73ca5SSean Callanan 
25340d871faSJim Ingham     if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
25440d871faSJim Ingham     {
25540d871faSJim Ingham         uint64_t break_site_id = stop_info_sp->GetValue();
25640d871faSJim Ingham         lldb::BreakpointSiteSP bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID(break_site_id);
25740d871faSJim Ingham         if (bp_site_sp)
25840d871faSJim Ingham         {
25940d871faSJim Ingham             uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
26040d871faSJim Ingham             bool is_internal = true;
26140d871faSJim Ingham             for (uint32_t i = 0; i < num_owners; i++)
26240d871faSJim Ingham             {
2636db73ca5SSean Callanan                 Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
2646db73ca5SSean Callanan 
2656db73ca5SSean Callanan                 if (!bp.IsInternal())
26640d871faSJim Ingham                 {
26740d871faSJim Ingham                     is_internal = false;
26840d871faSJim Ingham                     break;
26940d871faSJim Ingham                 }
27040d871faSJim Ingham             }
27140d871faSJim Ingham             if (is_internal)
27240d871faSJim Ingham                 return false;
27340d871faSJim Ingham         }
27440d871faSJim Ingham 
27540d871faSJim Ingham         return OkayToDiscard();
27640d871faSJim Ingham     }
27740d871faSJim Ingham     else
27840d871faSJim Ingham     {
27940d871faSJim Ingham         // If the subplan is running, any crashes are attributable to us.
2802c36439cSJim Ingham         // If we want to discard the plan, then we say we explain the stop
2812c36439cSJim Ingham         // but if we are going to be discarded, let whoever is above us
2822c36439cSJim Ingham         // explain the stop.
2832c36439cSJim Ingham         return ((m_subplan_sp.get() != NULL) && !OkayToDiscard());
28430fdc8d8SChris Lattner     }
28540d871faSJim Ingham }
28630fdc8d8SChris Lattner 
28730fdc8d8SChris Lattner bool
28830fdc8d8SChris Lattner ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
28930fdc8d8SChris Lattner {
29030fdc8d8SChris Lattner     if (PlanExplainsStop())
29130fdc8d8SChris Lattner     {
2929da3683cSJim Ingham         ReportRegisterState ("Function completed.  Register state was:");
2935300d37aSSean Callanan 
29410af7c43SSean Callanan         DoTakedown();
2956db73ca5SSean Callanan 
29630fdc8d8SChris Lattner         return true;
29730fdc8d8SChris Lattner     }
29830fdc8d8SChris Lattner     else
29930fdc8d8SChris Lattner     {
30030fdc8d8SChris Lattner         return false;
30130fdc8d8SChris Lattner     }
30230fdc8d8SChris Lattner }
30330fdc8d8SChris Lattner 
30430fdc8d8SChris Lattner bool
30530fdc8d8SChris Lattner ThreadPlanCallFunction::StopOthers ()
30630fdc8d8SChris Lattner {
30730fdc8d8SChris Lattner     return m_stop_other_threads;
30830fdc8d8SChris Lattner }
30930fdc8d8SChris Lattner 
31030fdc8d8SChris Lattner void
31130fdc8d8SChris Lattner ThreadPlanCallFunction::SetStopOthers (bool new_value)
31230fdc8d8SChris Lattner {
31330fdc8d8SChris Lattner     if (m_subplan_sp)
31430fdc8d8SChris Lattner     {
31530fdc8d8SChris Lattner         ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
31630fdc8d8SChris Lattner         address_plan->SetStopOthers(new_value);
31730fdc8d8SChris Lattner     }
31830fdc8d8SChris Lattner     m_stop_other_threads = new_value;
31930fdc8d8SChris Lattner }
32030fdc8d8SChris Lattner 
32130fdc8d8SChris Lattner StateType
32206e827ccSJim Ingham ThreadPlanCallFunction::GetPlanRunState ()
32330fdc8d8SChris Lattner {
32430fdc8d8SChris Lattner     return eStateRunning;
32530fdc8d8SChris Lattner }
32630fdc8d8SChris Lattner 
32730fdc8d8SChris Lattner void
32830fdc8d8SChris Lattner ThreadPlanCallFunction::DidPush ()
32930fdc8d8SChris Lattner {
330be3a1b14SSean Callanan //#define SINGLE_STEP_EXPRESSIONS
331be3a1b14SSean Callanan 
332be3a1b14SSean Callanan #ifndef SINGLE_STEP_EXPRESSIONS
33330fdc8d8SChris Lattner     m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
33430fdc8d8SChris Lattner 
33530fdc8d8SChris Lattner     m_thread.QueueThreadPlan(m_subplan_sp, false);
33677787033SJim Ingham     m_subplan_sp->SetPrivate (true);
337be3a1b14SSean Callanan #endif
33830fdc8d8SChris Lattner }
33930fdc8d8SChris Lattner 
34030fdc8d8SChris Lattner bool
34130fdc8d8SChris Lattner ThreadPlanCallFunction::WillStop ()
34230fdc8d8SChris Lattner {
34330fdc8d8SChris Lattner     return true;
34430fdc8d8SChris Lattner }
34530fdc8d8SChris Lattner 
34630fdc8d8SChris Lattner bool
34730fdc8d8SChris Lattner ThreadPlanCallFunction::MischiefManaged ()
34830fdc8d8SChris Lattner {
34930fdc8d8SChris Lattner     if (IsPlanComplete())
35030fdc8d8SChris Lattner     {
3512d4edfbcSGreg Clayton         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
35230fdc8d8SChris Lattner 
35330fdc8d8SChris Lattner         if (log)
35430fdc8d8SChris Lattner             log->Printf("Completed call function plan.");
35530fdc8d8SChris Lattner 
35630fdc8d8SChris Lattner         ThreadPlan::MischiefManaged ();
35730fdc8d8SChris Lattner         return true;
35830fdc8d8SChris Lattner     }
35930fdc8d8SChris Lattner     else
36030fdc8d8SChris Lattner     {
36130fdc8d8SChris Lattner         return false;
36230fdc8d8SChris Lattner     }
36330fdc8d8SChris Lattner }
3646db73ca5SSean Callanan 
3656db73ca5SSean Callanan void
3666db73ca5SSean Callanan ThreadPlanCallFunction::SetBreakpoints ()
3676db73ca5SSean Callanan {
368f211510fSSean Callanan     m_cxx_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeC_plus_plus);
369f211510fSSean Callanan     m_objc_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeObjC);
3706db73ca5SSean Callanan 
371f211510fSSean Callanan     if (m_cxx_language_runtime)
372f211510fSSean Callanan         m_cxx_language_runtime->SetExceptionBreakpoints();
373f211510fSSean Callanan     if (m_objc_language_runtime)
374f211510fSSean Callanan         m_objc_language_runtime->SetExceptionBreakpoints();
3756db73ca5SSean Callanan }
3766db73ca5SSean Callanan 
3776db73ca5SSean Callanan void
3786db73ca5SSean Callanan ThreadPlanCallFunction::ClearBreakpoints ()
3796db73ca5SSean Callanan {
380f211510fSSean Callanan     if (m_cxx_language_runtime)
381f211510fSSean Callanan         m_cxx_language_runtime->ClearExceptionBreakpoints();
382f211510fSSean Callanan     if (m_objc_language_runtime)
383f211510fSSean Callanan         m_objc_language_runtime->ClearExceptionBreakpoints();
3846db73ca5SSean Callanan }
385c98aca60SSean Callanan 
386c98aca60SSean Callanan bool
387c98aca60SSean Callanan ThreadPlanCallFunction::BreakpointsExplainStop()
388c98aca60SSean Callanan {
389c98aca60SSean Callanan     lldb::StopInfoSP stop_info_sp = GetPrivateStopReason();
390c98aca60SSean Callanan 
391f211510fSSean Callanan     if (m_cxx_language_runtime &&
392f211510fSSean Callanan         m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
393c98aca60SSean Callanan         return true;
394f211510fSSean Callanan 
395f211510fSSean Callanan     if (m_objc_language_runtime &&
396f211510fSSean Callanan         m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
397f211510fSSean Callanan         return true;
398c98aca60SSean Callanan 
399c98aca60SSean Callanan     return false;
400c98aca60SSean Callanan }
401