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