192 lines · cpp
1//===-- ClangUtilityFunction.cpp ------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ClangUtilityFunction.h"10#include "ClangExpressionDeclMap.h"11#include "ClangExpressionParser.h"12#include "ClangExpressionSourceCode.h"13#include "ClangPersistentVariables.h"14 15#include <cstdio>16#include <sys/types.h>17 18 19#include "lldb/Core/Module.h"20#include "lldb/Expression/IRExecutionUnit.h"21#include "lldb/Host/Host.h"22#include "lldb/Target/ExecutionContext.h"23#include "lldb/Target/Target.h"24#include "lldb/Utility/ConstString.h"25#include "lldb/Utility/Log.h"26#include "lldb/Utility/Stream.h"27 28using namespace lldb_private;29 30char ClangUtilityFunction::ID;31 32ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope,33 std::string text, std::string name,34 bool enable_debugging)35 : UtilityFunction(36 exe_scope,37 std::string(ClangExpressionSourceCode::g_expression_prefix) + text +38 std::string(ClangExpressionSourceCode::g_expression_suffix),39 std::move(name), enable_debugging) {40 // Write the source code to a file so that LLDB's source manager can display41 // it when debugging the code.42 if (enable_debugging) {43 int temp_fd = -1;44 llvm::SmallString<128> result_path;45 llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path);46 if (temp_fd != -1) {47 lldb_private::NativeFile file(temp_fd, File::eOpenOptionWriteOnly, true);48 text = "#line 1 \"" + std::string(result_path) + "\"\n" + text;49 size_t bytes_written = text.size();50 file.Write(text.c_str(), bytes_written);51 if (bytes_written == text.size()) {52 // If we successfully wrote the source to a temporary file, replace the53 // function text with the next text containing the line directive.54 m_function_text =55 std::string(ClangExpressionSourceCode::g_expression_prefix) + text +56 std::string(ClangExpressionSourceCode::g_expression_suffix);57 }58 file.Close();59 }60 }61}62 63ClangUtilityFunction::~ClangUtilityFunction() = default;64 65/// Install the utility function into a process66///67/// \param[in] diagnostic_manager68/// A diagnostic manager to report errors and warnings to.69///70/// \param[in] exe_ctx71/// The execution context to install the utility function to.72///73/// \return74/// True on success (no errors); false otherwise.75bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,76 ExecutionContext &exe_ctx) {77 if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {78 diagnostic_manager.PutString(lldb::eSeverityWarning, "already installed");79 return false;80 }81 82 ////////////////////////////////////83 // Set up the target and compiler84 //85 86 Target *target = exe_ctx.GetTargetPtr();87 88 if (!target) {89 diagnostic_manager.PutString(lldb::eSeverityError, "invalid target");90 return false;91 }92 93 Process *process = exe_ctx.GetProcessPtr();94 95 if (!process) {96 diagnostic_manager.PutString(lldb::eSeverityError, "invalid process");97 return false;98 }99 100 // Since we might need to call allocate memory and maybe call code to make101 // the caller, we need to be stopped.102 if (process->GetState() != lldb::eStateStopped) {103 diagnostic_manager.PutString(lldb::eSeverityError, "process running");104 return false;105 }106 //////////////////////////107 // Parse the expression108 //109 110 bool keep_result_in_memory = false;111 112 ResetDeclMap(exe_ctx, keep_result_in_memory);113 114 if (!DeclMap()->WillParse(exe_ctx, nullptr)) {115 diagnostic_manager.PutString(116 lldb::eSeverityError,117 "current process state is unsuitable for expression parsing");118 return false;119 }120 121 const bool generate_debug_info = true;122 ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,123 generate_debug_info, diagnostic_manager);124 125 unsigned num_errors = parser.Parse(diagnostic_manager);126 127 if (num_errors) {128 ResetDeclMap();129 130 return false;131 }132 133 //////////////////////////////////134 // JIT the output of the parser135 //136 137 bool can_interpret = false; // should stay that way138 139 Status jit_error = parser.PrepareForExecution(140 m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,141 can_interpret, eExecutionPolicyAlways);142 143 if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {144 m_jit_process_wp = process->shared_from_this();145 if (parser.GetGenerateDebugInfo()) {146 lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());147 148 if (jit_module_sp) {149 ConstString const_func_name(FunctionName());150 FileSpec jit_file;151 jit_file.SetFilename(const_func_name);152 jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());153 m_jit_module_wp = jit_module_sp;154 target->GetImages().Append(jit_module_sp);155 }156 }157 }158 159 DeclMap()->DidParse();160 161 ResetDeclMap();162 163 if (jit_error.Success()) {164 return true;165 } else {166 const char *error_cstr = jit_error.AsCString();167 if (error_cstr && error_cstr[0]) {168 diagnostic_manager.Printf(lldb::eSeverityError, "%s", error_cstr);169 } else {170 diagnostic_manager.PutString(lldb::eSeverityError,171 "expression can't be interpreted or run");172 }173 return false;174 }175}176 177char ClangUtilityFunction::ClangUtilityFunctionHelper::ID;178 179void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(180 ExecutionContext &exe_ctx, bool keep_result_in_memory) {181 std::shared_ptr<ClangASTImporter> ast_importer;182 auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage(183 lldb::eLanguageTypeC);184 if (state) {185 auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);186 ast_importer = persistent_vars->GetClangASTImporter();187 }188 m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>(189 keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer,190 nullptr);191}192