Path: blob/main/contrib/llvm-project/lldb/source/Expression/UserExpression.cpp
39587 views
//===-- UserExpression.cpp ------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include <cstdio>9#include <sys/types.h>1011#include <cstdlib>12#include <map>13#include <string>1415#include "lldb/Core/Module.h"16#include "lldb/Core/ValueObjectConstResult.h"17#include "lldb/Expression/DiagnosticManager.h"18#include "lldb/Expression/ExpressionVariable.h"19#include "lldb/Expression/IRExecutionUnit.h"20#include "lldb/Expression/IRInterpreter.h"21#include "lldb/Expression/Materializer.h"22#include "lldb/Expression/UserExpression.h"23#include "lldb/Host/HostInfo.h"24#include "lldb/Symbol/Block.h"25#include "lldb/Symbol/Function.h"26#include "lldb/Symbol/ObjectFile.h"27#include "lldb/Symbol/SymbolVendor.h"28#include "lldb/Symbol/Type.h"29#include "lldb/Symbol/TypeSystem.h"30#include "lldb/Symbol/VariableList.h"31#include "lldb/Target/ExecutionContext.h"32#include "lldb/Target/Process.h"33#include "lldb/Target/StackFrame.h"34#include "lldb/Target/Target.h"35#include "lldb/Target/ThreadPlan.h"36#include "lldb/Target/ThreadPlanCallUserExpression.h"37#include "lldb/Utility/LLDBLog.h"38#include "lldb/Utility/Log.h"39#include "lldb/Utility/State.h"40#include "lldb/Utility/StreamString.h"41#include "llvm/BinaryFormat/Dwarf.h"4243using namespace lldb_private;4445char UserExpression::ID;4647UserExpression::UserExpression(ExecutionContextScope &exe_scope,48llvm::StringRef expr, llvm::StringRef prefix,49SourceLanguage language, ResultType desired_type,50const EvaluateExpressionOptions &options)51: Expression(exe_scope), m_expr_text(std::string(expr)),52m_expr_prefix(std::string(prefix)), m_language(language),53m_desired_type(desired_type), m_options(options) {}5455UserExpression::~UserExpression() = default;5657void UserExpression::InstallContext(ExecutionContext &exe_ctx) {58m_jit_process_wp = exe_ctx.GetProcessSP();5960lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP();6162if (frame_sp)63m_address = frame_sp->GetFrameCodeAddress();64}6566bool UserExpression::LockAndCheckContext(ExecutionContext &exe_ctx,67lldb::TargetSP &target_sp,68lldb::ProcessSP &process_sp,69lldb::StackFrameSP &frame_sp) {70lldb::ProcessSP expected_process_sp = m_jit_process_wp.lock();71process_sp = exe_ctx.GetProcessSP();7273if (process_sp != expected_process_sp)74return false;7576process_sp = exe_ctx.GetProcessSP();77target_sp = exe_ctx.GetTargetSP();78frame_sp = exe_ctx.GetFrameSP();7980if (m_address.IsValid()) {81if (!frame_sp)82return false;83return (Address::CompareLoadAddress(m_address,84frame_sp->GetFrameCodeAddress(),85target_sp.get()) == 0);86}8788return true;89}9091bool UserExpression::MatchesContext(ExecutionContext &exe_ctx) {92lldb::TargetSP target_sp;93lldb::ProcessSP process_sp;94lldb::StackFrameSP frame_sp;9596return LockAndCheckContext(exe_ctx, target_sp, process_sp, frame_sp);97}9899lldb::ValueObjectSP UserExpression::GetObjectPointerValueObject(100lldb::StackFrameSP frame_sp, llvm::StringRef object_name, Status &err) {101err.Clear();102103if (!frame_sp) {104err.SetErrorStringWithFormatv(105"Couldn't load '{0}' because the context is incomplete", object_name);106return {};107}108109lldb::VariableSP var_sp;110lldb::ValueObjectSP valobj_sp;111112return frame_sp->GetValueForVariableExpressionPath(113object_name, lldb::eNoDynamicValues,114StackFrame::eExpressionPathOptionCheckPtrVsMember |115StackFrame::eExpressionPathOptionsNoFragileObjcIvar |116StackFrame::eExpressionPathOptionsNoSyntheticChildren |117StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,118var_sp, err);119}120121lldb::addr_t UserExpression::GetObjectPointer(lldb::StackFrameSP frame_sp,122llvm::StringRef object_name,123Status &err) {124auto valobj_sp =125GetObjectPointerValueObject(std::move(frame_sp), object_name, err);126127if (!err.Success() || !valobj_sp.get())128return LLDB_INVALID_ADDRESS;129130lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);131132if (ret == LLDB_INVALID_ADDRESS) {133err.SetErrorStringWithFormatv(134"Couldn't load '{0}' because its value couldn't be evaluated",135object_name);136return LLDB_INVALID_ADDRESS;137}138139return ret;140}141142lldb::ExpressionResults143UserExpression::Evaluate(ExecutionContext &exe_ctx,144const EvaluateExpressionOptions &options,145llvm::StringRef expr, llvm::StringRef prefix,146lldb::ValueObjectSP &result_valobj_sp, Status &error,147std::string *fixed_expression, ValueObject *ctx_obj) {148Log *log(GetLog(LLDBLog::Expressions | LLDBLog::Step));149150if (ctx_obj) {151static unsigned const ctx_type_mask = lldb::TypeFlags::eTypeIsClass |152lldb::TypeFlags::eTypeIsStructUnion |153lldb::TypeFlags::eTypeIsReference;154if (!(ctx_obj->GetTypeInfo() & ctx_type_mask)) {155LLDB_LOG(log, "== [UserExpression::Evaluate] Passed a context object of "156"an invalid type, can't run expressions.");157error.SetErrorString("a context object of an invalid type passed");158return lldb::eExpressionSetupError;159}160}161162if (ctx_obj && ctx_obj->GetTypeInfo() & lldb::TypeFlags::eTypeIsReference) {163Status error;164lldb::ValueObjectSP deref_ctx_sp = ctx_obj->Dereference(error);165if (!error.Success()) {166LLDB_LOG(log, "== [UserExpression::Evaluate] Passed a context object of "167"a reference type that can't be dereferenced, can't run "168"expressions.");169error.SetErrorString(170"passed context object of an reference type cannot be deferenced");171return lldb::eExpressionSetupError;172}173174ctx_obj = deref_ctx_sp.get();175}176177lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy();178SourceLanguage language = options.GetLanguage();179const ResultType desired_type = options.DoesCoerceToId()180? UserExpression::eResultTypeId181: UserExpression::eResultTypeAny;182lldb::ExpressionResults execution_results = lldb::eExpressionSetupError;183184Target *target = exe_ctx.GetTargetPtr();185if (!target) {186LLDB_LOG(log, "== [UserExpression::Evaluate] Passed a NULL target, can't "187"run expressions.");188error.SetErrorString("expression passed a null target");189return lldb::eExpressionSetupError;190}191192Process *process = exe_ctx.GetProcessPtr();193194if (process == nullptr && execution_policy == eExecutionPolicyAlways) {195LLDB_LOG(log, "== [UserExpression::Evaluate] No process, but the policy is "196"eExecutionPolicyAlways");197198error.SetErrorString("expression needed to run but couldn't: no process");199200return execution_results;201}202203// Since we might need to allocate memory, we need to be stopped to run204// an expression.205if (process != nullptr && process->GetState() != lldb::eStateStopped) {206error.SetErrorStringWithFormatv(207"unable to evaluate expression while the process is {0}: the process "208"must be stopped because the expression might require allocating "209"memory.",210StateAsCString(process->GetState()));211return execution_results;212}213214// Explicitly force the IR interpreter to evaluate the expression when the215// there is no process that supports running the expression for us. Don't216// change the execution policy if we have the special top-level policy that217// doesn't contain any expression and there is nothing to interpret.218if (execution_policy != eExecutionPolicyTopLevel &&219(process == nullptr || !process->CanJIT()))220execution_policy = eExecutionPolicyNever;221222// We need to set the expression execution thread here, turns out parse can223// call functions in the process of looking up symbols, which will escape the224// context set by exe_ctx passed to Execute.225lldb::ThreadSP thread_sp = exe_ctx.GetThreadSP();226ThreadList::ExpressionExecutionThreadPusher execution_thread_pusher(227thread_sp);228229llvm::StringRef full_prefix;230llvm::StringRef option_prefix(options.GetPrefix());231std::string full_prefix_storage;232if (!prefix.empty() && !option_prefix.empty()) {233full_prefix_storage = std::string(prefix);234full_prefix_storage.append(std::string(option_prefix));235full_prefix = full_prefix_storage;236} else if (!prefix.empty())237full_prefix = prefix;238else239full_prefix = option_prefix;240241// If the language was not specified in the expression command, set it to the242// language in the target's properties if specified, else default to the243// langage for the frame.244if (!language) {245if (target->GetLanguage() != lldb::eLanguageTypeUnknown)246language = target->GetLanguage();247else if (StackFrame *frame = exe_ctx.GetFramePtr())248language = frame->GetLanguage();249}250251lldb::UserExpressionSP user_expression_sp(252target->GetUserExpressionForLanguage(expr, full_prefix, language,253desired_type, options, ctx_obj,254error));255if (error.Fail() || !user_expression_sp) {256LLDB_LOG(log, "== [UserExpression::Evaluate] Getting expression: {0} ==",257error.AsCString());258return lldb::eExpressionSetupError;259}260261LLDB_LOG(log, "== [UserExpression::Evaluate] Parsing expression {0} ==",262expr.str());263264const bool keep_expression_in_memory = true;265const bool generate_debug_info = options.GetGenerateDebugInfo();266267if (options.InvokeCancelCallback(lldb::eExpressionEvaluationParse)) {268error.SetErrorString("expression interrupted by callback before parse");269result_valobj_sp = ValueObjectConstResult::Create(270exe_ctx.GetBestExecutionContextScope(), error);271return lldb::eExpressionInterrupted;272}273274DiagnosticManager diagnostic_manager;275276bool parse_success =277user_expression_sp->Parse(diagnostic_manager, exe_ctx, execution_policy,278keep_expression_in_memory, generate_debug_info);279280// Calculate the fixed expression always, since we need it for errors.281std::string tmp_fixed_expression;282if (fixed_expression == nullptr)283fixed_expression = &tmp_fixed_expression;284285*fixed_expression = user_expression_sp->GetFixedText().str();286287// If there is a fixed expression, try to parse it:288if (!parse_success) {289// Delete the expression that failed to parse before attempting to parse290// the next expression.291user_expression_sp.reset();292293execution_results = lldb::eExpressionParseError;294if (!fixed_expression->empty() && options.GetAutoApplyFixIts()) {295const uint64_t max_fix_retries = options.GetRetriesWithFixIts();296for (uint64_t i = 0; i < max_fix_retries; ++i) {297// Try parsing the fixed expression.298lldb::UserExpressionSP fixed_expression_sp(299target->GetUserExpressionForLanguage(300fixed_expression->c_str(), full_prefix, language, desired_type,301options, ctx_obj, error));302if (!fixed_expression_sp)303break;304DiagnosticManager fixed_diagnostic_manager;305parse_success = fixed_expression_sp->Parse(306fixed_diagnostic_manager, exe_ctx, execution_policy,307keep_expression_in_memory, generate_debug_info);308if (parse_success) {309diagnostic_manager.Clear();310user_expression_sp = fixed_expression_sp;311break;312}313// The fixed expression also didn't parse. Let's check for any new314// fixits we could try.315if (!fixed_expression_sp->GetFixedText().empty()) {316*fixed_expression = fixed_expression_sp->GetFixedText().str();317} else {318// Fixed expression didn't compile without a fixit, don't retry and319// don't tell the user about it.320fixed_expression->clear();321break;322}323}324}325326if (!parse_success) {327std::string msg;328{329llvm::raw_string_ostream os(msg);330if (!diagnostic_manager.Diagnostics().empty())331os << diagnostic_manager.GetString();332else333os << "expression failed to parse (no further compiler diagnostics)";334if (target->GetEnableNotifyAboutFixIts() && fixed_expression &&335!fixed_expression->empty())336os << "\nfixed expression suggested:\n " << *fixed_expression;337}338error.SetExpressionError(execution_results, msg.c_str());339}340}341342if (parse_success) {343lldb::ExpressionVariableSP expr_result;344345if (execution_policy == eExecutionPolicyNever &&346!user_expression_sp->CanInterpret()) {347LLDB_LOG(log, "== [UserExpression::Evaluate] Expression may not run, but "348"is not constant ==");349350if (!diagnostic_manager.Diagnostics().size())351error.SetExpressionError(lldb::eExpressionSetupError,352"expression needed to run but couldn't");353} else if (execution_policy == eExecutionPolicyTopLevel) {354error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric);355return lldb::eExpressionCompleted;356} else {357if (options.InvokeCancelCallback(lldb::eExpressionEvaluationExecution)) {358error.SetExpressionError(359lldb::eExpressionInterrupted,360"expression interrupted by callback before execution");361result_valobj_sp = ValueObjectConstResult::Create(362exe_ctx.GetBestExecutionContextScope(), error);363return lldb::eExpressionInterrupted;364}365366diagnostic_manager.Clear();367368LLDB_LOG(log, "== [UserExpression::Evaluate] Executing expression ==");369370execution_results =371user_expression_sp->Execute(diagnostic_manager, exe_ctx, options,372user_expression_sp, expr_result);373374if (execution_results != lldb::eExpressionCompleted) {375LLDB_LOG(log, "== [UserExpression::Evaluate] Execution completed "376"abnormally ==");377378if (!diagnostic_manager.Diagnostics().size())379error.SetExpressionError(380execution_results, "expression failed to execute, unknown error");381else382error.SetExpressionError(execution_results,383diagnostic_manager.GetString().c_str());384} else {385if (expr_result) {386result_valobj_sp = expr_result->GetValueObject();387result_valobj_sp->SetPreferredDisplayLanguage(388language.AsLanguageType());389390LLDB_LOG(log,391"== [UserExpression::Evaluate] Execution completed "392"normally with result {0} ==",393result_valobj_sp->GetValueAsCString());394} else {395LLDB_LOG(log, "== [UserExpression::Evaluate] Execution completed "396"normally with no result ==");397398error.SetError(UserExpression::kNoResult, lldb::eErrorTypeGeneric);399}400}401}402}403404if (options.InvokeCancelCallback(lldb::eExpressionEvaluationComplete)) {405error.SetExpressionError(406lldb::eExpressionInterrupted,407"expression interrupted by callback after complete");408return lldb::eExpressionInterrupted;409}410411if (result_valobj_sp.get() == nullptr) {412result_valobj_sp = ValueObjectConstResult::Create(413exe_ctx.GetBestExecutionContextScope(), error);414}415416return execution_results;417}418419lldb::ExpressionResults420UserExpression::Execute(DiagnosticManager &diagnostic_manager,421ExecutionContext &exe_ctx,422const EvaluateExpressionOptions &options,423lldb::UserExpressionSP &shared_ptr_to_me,424lldb::ExpressionVariableSP &result_var) {425lldb::ExpressionResults expr_result = DoExecute(426diagnostic_manager, exe_ctx, options, shared_ptr_to_me, result_var);427Target *target = exe_ctx.GetTargetPtr();428if (options.GetSuppressPersistentResult() && result_var && target) {429if (auto *persistent_state =430target->GetPersistentExpressionStateForLanguage(431m_language.AsLanguageType()))432persistent_state->RemovePersistentVariable(result_var);433}434return expr_result;435}436437438