180814287SRaphael Isemann //===-- ClangUtilityFunction.cpp ------------------------------------------===//
24dbb271fSSean Callanan //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64dbb271fSSean Callanan //
74dbb271fSSean Callanan //===----------------------------------------------------------------------===//
84dbb271fSSean Callanan
9b9c1b51eSKate Stone #include "ClangUtilityFunction.h"
104dbb271fSSean Callanan #include "ClangExpressionDeclMap.h"
114dbb271fSSean Callanan #include "ClangExpressionParser.h"
12ea401ec7SJim Ingham #include "ClangExpressionSourceCode.h"
13c4f6fbe9SAlex Langford #include "ClangPersistentVariables.h"
144dbb271fSSean Callanan
1576e47d48SRaphael Isemann #include <cstdio>
164dbb271fSSean Callanan #include <sys/types.h>
174dbb271fSSean Callanan
184dbb271fSSean Callanan
194dbb271fSSean Callanan #include "lldb/Core/Module.h"
204dbb271fSSean Callanan #include "lldb/Core/StreamFile.h"
214dbb271fSSean Callanan #include "lldb/Expression/IRExecutionUnit.h"
224dbb271fSSean Callanan #include "lldb/Host/Host.h"
234dbb271fSSean Callanan #include "lldb/Target/ExecutionContext.h"
244dbb271fSSean Callanan #include "lldb/Target/Target.h"
25bf9a7730SZachary Turner #include "lldb/Utility/ConstString.h"
266f9e6901SZachary Turner #include "lldb/Utility/Log.h"
27bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
284dbb271fSSean Callanan
294dbb271fSSean Callanan using namespace lldb_private;
304dbb271fSSean Callanan
3152f3a2faSRaphael Isemann char ClangUtilityFunction::ID;
3252f3a2faSRaphael Isemann
ClangUtilityFunction(ExecutionContextScope & exe_scope,std::string text,std::string name,bool enable_debugging)334dbb271fSSean Callanan ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope,
3438dfb235SJonas Devlieghere std::string text, std::string name,
3538dfb235SJonas Devlieghere bool enable_debugging)
363590a831SJonas Devlieghere : UtilityFunction(
373590a831SJonas Devlieghere exe_scope,
3838dfb235SJonas Devlieghere std::string(ClangExpressionSourceCode::g_expression_prefix) + text +
3938dfb235SJonas Devlieghere std::string(ClangExpressionSourceCode::g_expression_suffix),
4038dfb235SJonas Devlieghere std::move(name), enable_debugging) {
4138dfb235SJonas Devlieghere // Write the source code to a file so that LLDB's source manager can display
4238dfb235SJonas Devlieghere // it when debugging the code.
4338dfb235SJonas Devlieghere if (enable_debugging) {
4438dfb235SJonas Devlieghere int temp_fd = -1;
4538dfb235SJonas Devlieghere llvm::SmallString<128> result_path;
4638dfb235SJonas Devlieghere llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path);
4738dfb235SJonas Devlieghere if (temp_fd != -1) {
4814735cabSMichał Górny lldb_private::NativeFile file(temp_fd, File::eOpenOptionWriteOnly, true);
4938dfb235SJonas Devlieghere text = "#line 1 \"" + std::string(result_path) + "\"\n" + text;
5038dfb235SJonas Devlieghere size_t bytes_written = text.size();
5138dfb235SJonas Devlieghere file.Write(text.c_str(), bytes_written);
5238dfb235SJonas Devlieghere if (bytes_written == text.size()) {
5338dfb235SJonas Devlieghere // If we successfully wrote the source to a temporary file, replace the
5438dfb235SJonas Devlieghere // function text with the next text containing the line directive.
5538dfb235SJonas Devlieghere m_function_text =
5638dfb235SJonas Devlieghere std::string(ClangExpressionSourceCode::g_expression_prefix) + text +
5738dfb235SJonas Devlieghere std::string(ClangExpressionSourceCode::g_expression_suffix);
5838dfb235SJonas Devlieghere }
5938dfb235SJonas Devlieghere file.Close();
6038dfb235SJonas Devlieghere }
6138dfb235SJonas Devlieghere }
6238dfb235SJonas Devlieghere }
634dbb271fSSean Callanan
64fd2433e1SJonas Devlieghere ClangUtilityFunction::~ClangUtilityFunction() = default;
654dbb271fSSean Callanan
664dbb271fSSean Callanan /// Install the utility function into a process
674dbb271fSSean Callanan ///
68f05b42e9SAdrian Prantl /// \param[in] diagnostic_manager
69579e70c9SSean Callanan /// A diagnostic manager to report errors and warnings to.
704dbb271fSSean Callanan ///
71f05b42e9SAdrian Prantl /// \param[in] exe_ctx
724dbb271fSSean Callanan /// The execution context to install the utility function to.
734dbb271fSSean Callanan ///
74f05b42e9SAdrian Prantl /// \return
754dbb271fSSean Callanan /// True on success (no errors); false otherwise.
Install(DiagnosticManager & diagnostic_manager,ExecutionContext & exe_ctx)76b9c1b51eSKate Stone bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,
77b9c1b51eSKate Stone ExecutionContext &exe_ctx) {
78b9c1b51eSKate Stone if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
79e2411fabSZachary Turner diagnostic_manager.PutString(eDiagnosticSeverityWarning,
80b9c1b51eSKate Stone "already installed");
814dbb271fSSean Callanan return false;
824dbb271fSSean Callanan }
834dbb271fSSean Callanan
844dbb271fSSean Callanan ////////////////////////////////////
854dbb271fSSean Callanan // Set up the target and compiler
864dbb271fSSean Callanan //
874dbb271fSSean Callanan
884dbb271fSSean Callanan Target *target = exe_ctx.GetTargetPtr();
894dbb271fSSean Callanan
90b9c1b51eSKate Stone if (!target) {
91e2411fabSZachary Turner diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target");
924dbb271fSSean Callanan return false;
934dbb271fSSean Callanan }
944dbb271fSSean Callanan
954dbb271fSSean Callanan Process *process = exe_ctx.GetProcessPtr();
964dbb271fSSean Callanan
97b9c1b51eSKate Stone if (!process) {
98e2411fabSZachary Turner diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid process");
994dbb271fSSean Callanan return false;
1004dbb271fSSean Callanan }
1014dbb271fSSean Callanan
1024dbb271fSSean Callanan //////////////////////////
1034dbb271fSSean Callanan // Parse the expression
1044dbb271fSSean Callanan //
1054dbb271fSSean Callanan
1064dbb271fSSean Callanan bool keep_result_in_memory = false;
1074dbb271fSSean Callanan
1084dbb271fSSean Callanan ResetDeclMap(exe_ctx, keep_result_in_memory);
1094dbb271fSSean Callanan
110248a1305SKonrad Kleine if (!DeclMap()->WillParse(exe_ctx, nullptr)) {
111e2411fabSZachary Turner diagnostic_manager.PutString(
112b9c1b51eSKate Stone eDiagnosticSeverityError,
113579e70c9SSean Callanan "current process state is unsuitable for expression parsing");
1144dbb271fSSean Callanan return false;
1154dbb271fSSean Callanan }
1164dbb271fSSean Callanan
1174dbb271fSSean Callanan const bool generate_debug_info = true;
118b9c1b51eSKate Stone ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
119b9c1b51eSKate Stone generate_debug_info);
1204dbb271fSSean Callanan
121579e70c9SSean Callanan unsigned num_errors = parser.Parse(diagnostic_manager);
1224dbb271fSSean Callanan
123b9c1b51eSKate Stone if (num_errors) {
1244dbb271fSSean Callanan ResetDeclMap();
1254dbb271fSSean Callanan
1264dbb271fSSean Callanan return false;
1274dbb271fSSean Callanan }
1284dbb271fSSean Callanan
1294dbb271fSSean Callanan //////////////////////////////////
1304dbb271fSSean Callanan // JIT the output of the parser
1314dbb271fSSean Callanan //
1324dbb271fSSean Callanan
1334dbb271fSSean Callanan bool can_interpret = false; // should stay that way
1344dbb271fSSean Callanan
13597206d57SZachary Turner Status jit_error = parser.PrepareForExecution(
136b9c1b51eSKate Stone m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
137b9c1b51eSKate Stone can_interpret, eExecutionPolicyAlways);
1384dbb271fSSean Callanan
139b9c1b51eSKate Stone if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
1404dbb271fSSean Callanan m_jit_process_wp = process->shared_from_this();
141b9c1b51eSKate Stone if (parser.GetGenerateDebugInfo()) {
1424dbb271fSSean Callanan lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());
1434dbb271fSSean Callanan
144b9c1b51eSKate Stone if (jit_module_sp) {
1454dbb271fSSean Callanan ConstString const_func_name(FunctionName());
1464dbb271fSSean Callanan FileSpec jit_file;
147*1b4b12a3SNico Weber jit_file.GetFilename() = const_func_name;
1484dbb271fSSean Callanan jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());
1494dbb271fSSean Callanan m_jit_module_wp = jit_module_sp;
1504dbb271fSSean Callanan target->GetImages().Append(jit_module_sp);
1514dbb271fSSean Callanan }
1524dbb271fSSean Callanan }
1534dbb271fSSean Callanan }
1544dbb271fSSean Callanan
1554dbb271fSSean Callanan DeclMap()->DidParse();
1564dbb271fSSean Callanan
1574dbb271fSSean Callanan ResetDeclMap();
1584dbb271fSSean Callanan
159b9c1b51eSKate Stone if (jit_error.Success()) {
1604dbb271fSSean Callanan return true;
161b9c1b51eSKate Stone } else {
1624dbb271fSSean Callanan const char *error_cstr = jit_error.AsCString();
163b9c1b51eSKate Stone if (error_cstr && error_cstr[0]) {
164579e70c9SSean Callanan diagnostic_manager.Printf(eDiagnosticSeverityError, "%s", error_cstr);
165b9c1b51eSKate Stone } else {
166e2411fabSZachary Turner diagnostic_manager.PutString(eDiagnosticSeverityError,
167b9c1b51eSKate Stone "expression can't be interpreted or run");
168579e70c9SSean Callanan }
1694dbb271fSSean Callanan return false;
1704dbb271fSSean Callanan }
1714dbb271fSSean Callanan }
1724dbb271fSSean Callanan
ResetDeclMap(ExecutionContext & exe_ctx,bool keep_result_in_memory)173b9c1b51eSKate Stone void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(
174b9c1b51eSKate Stone ExecutionContext &exe_ctx, bool keep_result_in_memory) {
1757c9ebdd3SAlex Langford std::shared_ptr<ClangASTImporter> ast_importer;
176c4f6fbe9SAlex Langford auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage(
177c4f6fbe9SAlex Langford lldb::eLanguageTypeC);
178c4f6fbe9SAlex Langford if (state) {
179c4f6fbe9SAlex Langford auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);
180c4f6fbe9SAlex Langford ast_importer = persistent_vars->GetClangASTImporter();
181c4f6fbe9SAlex Langford }
18206412daeSJonas Devlieghere m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>(
18306412daeSJonas Devlieghere keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer,
18406412daeSJonas Devlieghere nullptr);
1854dbb271fSSean Callanan }
186