15ffd83dbSDimitry Andric //===-- ClangUtilityFunction.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 "ClangUtilityFunction.h" 100b57cec5SDimitry Andric #include "ClangExpressionDeclMap.h" 110b57cec5SDimitry Andric #include "ClangExpressionParser.h" 120b57cec5SDimitry Andric #include "ClangExpressionSourceCode.h" 135ffd83dbSDimitry Andric #include "ClangPersistentVariables.h" 140b57cec5SDimitry Andric 15fe6060f1SDimitry Andric #include <cstdio> 160b57cec5SDimitry Andric #include <sys/types.h> 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #include "lldb/Core/Module.h" 200b57cec5SDimitry Andric #include "lldb/Expression/IRExecutionUnit.h" 210b57cec5SDimitry Andric #include "lldb/Host/Host.h" 220b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h" 230b57cec5SDimitry Andric #include "lldb/Target/Target.h" 240b57cec5SDimitry Andric #include "lldb/Utility/ConstString.h" 250b57cec5SDimitry Andric #include "lldb/Utility/Log.h" 260b57cec5SDimitry Andric #include "lldb/Utility/Stream.h" 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric using namespace lldb_private; 290b57cec5SDimitry Andric 30480093f4SDimitry Andric char ClangUtilityFunction::ID; 31480093f4SDimitry Andric 320b57cec5SDimitry Andric ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope, 33fe6060f1SDimitry Andric std::string text, std::string name, 34fe6060f1SDimitry Andric bool enable_debugging) 35e8d8bef9SDimitry Andric : UtilityFunction( 36e8d8bef9SDimitry Andric exe_scope, 37fe6060f1SDimitry Andric std::string(ClangExpressionSourceCode::g_expression_prefix) + text + 38fe6060f1SDimitry Andric std::string(ClangExpressionSourceCode::g_expression_suffix), 39fe6060f1SDimitry Andric std::move(name), enable_debugging) { 40fe6060f1SDimitry Andric // Write the source code to a file so that LLDB's source manager can display 41fe6060f1SDimitry Andric // it when debugging the code. 42fe6060f1SDimitry Andric if (enable_debugging) { 43fe6060f1SDimitry Andric int temp_fd = -1; 44fe6060f1SDimitry Andric llvm::SmallString<128> result_path; 45fe6060f1SDimitry Andric llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path); 46fe6060f1SDimitry Andric if (temp_fd != -1) { 47349cc55cSDimitry Andric lldb_private::NativeFile file(temp_fd, File::eOpenOptionWriteOnly, true); 48fe6060f1SDimitry Andric text = "#line 1 \"" + std::string(result_path) + "\"\n" + text; 49fe6060f1SDimitry Andric size_t bytes_written = text.size(); 50fe6060f1SDimitry Andric file.Write(text.c_str(), bytes_written); 51fe6060f1SDimitry Andric if (bytes_written == text.size()) { 52fe6060f1SDimitry Andric // If we successfully wrote the source to a temporary file, replace the 53fe6060f1SDimitry Andric // function text with the next text containing the line directive. 54fe6060f1SDimitry Andric m_function_text = 55fe6060f1SDimitry Andric std::string(ClangExpressionSourceCode::g_expression_prefix) + text + 56fe6060f1SDimitry Andric std::string(ClangExpressionSourceCode::g_expression_suffix); 57fe6060f1SDimitry Andric } 58fe6060f1SDimitry Andric file.Close(); 59fe6060f1SDimitry Andric } 60fe6060f1SDimitry Andric } 61fe6060f1SDimitry Andric } 620b57cec5SDimitry Andric 63fe6060f1SDimitry Andric ClangUtilityFunction::~ClangUtilityFunction() = default; 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric /// Install the utility function into a process 660b57cec5SDimitry Andric /// 670b57cec5SDimitry Andric /// \param[in] diagnostic_manager 680b57cec5SDimitry Andric /// A diagnostic manager to report errors and warnings to. 690b57cec5SDimitry Andric /// 700b57cec5SDimitry Andric /// \param[in] exe_ctx 710b57cec5SDimitry Andric /// The execution context to install the utility function to. 720b57cec5SDimitry Andric /// 730b57cec5SDimitry Andric /// \return 740b57cec5SDimitry Andric /// True on success (no errors); false otherwise. 750b57cec5SDimitry Andric bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, 760b57cec5SDimitry Andric ExecutionContext &exe_ctx) { 770b57cec5SDimitry Andric if (m_jit_start_addr != LLDB_INVALID_ADDRESS) { 78*0fca6ea1SDimitry Andric diagnostic_manager.PutString(lldb::eSeverityWarning, "already installed"); 790b57cec5SDimitry Andric return false; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric //////////////////////////////////// 830b57cec5SDimitry Andric // Set up the target and compiler 840b57cec5SDimitry Andric // 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric Target *target = exe_ctx.GetTargetPtr(); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric if (!target) { 89*0fca6ea1SDimitry Andric diagnostic_manager.PutString(lldb::eSeverityError, "invalid target"); 900b57cec5SDimitry Andric return false; 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric Process *process = exe_ctx.GetProcessPtr(); 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric if (!process) { 96*0fca6ea1SDimitry Andric diagnostic_manager.PutString(lldb::eSeverityError, "invalid process"); 970b57cec5SDimitry Andric return false; 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 100bdd1243dSDimitry Andric // Since we might need to call allocate memory and maybe call code to make 101bdd1243dSDimitry Andric // the caller, we need to be stopped. 102bdd1243dSDimitry Andric if (process->GetState() != lldb::eStateStopped) { 103*0fca6ea1SDimitry Andric diagnostic_manager.PutString(lldb::eSeverityError, "process running"); 104bdd1243dSDimitry Andric return false; 105bdd1243dSDimitry Andric } 1060b57cec5SDimitry Andric ////////////////////////// 1070b57cec5SDimitry Andric // Parse the expression 1080b57cec5SDimitry Andric // 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric bool keep_result_in_memory = false; 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric ResetDeclMap(exe_ctx, keep_result_in_memory); 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric if (!DeclMap()->WillParse(exe_ctx, nullptr)) { 1150b57cec5SDimitry Andric diagnostic_manager.PutString( 116*0fca6ea1SDimitry Andric lldb::eSeverityError, 1170b57cec5SDimitry Andric "current process state is unsuitable for expression parsing"); 1180b57cec5SDimitry Andric return false; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric const bool generate_debug_info = true; 1220b57cec5SDimitry Andric ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this, 1230b57cec5SDimitry Andric generate_debug_info); 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric unsigned num_errors = parser.Parse(diagnostic_manager); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric if (num_errors) { 1280b57cec5SDimitry Andric ResetDeclMap(); 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric return false; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric ////////////////////////////////// 1340b57cec5SDimitry Andric // JIT the output of the parser 1350b57cec5SDimitry Andric // 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric bool can_interpret = false; // should stay that way 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric Status jit_error = parser.PrepareForExecution( 1400b57cec5SDimitry Andric m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx, 1410b57cec5SDimitry Andric can_interpret, eExecutionPolicyAlways); 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric if (m_jit_start_addr != LLDB_INVALID_ADDRESS) { 1440b57cec5SDimitry Andric m_jit_process_wp = process->shared_from_this(); 1450b57cec5SDimitry Andric if (parser.GetGenerateDebugInfo()) { 1460b57cec5SDimitry Andric lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule()); 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric if (jit_module_sp) { 1490b57cec5SDimitry Andric ConstString const_func_name(FunctionName()); 1500b57cec5SDimitry Andric FileSpec jit_file; 151bdd1243dSDimitry Andric jit_file.SetFilename(const_func_name); 1520b57cec5SDimitry Andric jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString()); 1530b57cec5SDimitry Andric m_jit_module_wp = jit_module_sp; 1540b57cec5SDimitry Andric target->GetImages().Append(jit_module_sp); 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric DeclMap()->DidParse(); 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric ResetDeclMap(); 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric if (jit_error.Success()) { 1640b57cec5SDimitry Andric return true; 1650b57cec5SDimitry Andric } else { 1660b57cec5SDimitry Andric const char *error_cstr = jit_error.AsCString(); 1670b57cec5SDimitry Andric if (error_cstr && error_cstr[0]) { 168*0fca6ea1SDimitry Andric diagnostic_manager.Printf(lldb::eSeverityError, "%s", error_cstr); 1690b57cec5SDimitry Andric } else { 170*0fca6ea1SDimitry Andric diagnostic_manager.PutString(lldb::eSeverityError, 1710b57cec5SDimitry Andric "expression can't be interpreted or run"); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric return false; 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 17706c3fb27SDimitry Andric char ClangUtilityFunction::ClangUtilityFunctionHelper::ID; 17806c3fb27SDimitry Andric 1790b57cec5SDimitry Andric void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap( 1800b57cec5SDimitry Andric ExecutionContext &exe_ctx, bool keep_result_in_memory) { 1815ffd83dbSDimitry Andric std::shared_ptr<ClangASTImporter> ast_importer; 1825ffd83dbSDimitry Andric auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage( 1835ffd83dbSDimitry Andric lldb::eLanguageTypeC); 1845ffd83dbSDimitry Andric if (state) { 1855ffd83dbSDimitry Andric auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); 1865ffd83dbSDimitry Andric ast_importer = persistent_vars->GetClangASTImporter(); 1875ffd83dbSDimitry Andric } 1885ffd83dbSDimitry Andric m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>( 1895ffd83dbSDimitry Andric keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer, 1905ffd83dbSDimitry Andric nullptr); 1910b57cec5SDimitry Andric } 192