llvm-project/lldb/source/Target/ThreadPlanTestCondition.cpp

195 lines
6.0 KiB
C++

//===-- 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,
const 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.GetThreadRef().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(), 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;
}