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,
43fc55f5d1SSean Callanan                                                 lldb::addr_t *this_arg) :
44b01e742aSJim Ingham     ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
4530fdc8d8SChris Lattner     m_valid (false),
461ee0d4f7SBenjamin Kramer     m_stop_other_threads (stop_other_threads),
4730fdc8d8SChris Lattner     m_arg_addr (arg),
4830fdc8d8SChris Lattner     m_args (NULL),
491ee0d4f7SBenjamin Kramer     m_process (thread.GetProcess()),
501ee0d4f7SBenjamin Kramer     m_thread (thread)
5130fdc8d8SChris Lattner {
5230fdc8d8SChris Lattner     SetOkayToDiscard (discard_on_error);
5330fdc8d8SChris Lattner 
5430fdc8d8SChris Lattner     Process& process = thread.GetProcess();
5530fdc8d8SChris Lattner     Target& target = process.GetTarget();
5630fdc8d8SChris Lattner     const ABI *abi = process.GetABI();
5730fdc8d8SChris Lattner 
5830fdc8d8SChris Lattner     if (!abi)
5930fdc8d8SChris Lattner         return;
6030fdc8d8SChris Lattner 
616db73ca5SSean Callanan     SetBreakpoints();
626db73ca5SSean Callanan 
6330fdc8d8SChris Lattner     lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
6430fdc8d8SChris Lattner 
6530fdc8d8SChris Lattner     SymbolContextList contexts;
6630fdc8d8SChris Lattner     SymbolContext context;
6730fdc8d8SChris Lattner     ModuleSP executableModuleSP (target.GetExecutableModule());
6830fdc8d8SChris Lattner 
6930fdc8d8SChris Lattner     if (!executableModuleSP ||
7030fdc8d8SChris Lattner         !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
7130fdc8d8SChris Lattner         return;
7230fdc8d8SChris Lattner 
7330fdc8d8SChris Lattner     contexts.GetContextAtIndex(0, context);
7430fdc8d8SChris Lattner 
7530fdc8d8SChris Lattner     m_start_addr = context.symbol->GetValue();
76f5e56de0SGreg Clayton     lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
7730fdc8d8SChris Lattner 
7830fdc8d8SChris Lattner     if (!thread.SaveFrameZeroState(m_register_backup))
7930fdc8d8SChris Lattner         return;
8030fdc8d8SChris Lattner 
8130fdc8d8SChris Lattner     m_function_addr = function;
82f5e56de0SGreg Clayton     lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
8330fdc8d8SChris Lattner 
8430fdc8d8SChris Lattner     if (!abi->PrepareTrivialCall(thread,
8530fdc8d8SChris Lattner                                  spBelowRedZone,
8630fdc8d8SChris Lattner                                  FunctionLoadAddr,
8730fdc8d8SChris Lattner                                  StartLoadAddr,
88fc55f5d1SSean Callanan                                  m_arg_addr,
89fc55f5d1SSean Callanan                                  this_arg))
9030fdc8d8SChris Lattner         return;
9130fdc8d8SChris Lattner 
92ece96492SSean Callanan     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
93ece96492SSean Callanan 
94ece96492SSean Callanan     if (log)
95ece96492SSean Callanan     {
96ece96492SSean Callanan         RegisterContext *reg_ctx = m_thread.GetRegisterContext();
97ece96492SSean Callanan 
98ece96492SSean Callanan         log->PutCString("Function call was set up.  Register state was:");
99ece96492SSean Callanan 
100ece96492SSean Callanan         for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
101ece96492SSean Callanan              register_index < num_registers;
102ece96492SSean Callanan              ++register_index)
103ece96492SSean Callanan         {
104ece96492SSean Callanan             const char *register_name = reg_ctx->GetRegisterName(register_index);
105ece96492SSean Callanan             uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
106ece96492SSean Callanan 
107ece96492SSean Callanan             log->Printf("  %s = 0x%llx", register_name, register_value);
108ece96492SSean Callanan         }
109ece96492SSean Callanan     }
110ece96492SSean Callanan 
11130fdc8d8SChris Lattner     m_valid = true;
11230fdc8d8SChris Lattner }
11330fdc8d8SChris Lattner 
11430fdc8d8SChris Lattner ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
11530fdc8d8SChris Lattner                                                 Address &function,
11630fdc8d8SChris Lattner                                                 ValueList &args,
11730fdc8d8SChris Lattner                                                 bool stop_other_threads,
11830fdc8d8SChris Lattner                                                 bool discard_on_error) :
119b01e742aSJim Ingham     ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
12030fdc8d8SChris Lattner     m_valid (false),
1211ee0d4f7SBenjamin Kramer     m_stop_other_threads (stop_other_threads),
12230fdc8d8SChris Lattner     m_arg_addr (0),
12330fdc8d8SChris Lattner     m_args (&args),
1241ee0d4f7SBenjamin Kramer     m_process (thread.GetProcess()),
1251ee0d4f7SBenjamin Kramer     m_thread (thread)
12630fdc8d8SChris Lattner {
12730fdc8d8SChris Lattner 
12830fdc8d8SChris Lattner     SetOkayToDiscard (discard_on_error);
12930fdc8d8SChris Lattner 
13030fdc8d8SChris Lattner     Process& process = thread.GetProcess();
13130fdc8d8SChris Lattner     Target& target = process.GetTarget();
13230fdc8d8SChris Lattner     const ABI *abi = process.GetABI();
13330fdc8d8SChris Lattner 
13430fdc8d8SChris Lattner     if(!abi)
13530fdc8d8SChris Lattner         return;
13630fdc8d8SChris Lattner 
1376db73ca5SSean Callanan     SetBreakpoints();
1386db73ca5SSean Callanan 
13930fdc8d8SChris Lattner     lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
14030fdc8d8SChris Lattner 
14130fdc8d8SChris Lattner     SymbolContextList contexts;
14230fdc8d8SChris Lattner     SymbolContext context;
14330fdc8d8SChris Lattner     ModuleSP executableModuleSP (target.GetExecutableModule());
14430fdc8d8SChris Lattner 
14530fdc8d8SChris Lattner     if (!executableModuleSP ||
14630fdc8d8SChris Lattner         !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
14730fdc8d8SChris Lattner         return;
14830fdc8d8SChris Lattner 
14930fdc8d8SChris Lattner     contexts.GetContextAtIndex(0, context);
15030fdc8d8SChris Lattner 
15130fdc8d8SChris Lattner     m_start_addr = context.symbol->GetValue();
152f5e56de0SGreg Clayton     lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
15330fdc8d8SChris Lattner 
15430fdc8d8SChris Lattner     if(!thread.SaveFrameZeroState(m_register_backup))
15530fdc8d8SChris Lattner         return;
15630fdc8d8SChris Lattner 
15730fdc8d8SChris Lattner     m_function_addr = function;
158f5e56de0SGreg Clayton     lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
15930fdc8d8SChris Lattner 
16030fdc8d8SChris Lattner     if (!abi->PrepareNormalCall(thread,
16130fdc8d8SChris Lattner                                 spBelowRedZone,
16230fdc8d8SChris Lattner                                 FunctionLoadAddr,
16330fdc8d8SChris Lattner                                 StartLoadAddr,
16430fdc8d8SChris Lattner                                 *m_args))
16530fdc8d8SChris Lattner         return;
16630fdc8d8SChris Lattner 
167ece96492SSean Callanan     LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
168ece96492SSean Callanan 
169ece96492SSean Callanan     if (log)
170ece96492SSean Callanan     {
171ece96492SSean Callanan         RegisterContext *reg_ctx = m_thread.GetRegisterContext();
172ece96492SSean Callanan 
173ece96492SSean Callanan         log->PutCString("Function call was set up.  Register state was:");
174ece96492SSean Callanan 
175ece96492SSean Callanan         for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
176ece96492SSean Callanan              register_index < num_registers;
177ece96492SSean Callanan              ++register_index)
178ece96492SSean Callanan         {
179ece96492SSean Callanan             const char *register_name = reg_ctx->GetRegisterName(register_index);
180ece96492SSean Callanan             uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
181ece96492SSean Callanan 
182ece96492SSean Callanan             log->Printf("  %s = 0x%llx", register_name, register_value);
183ece96492SSean Callanan         }
184ece96492SSean Callanan     }
185ece96492SSean Callanan 
18630fdc8d8SChris Lattner     m_valid = true;
18730fdc8d8SChris Lattner }
18830fdc8d8SChris Lattner 
18930fdc8d8SChris Lattner ThreadPlanCallFunction::~ThreadPlanCallFunction ()
19030fdc8d8SChris Lattner {
19110af7c43SSean Callanan     if (m_valid && !IsPlanComplete())
19210af7c43SSean Callanan         DoTakedown();
19310af7c43SSean Callanan }
19410af7c43SSean Callanan 
19510af7c43SSean Callanan void
19610af7c43SSean Callanan ThreadPlanCallFunction::DoTakedown ()
19710af7c43SSean Callanan {
19810af7c43SSean Callanan     m_thread.RestoreSaveFrameZero(m_register_backup);
19910af7c43SSean Callanan     m_thread.ClearStackFrames();
20010af7c43SSean Callanan     SetPlanComplete();
20110af7c43SSean Callanan     ClearBreakpoints();
20230fdc8d8SChris Lattner }
20330fdc8d8SChris Lattner 
20430fdc8d8SChris Lattner void
20530fdc8d8SChris Lattner ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
20630fdc8d8SChris Lattner {
20730fdc8d8SChris Lattner     if (level == lldb::eDescriptionLevelBrief)
20830fdc8d8SChris Lattner     {
20930fdc8d8SChris Lattner         s->Printf("Function call thread plan");
21030fdc8d8SChris Lattner     }
21130fdc8d8SChris Lattner     else
21230fdc8d8SChris Lattner     {
21330fdc8d8SChris Lattner         if (m_args)
214f5e56de0SGreg Clayton             s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
21530fdc8d8SChris Lattner         else
216f5e56de0SGreg Clayton             s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
21730fdc8d8SChris Lattner     }
21830fdc8d8SChris Lattner }
21930fdc8d8SChris Lattner 
22030fdc8d8SChris Lattner bool
22130fdc8d8SChris Lattner ThreadPlanCallFunction::ValidatePlan (Stream *error)
22230fdc8d8SChris Lattner {
22330fdc8d8SChris Lattner     if (!m_valid)
22430fdc8d8SChris Lattner         return false;
22530fdc8d8SChris Lattner 
22630fdc8d8SChris Lattner     return true;
22730fdc8d8SChris Lattner }
22830fdc8d8SChris Lattner 
22930fdc8d8SChris Lattner bool
23030fdc8d8SChris Lattner ThreadPlanCallFunction::PlanExplainsStop ()
23130fdc8d8SChris Lattner {
23240d871faSJim Ingham     // If our subplan knows why we stopped, even if it's done (which would forward the question to us)
23340d871faSJim Ingham     // we answer yes.
23440d871faSJim Ingham     if(m_subplan_sp.get() != NULL && m_subplan_sp->PlanExplainsStop())
23540d871faSJim Ingham         return true;
2363e6fedcaSSean Callanan 
237c98aca60SSean Callanan     // Check if the breakpoint is one of ours.
238c98aca60SSean Callanan 
239c98aca60SSean Callanan     if (BreakpointsExplainStop())
240c98aca60SSean Callanan         return true;
241c98aca60SSean Callanan 
24240d871faSJim Ingham     // If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
24340d871faSJim Ingham     if (!OkayToDiscard())
24440d871faSJim Ingham         return false;
24540d871faSJim Ingham 
24640d871faSJim Ingham     // Otherwise, check the case where we stopped for an internal breakpoint, in that case, continue on.
24740d871faSJim Ingham     // If it is not an internal breakpoint, consult OkayToDiscard.
24840d871faSJim Ingham     lldb::StopInfoSP stop_info_sp = GetPrivateStopReason();
2496db73ca5SSean Callanan 
25040d871faSJim Ingham     if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
25140d871faSJim Ingham     {
25240d871faSJim Ingham         uint64_t break_site_id = stop_info_sp->GetValue();
25340d871faSJim Ingham         lldb::BreakpointSiteSP bp_site_sp = m_thread.GetProcess().GetBreakpointSiteList().FindByID(break_site_id);
25440d871faSJim Ingham         if (bp_site_sp)
25540d871faSJim Ingham         {
25640d871faSJim Ingham             uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
25740d871faSJim Ingham             bool is_internal = true;
25840d871faSJim Ingham             for (uint32_t i = 0; i < num_owners; i++)
25940d871faSJim Ingham             {
2606db73ca5SSean Callanan                 Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
2616db73ca5SSean Callanan 
2626db73ca5SSean Callanan                 if (!bp.IsInternal())
26340d871faSJim Ingham                 {
26440d871faSJim Ingham                     is_internal = false;
26540d871faSJim Ingham                     break;
26640d871faSJim Ingham                 }
26740d871faSJim Ingham             }
26840d871faSJim Ingham             if (is_internal)
26940d871faSJim Ingham                 return false;
27040d871faSJim Ingham         }
27140d871faSJim Ingham 
27240d871faSJim Ingham         return OkayToDiscard();
27340d871faSJim Ingham     }
27440d871faSJim Ingham     else
27540d871faSJim Ingham     {
27640d871faSJim Ingham         // If the subplan is running, any crashes are attributable to us.
2773e6fedcaSSean Callanan         return (m_subplan_sp.get() != NULL);
27830fdc8d8SChris Lattner     }
27940d871faSJim Ingham }
28030fdc8d8SChris Lattner 
28130fdc8d8SChris Lattner bool
28230fdc8d8SChris Lattner ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
28330fdc8d8SChris Lattner {
28430fdc8d8SChris Lattner     if (PlanExplainsStop())
28530fdc8d8SChris Lattner     {
2862d4edfbcSGreg Clayton         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
2875300d37aSSean Callanan 
2885300d37aSSean Callanan         if (log)
2895300d37aSSean Callanan         {
2905300d37aSSean Callanan             RegisterContext *reg_ctx = m_thread.GetRegisterContext();
2915300d37aSSean Callanan 
2925300d37aSSean Callanan             log->PutCString("Function completed.  Register state was:");
2935300d37aSSean Callanan 
2945300d37aSSean Callanan             for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
2955300d37aSSean Callanan                  register_index < num_registers;
2965300d37aSSean Callanan                  ++register_index)
2975300d37aSSean Callanan             {
2985300d37aSSean Callanan                 const char *register_name = reg_ctx->GetRegisterName(register_index);
2995300d37aSSean Callanan                 uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
3005300d37aSSean Callanan 
3015300d37aSSean Callanan                 log->Printf("  %s = 0x%llx", register_name, register_value);
3025300d37aSSean Callanan             }
3035300d37aSSean Callanan         }
3045300d37aSSean Callanan 
30510af7c43SSean Callanan         DoTakedown();
3066db73ca5SSean Callanan 
30730fdc8d8SChris Lattner         return true;
30830fdc8d8SChris Lattner     }
30930fdc8d8SChris Lattner     else
31030fdc8d8SChris Lattner     {
31130fdc8d8SChris Lattner         return false;
31230fdc8d8SChris Lattner     }
31330fdc8d8SChris Lattner }
31430fdc8d8SChris Lattner 
31530fdc8d8SChris Lattner bool
31630fdc8d8SChris Lattner ThreadPlanCallFunction::StopOthers ()
31730fdc8d8SChris Lattner {
31830fdc8d8SChris Lattner     return m_stop_other_threads;
31930fdc8d8SChris Lattner }
32030fdc8d8SChris Lattner 
32130fdc8d8SChris Lattner void
32230fdc8d8SChris Lattner ThreadPlanCallFunction::SetStopOthers (bool new_value)
32330fdc8d8SChris Lattner {
32430fdc8d8SChris Lattner     if (m_subplan_sp)
32530fdc8d8SChris Lattner     {
32630fdc8d8SChris Lattner         ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
32730fdc8d8SChris Lattner         address_plan->SetStopOthers(new_value);
32830fdc8d8SChris Lattner     }
32930fdc8d8SChris Lattner     m_stop_other_threads = new_value;
33030fdc8d8SChris Lattner }
33130fdc8d8SChris Lattner 
33230fdc8d8SChris Lattner StateType
333*06e827ccSJim Ingham ThreadPlanCallFunction::GetPlanRunState ()
33430fdc8d8SChris Lattner {
33530fdc8d8SChris Lattner     return eStateRunning;
33630fdc8d8SChris Lattner }
33730fdc8d8SChris Lattner 
33830fdc8d8SChris Lattner void
33930fdc8d8SChris Lattner ThreadPlanCallFunction::DidPush ()
34030fdc8d8SChris Lattner {
341be3a1b14SSean Callanan //#define SINGLE_STEP_EXPRESSIONS
342be3a1b14SSean Callanan 
343be3a1b14SSean Callanan #ifndef SINGLE_STEP_EXPRESSIONS
34430fdc8d8SChris Lattner     m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
34530fdc8d8SChris Lattner 
34630fdc8d8SChris Lattner     m_thread.QueueThreadPlan(m_subplan_sp, false);
347be3a1b14SSean Callanan #endif
34830fdc8d8SChris Lattner }
34930fdc8d8SChris Lattner 
35030fdc8d8SChris Lattner bool
35130fdc8d8SChris Lattner ThreadPlanCallFunction::WillStop ()
35230fdc8d8SChris Lattner {
35330fdc8d8SChris Lattner     return true;
35430fdc8d8SChris Lattner }
35530fdc8d8SChris Lattner 
35630fdc8d8SChris Lattner bool
35730fdc8d8SChris Lattner ThreadPlanCallFunction::MischiefManaged ()
35830fdc8d8SChris Lattner {
35930fdc8d8SChris Lattner     if (IsPlanComplete())
36030fdc8d8SChris Lattner     {
3612d4edfbcSGreg Clayton         LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
36230fdc8d8SChris Lattner 
36330fdc8d8SChris Lattner         if (log)
36430fdc8d8SChris Lattner             log->Printf("Completed call function plan.");
36530fdc8d8SChris Lattner 
36630fdc8d8SChris Lattner         ThreadPlan::MischiefManaged ();
36730fdc8d8SChris Lattner         return true;
36830fdc8d8SChris Lattner     }
36930fdc8d8SChris Lattner     else
37030fdc8d8SChris Lattner     {
37130fdc8d8SChris Lattner         return false;
37230fdc8d8SChris Lattner     }
37330fdc8d8SChris Lattner }
3746db73ca5SSean Callanan 
3756db73ca5SSean Callanan void
3766db73ca5SSean Callanan ThreadPlanCallFunction::SetBreakpoints ()
3776db73ca5SSean Callanan {
378f211510fSSean Callanan     m_cxx_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeC_plus_plus);
379f211510fSSean Callanan     m_objc_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeObjC);
3806db73ca5SSean Callanan 
381f211510fSSean Callanan     if (m_cxx_language_runtime)
382f211510fSSean Callanan         m_cxx_language_runtime->SetExceptionBreakpoints();
383f211510fSSean Callanan     if (m_objc_language_runtime)
384f211510fSSean Callanan         m_objc_language_runtime->SetExceptionBreakpoints();
3856db73ca5SSean Callanan }
3866db73ca5SSean Callanan 
3876db73ca5SSean Callanan void
3886db73ca5SSean Callanan ThreadPlanCallFunction::ClearBreakpoints ()
3896db73ca5SSean Callanan {
390f211510fSSean Callanan     if (m_cxx_language_runtime)
391f211510fSSean Callanan         m_cxx_language_runtime->ClearExceptionBreakpoints();
392f211510fSSean Callanan     if (m_objc_language_runtime)
393f211510fSSean Callanan         m_objc_language_runtime->ClearExceptionBreakpoints();
3946db73ca5SSean Callanan }
395c98aca60SSean Callanan 
396c98aca60SSean Callanan bool
397c98aca60SSean Callanan ThreadPlanCallFunction::BreakpointsExplainStop()
398c98aca60SSean Callanan {
399c98aca60SSean Callanan     lldb::StopInfoSP stop_info_sp = GetPrivateStopReason();
400c98aca60SSean Callanan 
401f211510fSSean Callanan     if (m_cxx_language_runtime &&
402f211510fSSean Callanan         m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
403c98aca60SSean Callanan         return true;
404f211510fSSean Callanan 
405f211510fSSean Callanan     if (m_objc_language_runtime &&
406f211510fSSean Callanan         m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
407f211510fSSean Callanan         return true;
408c98aca60SSean Callanan 
409c98aca60SSean Callanan     return false;
410c98aca60SSean Callanan }
411