xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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