15ffd83dbSDimitry Andric //===-- ThreadPlanCallUserExpression.cpp ----------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanCallUserExpression.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Breakpoint/Breakpoint.h"
120b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
130b57cec5SDimitry Andric #include "lldb/Core/Address.h"
140b57cec5SDimitry Andric #include "lldb/Expression/DiagnosticManager.h"
150b57cec5SDimitry Andric #include "lldb/Expression/DynamicCheckerFunctions.h"
160b57cec5SDimitry Andric #include "lldb/Expression/UserExpression.h"
170b57cec5SDimitry Andric #include "lldb/Host/HostInfo.h"
180b57cec5SDimitry Andric #include "lldb/Target/LanguageRuntime.h"
190b57cec5SDimitry Andric #include "lldb/Target/Process.h"
200b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
210b57cec5SDimitry Andric #include "lldb/Target/StopInfo.h"
220b57cec5SDimitry Andric #include "lldb/Target/Target.h"
230b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
240b57cec5SDimitry Andric #include "lldb/Target/ThreadPlanRunToAddress.h"
2581ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
260b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
270b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace lldb;
300b57cec5SDimitry Andric using namespace lldb_private;
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric // ThreadPlanCallUserExpression: Plan to call a single function
330b57cec5SDimitry Andric 
ThreadPlanCallUserExpression(Thread & thread,Address & function,llvm::ArrayRef<lldb::addr_t> args,const EvaluateExpressionOptions & options,lldb::UserExpressionSP & user_expression_sp)340b57cec5SDimitry Andric ThreadPlanCallUserExpression::ThreadPlanCallUserExpression(
350b57cec5SDimitry Andric     Thread &thread, Address &function, llvm::ArrayRef<lldb::addr_t> args,
360b57cec5SDimitry Andric     const EvaluateExpressionOptions &options,
370b57cec5SDimitry Andric     lldb::UserExpressionSP &user_expression_sp)
380b57cec5SDimitry Andric     : ThreadPlanCallFunction(thread, function, CompilerType(), args, options),
390b57cec5SDimitry Andric       m_user_expression_sp(user_expression_sp) {
400b57cec5SDimitry Andric   // User expressions are generally "User generated" so we should set them up
410b57cec5SDimitry Andric   // to stop when done.
42349cc55cSDimitry Andric   SetIsControllingPlan(true);
430b57cec5SDimitry Andric   SetOkayToDiscard(false);
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric 
46fe6060f1SDimitry Andric ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression() = default;
470b57cec5SDimitry Andric 
GetDescription(Stream * s,lldb::DescriptionLevel level)480b57cec5SDimitry Andric void ThreadPlanCallUserExpression::GetDescription(
490b57cec5SDimitry Andric     Stream *s, lldb::DescriptionLevel level) {
500b57cec5SDimitry Andric   if (level == eDescriptionLevelBrief)
510b57cec5SDimitry Andric     s->Printf("User Expression thread plan");
520b57cec5SDimitry Andric   else
530b57cec5SDimitry Andric     ThreadPlanCallFunction::GetDescription(s, level);
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
DidPush()560b57cec5SDimitry Andric void ThreadPlanCallUserExpression::DidPush() {
570b57cec5SDimitry Andric   ThreadPlanCallFunction::DidPush();
580b57cec5SDimitry Andric   if (m_user_expression_sp)
590b57cec5SDimitry Andric     m_user_expression_sp->WillStartExecuting();
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
DidPop()62349cc55cSDimitry Andric void ThreadPlanCallUserExpression::DidPop() {
63349cc55cSDimitry Andric   ThreadPlanCallFunction::DidPop();
640b57cec5SDimitry Andric   if (m_user_expression_sp)
650b57cec5SDimitry Andric     m_user_expression_sp.reset();
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric 
MischiefManaged()680b57cec5SDimitry Andric bool ThreadPlanCallUserExpression::MischiefManaged() {
6981ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Step);
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   if (IsPlanComplete()) {
729dba64beSDimitry Andric     LLDB_LOGF(log, "ThreadPlanCallFunction(%p): Completed call function plan.",
730b57cec5SDimitry Andric               static_cast<void *>(this));
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric     if (m_manage_materialization && PlanSucceeded() && m_user_expression_sp) {
760b57cec5SDimitry Andric       lldb::addr_t function_stack_top;
770b57cec5SDimitry Andric       lldb::addr_t function_stack_bottom;
780b57cec5SDimitry Andric       lldb::addr_t function_stack_pointer = GetFunctionStackPointer();
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric       function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize();
810b57cec5SDimitry Andric       function_stack_top = function_stack_pointer;
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric       DiagnosticManager diagnostics;
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric       ExecutionContext exe_ctx(GetThread());
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric       m_user_expression_sp->FinalizeJITExecution(
880b57cec5SDimitry Andric           diagnostics, exe_ctx, m_result_var_sp, function_stack_bottom,
890b57cec5SDimitry Andric           function_stack_top);
900b57cec5SDimitry Andric     }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric     ThreadPlan::MischiefManaged();
930b57cec5SDimitry Andric     return true;
940b57cec5SDimitry Andric   } else {
950b57cec5SDimitry Andric     return false;
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric 
GetRealStopInfo()990b57cec5SDimitry Andric StopInfoSP ThreadPlanCallUserExpression::GetRealStopInfo() {
1000b57cec5SDimitry Andric   StopInfoSP stop_info_sp = ThreadPlanCallFunction::GetRealStopInfo();
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   if (stop_info_sp) {
1030b57cec5SDimitry Andric     lldb::addr_t addr = GetStopAddress();
1045ffd83dbSDimitry Andric     DynamicCheckerFunctions *checkers = m_process.GetDynamicCheckers();
1050b57cec5SDimitry Andric     StreamString s;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric     if (checkers && checkers->DoCheckersExplainStop(addr, s))
1080b57cec5SDimitry Andric       stop_info_sp->SetDescription(s.GetData());
1090b57cec5SDimitry Andric   }
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   return stop_info_sp;
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric 
DoTakedown(bool success)1140b57cec5SDimitry Andric void ThreadPlanCallUserExpression::DoTakedown(bool success) {
1150b57cec5SDimitry Andric   ThreadPlanCallFunction::DoTakedown(success);
1160b57cec5SDimitry Andric   m_user_expression_sp->DidFinishExecuting();
1170b57cec5SDimitry Andric }
118