|  | //===-- ThreadPlanCallUserExpression.cpp ----------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "lldb/Target/ThreadPlanCallUserExpression.h" | 
|  |  | 
|  |  | 
|  | #include "lldb/Breakpoint/Breakpoint.h" | 
|  | #include "lldb/Breakpoint/BreakpointLocation.h" | 
|  | #include "lldb/Core/Address.h" | 
|  | #include "lldb/Expression/DiagnosticManager.h" | 
|  | #include "lldb/Expression/DynamicCheckerFunctions.h" | 
|  | #include "lldb/Expression/UserExpression.h" | 
|  | #include "lldb/Host/HostInfo.h" | 
|  | #include "lldb/Target/LanguageRuntime.h" | 
|  | #include "lldb/Target/Process.h" | 
|  | #include "lldb/Target/RegisterContext.h" | 
|  | #include "lldb/Target/StopInfo.h" | 
|  | #include "lldb/Target/Target.h" | 
|  | #include "lldb/Target/Thread.h" | 
|  | #include "lldb/Target/ThreadPlanRunToAddress.h" | 
|  | #include "lldb/Utility/Log.h" | 
|  | #include "lldb/Utility/Stream.h" | 
|  |  | 
|  | using namespace lldb; | 
|  | using namespace lldb_private; | 
|  |  | 
|  | // ThreadPlanCallUserExpression: Plan to call a single function | 
|  |  | 
|  | ThreadPlanCallUserExpression::ThreadPlanCallUserExpression( | 
|  | Thread &thread, Address &function, llvm::ArrayRef<lldb::addr_t> args, | 
|  | const EvaluateExpressionOptions &options, | 
|  | lldb::UserExpressionSP &user_expression_sp) | 
|  | : ThreadPlanCallFunction(thread, function, CompilerType(), args, options), | 
|  | m_user_expression_sp(user_expression_sp) { | 
|  | // User expressions are generally "User generated" so we should set them up | 
|  | // to stop when done. | 
|  | SetIsMasterPlan(true); | 
|  | SetOkayToDiscard(false); | 
|  | } | 
|  |  | 
|  | ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression() {} | 
|  |  | 
|  | void ThreadPlanCallUserExpression::GetDescription( | 
|  | Stream *s, lldb::DescriptionLevel level) { | 
|  | if (level == eDescriptionLevelBrief) | 
|  | s->Printf("User Expression thread plan"); | 
|  | else | 
|  | ThreadPlanCallFunction::GetDescription(s, level); | 
|  | } | 
|  |  | 
|  | void ThreadPlanCallUserExpression::DidPush() { | 
|  | ThreadPlanCallFunction::DidPush(); | 
|  | if (m_user_expression_sp) | 
|  | m_user_expression_sp->WillStartExecuting(); | 
|  | } | 
|  |  | 
|  | void ThreadPlanCallUserExpression::WillPop() { | 
|  | ThreadPlanCallFunction::WillPop(); | 
|  | if (m_user_expression_sp) | 
|  | m_user_expression_sp.reset(); | 
|  | } | 
|  |  | 
|  | bool ThreadPlanCallUserExpression::MischiefManaged() { | 
|  | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); | 
|  |  | 
|  | if (IsPlanComplete()) { | 
|  | LLDB_LOGF(log, "ThreadPlanCallFunction(%p): Completed call function plan.", | 
|  | static_cast<void *>(this)); | 
|  |  | 
|  | if (m_manage_materialization && PlanSucceeded() && m_user_expression_sp) { | 
|  | lldb::addr_t function_stack_top; | 
|  | lldb::addr_t function_stack_bottom; | 
|  | lldb::addr_t function_stack_pointer = GetFunctionStackPointer(); | 
|  |  | 
|  | function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); | 
|  | function_stack_top = function_stack_pointer; | 
|  |  | 
|  | DiagnosticManager diagnostics; | 
|  |  | 
|  | ExecutionContext exe_ctx(GetThread()); | 
|  |  | 
|  | m_user_expression_sp->FinalizeJITExecution( | 
|  | diagnostics, exe_ctx, m_result_var_sp, function_stack_bottom, | 
|  | function_stack_top); | 
|  | } | 
|  |  | 
|  | ThreadPlan::MischiefManaged(); | 
|  | return true; | 
|  | } else { | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | StopInfoSP ThreadPlanCallUserExpression::GetRealStopInfo() { | 
|  | StopInfoSP stop_info_sp = ThreadPlanCallFunction::GetRealStopInfo(); | 
|  |  | 
|  | if (stop_info_sp) { | 
|  | lldb::addr_t addr = GetStopAddress(); | 
|  | DynamicCheckerFunctions *checkers = m_process.GetDynamicCheckers(); | 
|  | StreamString s; | 
|  |  | 
|  | if (checkers && checkers->DoCheckersExplainStop(addr, s)) | 
|  | stop_info_sp->SetDescription(s.GetData()); | 
|  | } | 
|  |  | 
|  | return stop_info_sp; | 
|  | } | 
|  |  | 
|  | void ThreadPlanCallUserExpression::DoTakedown(bool success) { | 
|  | ThreadPlanCallFunction::DoTakedown(success); | 
|  | m_user_expression_sp->DidFinishExecuting(); | 
|  | } |