Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
39648 views
//===-- ClangUserExpression.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 "ClangUserExpression.h"1617#include "ASTResultSynthesizer.h"18#include "ClangASTMetadata.h"19#include "ClangDiagnostic.h"20#include "ClangExpressionDeclMap.h"21#include "ClangExpressionParser.h"22#include "ClangModulesDeclVendor.h"23#include "ClangPersistentVariables.h"24#include "CppModuleConfiguration.h"2526#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"27#include "lldb/Core/Debugger.h"28#include "lldb/Core/Module.h"29#include "lldb/Core/ValueObjectConstResult.h"30#include "lldb/Expression/ExpressionSourceCode.h"31#include "lldb/Expression/IRExecutionUnit.h"32#include "lldb/Expression/IRInterpreter.h"33#include "lldb/Expression/Materializer.h"34#include "lldb/Host/HostInfo.h"35#include "lldb/Symbol/Block.h"36#include "lldb/Symbol/CompileUnit.h"37#include "lldb/Symbol/Function.h"38#include "lldb/Symbol/ObjectFile.h"39#include "lldb/Symbol/SymbolFile.h"40#include "lldb/Symbol/SymbolVendor.h"41#include "lldb/Symbol/Type.h"42#include "lldb/Symbol/VariableList.h"43#include "lldb/Target/ExecutionContext.h"44#include "lldb/Target/Process.h"45#include "lldb/Target/StackFrame.h"46#include "lldb/Target/Target.h"47#include "lldb/Target/ThreadPlan.h"48#include "lldb/Target/ThreadPlanCallUserExpression.h"49#include "lldb/Utility/ConstString.h"50#include "lldb/Utility/LLDBLog.h"51#include "lldb/Utility/Log.h"52#include "lldb/Utility/StreamString.h"5354#include "clang/AST/DeclCXX.h"55#include "clang/AST/DeclObjC.h"5657#include "llvm/ADT/ScopeExit.h"58#include "llvm/BinaryFormat/Dwarf.h"5960using namespace lldb_private;6162char ClangUserExpression::ID;6364ClangUserExpression::ClangUserExpression(65ExecutionContextScope &exe_scope, llvm::StringRef expr,66llvm::StringRef prefix, SourceLanguage language, ResultType desired_type,67const EvaluateExpressionOptions &options, ValueObject *ctx_obj)68: LLVMUserExpression(exe_scope, expr, prefix, language, desired_type,69options),70m_type_system_helper(*m_target_wp.lock(), options.GetExecutionPolicy() ==71eExecutionPolicyTopLevel),72m_result_delegate(exe_scope.CalculateTarget()), m_ctx_obj(ctx_obj) {73switch (m_language.name) {74case llvm::dwarf::DW_LNAME_C_plus_plus:75m_allow_cxx = true;76break;77case llvm::dwarf::DW_LNAME_ObjC:78m_allow_objc = true;79break;80case llvm::dwarf::DW_LNAME_ObjC_plus_plus:81default:82m_allow_cxx = true;83m_allow_objc = true;84break;85}86}8788ClangUserExpression::~ClangUserExpression() = default;8990void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) {91Log *log = GetLog(LLDBLog::Expressions);9293LLDB_LOGF(log, "ClangUserExpression::ScanContext()");9495m_target = exe_ctx.GetTargetPtr();9697if (!(m_allow_cxx || m_allow_objc)) {98LLDB_LOGF(log, " [CUE::SC] Settings inhibit C++ and Objective-C");99return;100}101102StackFrame *frame = exe_ctx.GetFramePtr();103if (frame == nullptr) {104LLDB_LOGF(log, " [CUE::SC] Null stack frame");105return;106}107108SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction |109lldb::eSymbolContextBlock);110111if (!sym_ctx.function) {112LLDB_LOGF(log, " [CUE::SC] Null function");113return;114}115116// Find the block that defines the function represented by "sym_ctx"117Block *function_block = sym_ctx.GetFunctionBlock();118119if (!function_block) {120LLDB_LOGF(log, " [CUE::SC] Null function block");121return;122}123124CompilerDeclContext decl_context = function_block->GetDeclContext();125126if (!decl_context) {127LLDB_LOGF(log, " [CUE::SC] Null decl context");128return;129}130131if (m_ctx_obj) {132switch (m_ctx_obj->GetObjectRuntimeLanguage()) {133case lldb::eLanguageTypeC:134case lldb::eLanguageTypeC89:135case lldb::eLanguageTypeC99:136case lldb::eLanguageTypeC11:137case lldb::eLanguageTypeC_plus_plus:138case lldb::eLanguageTypeC_plus_plus_03:139case lldb::eLanguageTypeC_plus_plus_11:140case lldb::eLanguageTypeC_plus_plus_14:141m_in_cplusplus_method = true;142break;143case lldb::eLanguageTypeObjC:144case lldb::eLanguageTypeObjC_plus_plus:145m_in_objectivec_method = true;146break;147default:148break;149}150m_needs_object_ptr = true;151} else if (clang::CXXMethodDecl *method_decl =152TypeSystemClang::DeclContextGetAsCXXMethodDecl(decl_context)) {153if (m_allow_cxx && method_decl->isInstance()) {154if (m_enforce_valid_object) {155lldb::VariableListSP variable_list_sp(156function_block->GetBlockVariableList(true));157158const char *thisErrorString = "Stopped in a C++ method, but 'this' "159"isn't available; pretending we are in a "160"generic context";161162if (!variable_list_sp) {163err.SetErrorString(thisErrorString);164return;165}166167lldb::VariableSP this_var_sp(168variable_list_sp->FindVariable(ConstString("this")));169170if (!this_var_sp || !this_var_sp->IsInScope(frame) ||171!this_var_sp->LocationIsValidForFrame(frame)) {172err.SetErrorString(thisErrorString);173return;174}175}176177m_in_cplusplus_method = true;178m_needs_object_ptr = true;179}180} else if (clang::ObjCMethodDecl *method_decl =181TypeSystemClang::DeclContextGetAsObjCMethodDecl(182decl_context)) {183if (m_allow_objc) {184if (m_enforce_valid_object) {185lldb::VariableListSP variable_list_sp(186function_block->GetBlockVariableList(true));187188const char *selfErrorString = "Stopped in an Objective-C method, but "189"'self' isn't available; pretending we "190"are in a generic context";191192if (!variable_list_sp) {193err.SetErrorString(selfErrorString);194return;195}196197lldb::VariableSP self_variable_sp =198variable_list_sp->FindVariable(ConstString("self"));199200if (!self_variable_sp || !self_variable_sp->IsInScope(frame) ||201!self_variable_sp->LocationIsValidForFrame(frame)) {202err.SetErrorString(selfErrorString);203return;204}205}206207m_in_objectivec_method = true;208m_needs_object_ptr = true;209210if (!method_decl->isInstanceMethod())211m_in_static_method = true;212}213} else if (clang::FunctionDecl *function_decl =214TypeSystemClang::DeclContextGetAsFunctionDecl(decl_context)) {215// We might also have a function that said in the debug information that it216// captured an object pointer. The best way to deal with getting to the217// ivars at present is by pretending that this is a method of a class in218// whatever runtime the debug info says the object pointer belongs to. Do219// that here.220221ClangASTMetadata *metadata =222TypeSystemClang::DeclContextGetMetaData(decl_context, function_decl);223if (metadata && metadata->HasObjectPtr()) {224lldb::LanguageType language = metadata->GetObjectPtrLanguage();225if (language == lldb::eLanguageTypeC_plus_plus) {226if (m_enforce_valid_object) {227lldb::VariableListSP variable_list_sp(228function_block->GetBlockVariableList(true));229230const char *thisErrorString = "Stopped in a context claiming to "231"capture a C++ object pointer, but "232"'this' isn't available; pretending we "233"are in a generic context";234235if (!variable_list_sp) {236err.SetErrorString(thisErrorString);237return;238}239240lldb::VariableSP this_var_sp(241variable_list_sp->FindVariable(ConstString("this")));242243if (!this_var_sp || !this_var_sp->IsInScope(frame) ||244!this_var_sp->LocationIsValidForFrame(frame)) {245err.SetErrorString(thisErrorString);246return;247}248}249250m_in_cplusplus_method = true;251m_needs_object_ptr = true;252} else if (language == lldb::eLanguageTypeObjC) {253if (m_enforce_valid_object) {254lldb::VariableListSP variable_list_sp(255function_block->GetBlockVariableList(true));256257const char *selfErrorString =258"Stopped in a context claiming to capture an Objective-C object "259"pointer, but 'self' isn't available; pretending we are in a "260"generic context";261262if (!variable_list_sp) {263err.SetErrorString(selfErrorString);264return;265}266267lldb::VariableSP self_variable_sp =268variable_list_sp->FindVariable(ConstString("self"));269270if (!self_variable_sp || !self_variable_sp->IsInScope(frame) ||271!self_variable_sp->LocationIsValidForFrame(frame)) {272err.SetErrorString(selfErrorString);273return;274}275276Type *self_type = self_variable_sp->GetType();277278if (!self_type) {279err.SetErrorString(selfErrorString);280return;281}282283CompilerType self_clang_type = self_type->GetForwardCompilerType();284285if (!self_clang_type) {286err.SetErrorString(selfErrorString);287return;288}289290if (TypeSystemClang::IsObjCClassType(self_clang_type)) {291return;292} else if (TypeSystemClang::IsObjCObjectPointerType(293self_clang_type)) {294m_in_objectivec_method = true;295m_needs_object_ptr = true;296} else {297err.SetErrorString(selfErrorString);298return;299}300} else {301m_in_objectivec_method = true;302m_needs_object_ptr = true;303}304}305}306}307}308309// This is a really nasty hack, meant to fix Objective-C expressions of the310// form (int)[myArray count]. Right now, because the type information for311// count is not available, [myArray count] returns id, which can't be directly312// cast to int without causing a clang error.313static void ApplyObjcCastHack(std::string &expr) {314const std::string from = "(int)[";315const std::string to = "(int)(long long)[";316317size_t offset;318319while ((offset = expr.find(from)) != expr.npos)320expr.replace(offset, from.size(), to);321}322323bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_manager,324ExecutionContext &exe_ctx) {325if (Target *target = exe_ctx.GetTargetPtr()) {326if (PersistentExpressionState *persistent_state =327target->GetPersistentExpressionStateForLanguage(328lldb::eLanguageTypeC)) {329m_clang_state = llvm::cast<ClangPersistentVariables>(persistent_state);330m_result_delegate.RegisterPersistentState(persistent_state);331} else {332diagnostic_manager.PutString(333lldb::eSeverityError, "couldn't start parsing (no persistent data)");334return false;335}336} else {337diagnostic_manager.PutString(lldb::eSeverityError,338"error: couldn't start parsing (no target)");339return false;340}341return true;342}343344static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target,345DiagnosticManager &diagnostic_manager) {346if (!target->GetEnableAutoImportClangModules())347return;348349auto *persistent_state = llvm::cast<ClangPersistentVariables>(350target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC));351if (!persistent_state)352return;353354std::shared_ptr<ClangModulesDeclVendor> decl_vendor =355persistent_state->GetClangModulesDeclVendor();356if (!decl_vendor)357return;358359StackFrame *frame = exe_ctx.GetFramePtr();360if (!frame)361return;362363Block *block = frame->GetFrameBlock();364if (!block)365return;366SymbolContext sc;367368block->CalculateSymbolContext(&sc);369370if (!sc.comp_unit)371return;372StreamString error_stream;373374ClangModulesDeclVendor::ModuleVector modules_for_macros =375persistent_state->GetHandLoadedClangModules();376if (decl_vendor->AddModulesForCompileUnit(*sc.comp_unit, modules_for_macros,377error_stream))378return;379380// Failed to load some modules, so emit the error stream as a diagnostic.381if (!error_stream.Empty()) {382// The error stream already contains several Clang diagnostics that might383// be either errors or warnings, so just print them all as one remark384// diagnostic to prevent that the message starts with "error: error:".385diagnostic_manager.PutString(lldb::eSeverityInfo, error_stream.GetString());386return;387}388389diagnostic_manager.PutString(lldb::eSeverityError,390"Unknown error while loading modules needed for "391"current compilation unit.");392}393394ClangExpressionSourceCode::WrapKind ClangUserExpression::GetWrapKind() const {395assert(m_options.GetExecutionPolicy() != eExecutionPolicyTopLevel &&396"Top level expressions aren't wrapped.");397using Kind = ClangExpressionSourceCode::WrapKind;398if (m_in_cplusplus_method)399return Kind::CppMemberFunction;400else if (m_in_objectivec_method) {401if (m_in_static_method)402return Kind::ObjCStaticMethod;403return Kind::ObjCInstanceMethod;404}405// Not in any kind of 'special' function, so just wrap it in a normal C406// function.407return Kind::Function;408}409410void ClangUserExpression::CreateSourceCode(411DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,412std::vector<std::string> modules_to_import, bool for_completion) {413414std::string prefix = m_expr_prefix;415416if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {417m_transformed_text = m_expr_text;418} else {419m_source_code.reset(ClangExpressionSourceCode::CreateWrapped(420m_filename, prefix, m_expr_text, GetWrapKind()));421422if (!m_source_code->GetText(m_transformed_text, exe_ctx, !m_ctx_obj,423for_completion, modules_to_import)) {424diagnostic_manager.PutString(lldb::eSeverityError,425"couldn't construct expression body");426return;427}428429// Find and store the start position of the original code inside the430// transformed code. We need this later for the code completion.431std::size_t original_start;432std::size_t original_end;433bool found_bounds = m_source_code->GetOriginalBodyBounds(434m_transformed_text, original_start, original_end);435if (found_bounds)436m_user_expression_start_pos = original_start;437}438}439440static bool SupportsCxxModuleImport(lldb::LanguageType language) {441switch (language) {442case lldb::eLanguageTypeC_plus_plus:443case lldb::eLanguageTypeC_plus_plus_03:444case lldb::eLanguageTypeC_plus_plus_11:445case lldb::eLanguageTypeC_plus_plus_14:446case lldb::eLanguageTypeObjC_plus_plus:447return true;448default:449return false;450}451}452453/// Utility method that puts a message into the expression log and454/// returns an invalid module configuration.455static CppModuleConfiguration LogConfigError(const std::string &msg) {456Log *log = GetLog(LLDBLog::Expressions);457LLDB_LOG(log, "[C++ module config] {0}", msg);458return CppModuleConfiguration();459}460461CppModuleConfiguration GetModuleConfig(lldb::LanguageType language,462ExecutionContext &exe_ctx) {463Log *log = GetLog(LLDBLog::Expressions);464465// Don't do anything if this is not a C++ module configuration.466if (!SupportsCxxModuleImport(language))467return LogConfigError("Language doesn't support C++ modules");468469Target *target = exe_ctx.GetTargetPtr();470if (!target)471return LogConfigError("No target");472473StackFrame *frame = exe_ctx.GetFramePtr();474if (!frame)475return LogConfigError("No frame");476477Block *block = frame->GetFrameBlock();478if (!block)479return LogConfigError("No block");480481SymbolContext sc;482block->CalculateSymbolContext(&sc);483if (!sc.comp_unit)484return LogConfigError("Couldn't calculate symbol context");485486// Build a list of files we need to analyze to build the configuration.487FileSpecList files;488for (auto &f : sc.comp_unit->GetSupportFiles())489files.AppendIfUnique(f->Materialize());490// We also need to look at external modules in the case of -gmodules as they491// contain the support files for libc++ and the C library.492llvm::DenseSet<SymbolFile *> visited_symbol_files;493sc.comp_unit->ForEachExternalModule(494visited_symbol_files, [&files](Module &module) {495for (std::size_t i = 0; i < module.GetNumCompileUnits(); ++i) {496const SupportFileList &support_files =497module.GetCompileUnitAtIndex(i)->GetSupportFiles();498for (auto &f : support_files) {499files.AppendIfUnique(f->Materialize());500}501}502return false;503});504505LLDB_LOG(log, "[C++ module config] Found {0} support files to analyze",506files.GetSize());507if (log && log->GetVerbose()) {508for (auto &f : files)509LLDB_LOGV(log, "[C++ module config] Analyzing support file: {0}",510f.GetPath());511}512513// Try to create a configuration from the files. If there is no valid514// configuration possible with the files, this just returns an invalid515// configuration.516return CppModuleConfiguration(files, target->GetArchitecture().GetTriple());517}518519bool ClangUserExpression::PrepareForParsing(520DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,521bool for_completion) {522InstallContext(exe_ctx);523524if (!SetupPersistentState(diagnostic_manager, exe_ctx))525return false;526527Status err;528ScanContext(exe_ctx, err);529530if (!err.Success()) {531diagnostic_manager.PutString(lldb::eSeverityWarning, err.AsCString());532}533534////////////////////////////////////535// Generate the expression536//537538ApplyObjcCastHack(m_expr_text);539540SetupDeclVendor(exe_ctx, m_target, diagnostic_manager);541542m_filename = m_clang_state->GetNextExprFileName();543544if (m_target->GetImportStdModule() == eImportStdModuleTrue)545SetupCppModuleImports(exe_ctx);546547CreateSourceCode(diagnostic_manager, exe_ctx, m_imported_cpp_modules,548for_completion);549return true;550}551552bool ClangUserExpression::TryParse(553DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,554lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory,555bool generate_debug_info) {556m_materializer_up = std::make_unique<Materializer>();557558ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory);559560auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); });561562if (!DeclMap()->WillParse(exe_ctx, GetMaterializer())) {563diagnostic_manager.PutString(564lldb::eSeverityError,565"current process state is unsuitable for expression parsing");566return false;567}568569if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {570DeclMap()->SetLookupsEnabled(true);571}572573m_parser = std::make_unique<ClangExpressionParser>(574exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info,575m_include_directories, m_filename);576577unsigned num_errors = m_parser->Parse(diagnostic_manager);578579// Check here for FixItHints. If there are any try to apply the fixits and580// set the fixed text in m_fixed_text before returning an error.581if (num_errors) {582if (diagnostic_manager.HasFixIts()) {583if (m_parser->RewriteExpression(diagnostic_manager)) {584size_t fixed_start;585size_t fixed_end;586m_fixed_text = diagnostic_manager.GetFixedExpression();587// Retrieve the original expression in case we don't have a top level588// expression (which has no surrounding source code).589if (m_source_code && m_source_code->GetOriginalBodyBounds(590m_fixed_text, fixed_start, fixed_end))591m_fixed_text =592m_fixed_text.substr(fixed_start, fixed_end - fixed_start);593}594}595return false;596}597598//////////////////////////////////////////////////////////////////////////////599// Prepare the output of the parser for execution, evaluating it statically600// if possible601//602603{604Status jit_error = m_parser->PrepareForExecution(605m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,606m_can_interpret, execution_policy);607608if (!jit_error.Success()) {609const char *error_cstr = jit_error.AsCString();610if (error_cstr && error_cstr[0])611diagnostic_manager.PutString(lldb::eSeverityError, error_cstr);612else613diagnostic_manager.PutString(lldb::eSeverityError,614"expression can't be interpreted or run");615return false;616}617}618return true;619}620621void ClangUserExpression::SetupCppModuleImports(ExecutionContext &exe_ctx) {622Log *log = GetLog(LLDBLog::Expressions);623624CppModuleConfiguration module_config =625GetModuleConfig(m_language.AsLanguageType(), exe_ctx);626m_imported_cpp_modules = module_config.GetImportedModules();627m_include_directories = module_config.GetIncludeDirs();628629LLDB_LOG(log, "List of imported modules in expression: {0}",630llvm::make_range(m_imported_cpp_modules.begin(),631m_imported_cpp_modules.end()));632LLDB_LOG(log, "List of include directories gathered for modules: {0}",633llvm::make_range(m_include_directories.begin(),634m_include_directories.end()));635}636637static bool shouldRetryWithCppModule(Target &target, ExecutionPolicy exe_policy) {638// Top-level expression don't yet support importing C++ modules.639if (exe_policy == ExecutionPolicy::eExecutionPolicyTopLevel)640return false;641return target.GetImportStdModule() == eImportStdModuleFallback;642}643644bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager,645ExecutionContext &exe_ctx,646lldb_private::ExecutionPolicy execution_policy,647bool keep_result_in_memory,648bool generate_debug_info) {649Log *log = GetLog(LLDBLog::Expressions);650651if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false))652return false;653654LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str());655656////////////////////////////////////657// Set up the target and compiler658//659660Target *target = exe_ctx.GetTargetPtr();661662if (!target) {663diagnostic_manager.PutString(lldb::eSeverityError, "invalid target");664return false;665}666667//////////////////////////668// Parse the expression669//670671bool parse_success = TryParse(diagnostic_manager, exe_ctx, execution_policy,672keep_result_in_memory, generate_debug_info);673// If the expression failed to parse, check if retrying parsing with a loaded674// C++ module is possible.675if (!parse_success && shouldRetryWithCppModule(*target, execution_policy)) {676// Load the loaded C++ modules.677SetupCppModuleImports(exe_ctx);678// If we did load any modules, then retry parsing.679if (!m_imported_cpp_modules.empty()) {680// Create a dedicated diagnostic manager for the second parse attempt.681// These diagnostics are only returned to the caller if using the fallback682// actually succeeded in getting the expression to parse. This prevents683// that module-specific issues regress diagnostic quality with the684// fallback mode.685DiagnosticManager retry_manager;686// The module imports are injected into the source code wrapper,687// so recreate those.688CreateSourceCode(retry_manager, exe_ctx, m_imported_cpp_modules,689/*for_completion*/ false);690parse_success = TryParse(retry_manager, exe_ctx, execution_policy,691keep_result_in_memory, generate_debug_info);692// Return the parse diagnostics if we were successful.693if (parse_success)694diagnostic_manager = std::move(retry_manager);695}696}697if (!parse_success)698return false;699700if (m_execution_unit_sp) {701bool register_execution_unit = false;702703if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {704register_execution_unit = true;705}706707// If there is more than one external function in the execution unit, it708// needs to keep living even if it's not top level, because the result709// could refer to that function.710711if (m_execution_unit_sp->GetJittedFunctions().size() > 1) {712register_execution_unit = true;713}714715if (register_execution_unit) {716if (auto *persistent_state =717exe_ctx.GetTargetPtr()->GetPersistentExpressionStateForLanguage(718m_language.AsLanguageType()))719persistent_state->RegisterExecutionUnit(m_execution_unit_sp);720}721}722723if (generate_debug_info) {724lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());725726if (jit_module_sp) {727ConstString const_func_name(FunctionName());728FileSpec jit_file;729jit_file.SetFilename(const_func_name);730jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());731m_jit_module_wp = jit_module_sp;732target->GetImages().Append(jit_module_sp);733}734}735736Process *process = exe_ctx.GetProcessPtr();737if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS)738m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());739return true;740}741742/// Converts an absolute position inside a given code string into743/// a column/line pair.744///745/// \param[in] abs_pos746/// A absolute position in the code string that we want to convert747/// to a column/line pair.748///749/// \param[in] code750/// A multi-line string usually representing source code.751///752/// \param[out] line753/// The line in the code that contains the given absolute position.754/// The first line in the string is indexed as 1.755///756/// \param[out] column757/// The column in the line that contains the absolute position.758/// The first character in a line is indexed as 0.759static void AbsPosToLineColumnPos(size_t abs_pos, llvm::StringRef code,760unsigned &line, unsigned &column) {761// Reset to code position to beginning of the file.762line = 0;763column = 0;764765assert(abs_pos <= code.size() && "Absolute position outside code string?");766767// We have to walk up to the position and count lines/columns.768for (std::size_t i = 0; i < abs_pos; ++i) {769// If we hit a line break, we go back to column 0 and enter a new line.770// We only handle \n because that's what we internally use to make new771// lines for our temporary code strings.772if (code[i] == '\n') {773++line;774column = 0;775continue;776}777++column;778}779}780781bool ClangUserExpression::Complete(ExecutionContext &exe_ctx,782CompletionRequest &request,783unsigned complete_pos) {784Log *log = GetLog(LLDBLog::Expressions);785786// We don't want any visible feedback when completing an expression. Mostly787// because the results we get from an incomplete invocation are probably not788// correct.789DiagnosticManager diagnostic_manager;790791if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ true))792return false;793794LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str());795796//////////////////////////797// Parse the expression798//799800m_materializer_up = std::make_unique<Materializer>();801802ResetDeclMap(exe_ctx, m_result_delegate, /*keep result in memory*/ true);803804auto on_exit = llvm::make_scope_exit([this]() { ResetDeclMap(); });805806if (!DeclMap()->WillParse(exe_ctx, GetMaterializer())) {807diagnostic_manager.PutString(808lldb::eSeverityError,809"current process state is unsuitable for expression parsing");810811return false;812}813814if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) {815DeclMap()->SetLookupsEnabled(true);816}817818ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,819false);820821// We have to find the source code location where the user text is inside822// the transformed expression code. When creating the transformed text, we823// already stored the absolute position in the m_transformed_text string. The824// only thing left to do is to transform it into the line:column format that825// Clang expects.826827// The line and column of the user expression inside the transformed source828// code.829unsigned user_expr_line, user_expr_column;830if (m_user_expression_start_pos)831AbsPosToLineColumnPos(*m_user_expression_start_pos, m_transformed_text,832user_expr_line, user_expr_column);833else834return false;835836// The actual column where we have to complete is the start column of the837// user expression + the offset inside the user code that we were given.838const unsigned completion_column = user_expr_column + complete_pos;839parser.Complete(request, user_expr_line, completion_column, complete_pos);840841return true;842}843844lldb::addr_t ClangUserExpression::GetCppObjectPointer(845lldb::StackFrameSP frame_sp, llvm::StringRef object_name, Status &err) {846auto valobj_sp =847GetObjectPointerValueObject(std::move(frame_sp), object_name, err);848849// We're inside a C++ class method. This could potentially be an unnamed850// lambda structure. If the lambda captured a "this", that should be851// the object pointer.852if (auto thisChildSP = valobj_sp->GetChildMemberWithName("this")) {853valobj_sp = thisChildSP;854}855856if (!err.Success() || !valobj_sp.get())857return LLDB_INVALID_ADDRESS;858859lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);860861if (ret == LLDB_INVALID_ADDRESS) {862err.SetErrorStringWithFormatv(863"Couldn't load '{0}' because its value couldn't be evaluated",864object_name);865return LLDB_INVALID_ADDRESS;866}867868return ret;869}870871bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx,872std::vector<lldb::addr_t> &args,873lldb::addr_t struct_address,874DiagnosticManager &diagnostic_manager) {875lldb::addr_t object_ptr = LLDB_INVALID_ADDRESS;876lldb::addr_t cmd_ptr = LLDB_INVALID_ADDRESS;877878if (m_needs_object_ptr) {879lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP();880if (!frame_sp)881return true;882883if (!m_in_cplusplus_method && !m_in_objectivec_method) {884diagnostic_manager.PutString(885lldb::eSeverityError,886"need object pointer but don't know the language");887return false;888}889890static constexpr llvm::StringLiteral g_cplusplus_object_name("this");891static constexpr llvm::StringLiteral g_objc_object_name("self");892llvm::StringRef object_name =893m_in_cplusplus_method ? g_cplusplus_object_name : g_objc_object_name;894895Status object_ptr_error;896897if (m_ctx_obj) {898AddressType address_type;899object_ptr = m_ctx_obj->GetAddressOf(false, &address_type);900if (object_ptr == LLDB_INVALID_ADDRESS ||901address_type != eAddressTypeLoad)902object_ptr_error.SetErrorString("Can't get context object's "903"debuggee address");904} else {905if (m_in_cplusplus_method) {906object_ptr =907GetCppObjectPointer(frame_sp, object_name, object_ptr_error);908} else {909object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);910}911}912913if (!object_ptr_error.Success()) {914exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Format(915"warning: `{0}' is not accessible (substituting 0). {1}\n",916object_name, object_ptr_error.AsCString());917object_ptr = 0;918}919920if (m_in_objectivec_method) {921static constexpr llvm::StringLiteral cmd_name("_cmd");922923cmd_ptr = GetObjectPointer(frame_sp, cmd_name, object_ptr_error);924925if (!object_ptr_error.Success()) {926diagnostic_manager.Printf(927lldb::eSeverityWarning,928"couldn't get cmd pointer (substituting NULL): %s",929object_ptr_error.AsCString());930cmd_ptr = 0;931}932}933934args.push_back(object_ptr);935936if (m_in_objectivec_method)937args.push_back(cmd_ptr);938939args.push_back(struct_address);940} else {941args.push_back(struct_address);942}943return true;944}945946lldb::ExpressionVariableSP ClangUserExpression::GetResultAfterDematerialization(947ExecutionContextScope *exe_scope) {948return m_result_delegate.GetVariable();949}950951char ClangUserExpression::ClangUserExpressionHelper::ID;952953void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(954ExecutionContext &exe_ctx,955Materializer::PersistentVariableDelegate &delegate,956bool keep_result_in_memory,957ValueObject *ctx_obj) {958std::shared_ptr<ClangASTImporter> ast_importer;959auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage(960lldb::eLanguageTypeC);961if (state) {962auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);963ast_importer = persistent_vars->GetClangASTImporter();964}965m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>(966keep_result_in_memory, &delegate, exe_ctx.GetTargetSP(), ast_importer,967ctx_obj);968}969970clang::ASTConsumer *971ClangUserExpression::ClangUserExpressionHelper::ASTTransformer(972clang::ASTConsumer *passthrough) {973m_result_synthesizer_up = std::make_unique<ASTResultSynthesizer>(974passthrough, m_top_level, m_target);975976return m_result_synthesizer_up.get();977}978979void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() {980if (m_result_synthesizer_up) {981m_result_synthesizer_up->CommitPersistentDecls();982}983}984985ConstString ClangUserExpression::ResultDelegate::GetName() {986return m_persistent_state->GetNextPersistentVariableName(false);987}988989void ClangUserExpression::ResultDelegate::DidDematerialize(990lldb::ExpressionVariableSP &variable) {991m_variable = variable;992}993994void ClangUserExpression::ResultDelegate::RegisterPersistentState(995PersistentExpressionState *persistent_state) {996m_persistent_state = persistent_state;997}998999lldb::ExpressionVariableSP &ClangUserExpression::ResultDelegate::GetVariable() {1000return m_variable;1001}100210031004