//===-- ThreadPlanTestCondition.cpp ---------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lldb/Target/ThreadPlanTestCondition.h" // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/lldb-private-log.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Log.h" #include "lldb/Core/Stream.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObject.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- // ThreadPlanTestCondition: Step through a stack range, either stepping over or into // based on the value of \a type. //---------------------------------------------------------------------- ThreadPlanTestCondition::ThreadPlanTestCondition ( Thread& thread, ExecutionContext &exe_ctx, ClangUserExpression *expression, lldb::BreakpointLocationSP break_loc_sp, bool stop_others) : ThreadPlan (ThreadPlan::eKindTestCondition, "test condition", thread, eVoteNoOpinion, eVoteNoOpinion), m_expression (expression), m_exe_ctx (exe_ctx), m_break_loc_sp (break_loc_sp), m_did_stop (false), m_stop_others (stop_others) { } ThreadPlanTestCondition::~ThreadPlanTestCondition () { } bool ThreadPlanTestCondition::ValidatePlan (Stream *error) { return true; } void ThreadPlanTestCondition::GetDescription (Stream *s, lldb::DescriptionLevel level) { if (m_expression) s->Printf("Thread plan to test condition: \"%s\".", m_expression->GetUserText()); else s->Printf("Thread plan to test unspecified condition."); } bool ThreadPlanTestCondition::ShouldStop (Event *event_ptr) { LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); if (m_thread.IsThreadPlanDone(m_expression_plan_sp.get())) { lldb::ClangExpressionVariableSP expr_result; StreamString error_stream; m_expression->FinalizeJITExecution(error_stream, m_exe_ctx, expr_result); ValueObjectSP result_sp (expr_result->GetValueObject()); if (result_sp) { // FIXME: This is not the right answer, we should have a "GetValueAsBoolean..." Scalar scalar_value; if (result_sp->ResolveValue (scalar_value)) { if (scalar_value.ULongLong(1) == 0) m_did_stop = false; else m_did_stop = true; } if (log) log->Printf("Condition successfully evaluated, result is %s.\n", m_did_stop ? "true" : "false"); } else { if (log) log->Printf("Failed to get a result from the expression, error: \"%s\"\n", error_stream.GetData()); m_did_stop = true; } } else if (m_exe_ctx.thread->WasThreadPlanDiscarded (m_expression_plan_sp.get())) { if (log) log->Printf("ExecuteExpression thread plan was discarded.\n"); m_did_stop = true; } // One tricky bit, somebody might have disabled/deleted the breakpoint while we were running this condition, if so we // should just continue. If the breakpoint gets disabled, then its "site" will be null'ed out, so we can't report // this as a breakpoint event any more, since we can't reconstruct it's site. So just pass the event on. if (!m_break_loc_sp->IsEnabled()) { m_did_stop = false; } else { // Now we have to change the event to a breakpoint event and mark it up appropriately: Process::ProcessEventData *new_data = new Process::ProcessEventData (m_thread.GetProcess().GetSP(), eStateStopped); event_ptr->SetData(new_data); event_ptr->SetType(Process::eBroadcastBitStateChanged); SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID (m_thread, m_break_loc_sp->GetBreakpointSite()->GetID(), m_did_stop)); if (m_did_stop) { Process::ProcessEventData::SetRestartedInEvent (event_ptr, false); } else { Process::ProcessEventData::SetRestartedInEvent (event_ptr, true); } } SetPlanComplete(); return m_did_stop; } bool ThreadPlanTestCondition::PlanExplainsStop () { // We explain all stops, and we just can the execution and return true if we stop for any // reason other than that our expression execution is done. return true; } Vote ThreadPlanTestCondition::ShouldReportStop (Event *event_ptr) { if (m_did_stop) { return eVoteYes; } else { return eVoteNo; } } void ThreadPlanTestCondition::DidPush() { StreamString error_stream; m_expression_plan_sp.reset(m_expression->GetThreadPlanToExecuteJITExpression (error_stream, m_exe_ctx)); m_thread.QueueThreadPlan (m_expression_plan_sp, false); } bool ThreadPlanTestCondition::StopOthers () { return m_stop_others; } bool ThreadPlanTestCondition::WillStop () { return true; } StateType ThreadPlanTestCondition::GetPlanRunState () { return eStateRunning; } bool ThreadPlanTestCondition::MischiefManaged () { // If we get a stop we're done, we don't puase in the middle of // condition execution. return true; }