1dda28197Spatrick //===-- ClangUtilityFunction.cpp ------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "ClangUtilityFunction.h"
10061da546Spatrick #include "ClangExpressionDeclMap.h"
11061da546Spatrick #include "ClangExpressionParser.h"
12061da546Spatrick #include "ClangExpressionSourceCode.h"
13dda28197Spatrick #include "ClangPersistentVariables.h"
14061da546Spatrick
15be691f3bSpatrick #include <cstdio>
16061da546Spatrick #include <sys/types.h>
17061da546Spatrick
18061da546Spatrick
19061da546Spatrick #include "lldb/Core/Module.h"
20061da546Spatrick #include "lldb/Core/StreamFile.h"
21061da546Spatrick #include "lldb/Expression/IRExecutionUnit.h"
22061da546Spatrick #include "lldb/Host/Host.h"
23061da546Spatrick #include "lldb/Target/ExecutionContext.h"
24061da546Spatrick #include "lldb/Target/Target.h"
25061da546Spatrick #include "lldb/Utility/ConstString.h"
26061da546Spatrick #include "lldb/Utility/Log.h"
27061da546Spatrick #include "lldb/Utility/Stream.h"
28061da546Spatrick
29061da546Spatrick using namespace lldb_private;
30061da546Spatrick
31061da546Spatrick char ClangUtilityFunction::ID;
32061da546Spatrick
ClangUtilityFunction(ExecutionContextScope & exe_scope,std::string text,std::string name,bool enable_debugging)33061da546Spatrick ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope,
34be691f3bSpatrick std::string text, std::string name,
35be691f3bSpatrick bool enable_debugging)
36be691f3bSpatrick : UtilityFunction(
37be691f3bSpatrick exe_scope,
38be691f3bSpatrick std::string(ClangExpressionSourceCode::g_expression_prefix) + text +
39be691f3bSpatrick std::string(ClangExpressionSourceCode::g_expression_suffix),
40be691f3bSpatrick std::move(name), enable_debugging) {
41be691f3bSpatrick // Write the source code to a file so that LLDB's source manager can display
42be691f3bSpatrick // it when debugging the code.
43be691f3bSpatrick if (enable_debugging) {
44be691f3bSpatrick int temp_fd = -1;
45be691f3bSpatrick llvm::SmallString<128> result_path;
46be691f3bSpatrick llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path);
47be691f3bSpatrick if (temp_fd != -1) {
48*f6aab3d8Srobert lldb_private::NativeFile file(temp_fd, File::eOpenOptionWriteOnly, true);
49be691f3bSpatrick text = "#line 1 \"" + std::string(result_path) + "\"\n" + text;
50be691f3bSpatrick size_t bytes_written = text.size();
51be691f3bSpatrick file.Write(text.c_str(), bytes_written);
52be691f3bSpatrick if (bytes_written == text.size()) {
53be691f3bSpatrick // If we successfully wrote the source to a temporary file, replace the
54be691f3bSpatrick // function text with the next text containing the line directive.
55be691f3bSpatrick m_function_text =
56be691f3bSpatrick std::string(ClangExpressionSourceCode::g_expression_prefix) + text +
57be691f3bSpatrick std::string(ClangExpressionSourceCode::g_expression_suffix);
58be691f3bSpatrick }
59be691f3bSpatrick file.Close();
60be691f3bSpatrick }
61be691f3bSpatrick }
62061da546Spatrick }
63061da546Spatrick
64be691f3bSpatrick ClangUtilityFunction::~ClangUtilityFunction() = default;
65061da546Spatrick
66061da546Spatrick /// Install the utility function into a process
67061da546Spatrick ///
68061da546Spatrick /// \param[in] diagnostic_manager
69061da546Spatrick /// A diagnostic manager to report errors and warnings to.
70061da546Spatrick ///
71061da546Spatrick /// \param[in] exe_ctx
72061da546Spatrick /// The execution context to install the utility function to.
73061da546Spatrick ///
74061da546Spatrick /// \return
75061da546Spatrick /// True on success (no errors); false otherwise.
Install(DiagnosticManager & diagnostic_manager,ExecutionContext & exe_ctx)76061da546Spatrick bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,
77061da546Spatrick ExecutionContext &exe_ctx) {
78061da546Spatrick if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
79061da546Spatrick diagnostic_manager.PutString(eDiagnosticSeverityWarning,
80061da546Spatrick "already installed");
81061da546Spatrick return false;
82061da546Spatrick }
83061da546Spatrick
84061da546Spatrick ////////////////////////////////////
85061da546Spatrick // Set up the target and compiler
86061da546Spatrick //
87061da546Spatrick
88061da546Spatrick Target *target = exe_ctx.GetTargetPtr();
89061da546Spatrick
90061da546Spatrick if (!target) {
91061da546Spatrick diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target");
92061da546Spatrick return false;
93061da546Spatrick }
94061da546Spatrick
95061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
96061da546Spatrick
97061da546Spatrick if (!process) {
98061da546Spatrick diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid process");
99061da546Spatrick return false;
100061da546Spatrick }
101061da546Spatrick
102*f6aab3d8Srobert // Since we might need to call allocate memory and maybe call code to make
103*f6aab3d8Srobert // the caller, we need to be stopped.
104*f6aab3d8Srobert if (process->GetState() != lldb::eStateStopped) {
105*f6aab3d8Srobert diagnostic_manager.PutString(eDiagnosticSeverityError, "process running");
106*f6aab3d8Srobert return false;
107*f6aab3d8Srobert }
108061da546Spatrick //////////////////////////
109061da546Spatrick // Parse the expression
110061da546Spatrick //
111061da546Spatrick
112061da546Spatrick bool keep_result_in_memory = false;
113061da546Spatrick
114061da546Spatrick ResetDeclMap(exe_ctx, keep_result_in_memory);
115061da546Spatrick
116061da546Spatrick if (!DeclMap()->WillParse(exe_ctx, nullptr)) {
117061da546Spatrick diagnostic_manager.PutString(
118061da546Spatrick eDiagnosticSeverityError,
119061da546Spatrick "current process state is unsuitable for expression parsing");
120061da546Spatrick return false;
121061da546Spatrick }
122061da546Spatrick
123061da546Spatrick const bool generate_debug_info = true;
124061da546Spatrick ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
125061da546Spatrick generate_debug_info);
126061da546Spatrick
127061da546Spatrick unsigned num_errors = parser.Parse(diagnostic_manager);
128061da546Spatrick
129061da546Spatrick if (num_errors) {
130061da546Spatrick ResetDeclMap();
131061da546Spatrick
132061da546Spatrick return false;
133061da546Spatrick }
134061da546Spatrick
135061da546Spatrick //////////////////////////////////
136061da546Spatrick // JIT the output of the parser
137061da546Spatrick //
138061da546Spatrick
139061da546Spatrick bool can_interpret = false; // should stay that way
140061da546Spatrick
141061da546Spatrick Status jit_error = parser.PrepareForExecution(
142061da546Spatrick m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
143061da546Spatrick can_interpret, eExecutionPolicyAlways);
144061da546Spatrick
145061da546Spatrick if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
146061da546Spatrick m_jit_process_wp = process->shared_from_this();
147061da546Spatrick if (parser.GetGenerateDebugInfo()) {
148061da546Spatrick lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());
149061da546Spatrick
150061da546Spatrick if (jit_module_sp) {
151061da546Spatrick ConstString const_func_name(FunctionName());
152061da546Spatrick FileSpec jit_file;
153*f6aab3d8Srobert jit_file.SetFilename(const_func_name);
154061da546Spatrick jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());
155061da546Spatrick m_jit_module_wp = jit_module_sp;
156061da546Spatrick target->GetImages().Append(jit_module_sp);
157061da546Spatrick }
158061da546Spatrick }
159061da546Spatrick }
160061da546Spatrick
161061da546Spatrick DeclMap()->DidParse();
162061da546Spatrick
163061da546Spatrick ResetDeclMap();
164061da546Spatrick
165061da546Spatrick if (jit_error.Success()) {
166061da546Spatrick return true;
167061da546Spatrick } else {
168061da546Spatrick const char *error_cstr = jit_error.AsCString();
169061da546Spatrick if (error_cstr && error_cstr[0]) {
170061da546Spatrick diagnostic_manager.Printf(eDiagnosticSeverityError, "%s", error_cstr);
171061da546Spatrick } else {
172061da546Spatrick diagnostic_manager.PutString(eDiagnosticSeverityError,
173061da546Spatrick "expression can't be interpreted or run");
174061da546Spatrick }
175061da546Spatrick return false;
176061da546Spatrick }
177061da546Spatrick }
178061da546Spatrick
ResetDeclMap(ExecutionContext & exe_ctx,bool keep_result_in_memory)179061da546Spatrick void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(
180061da546Spatrick ExecutionContext &exe_ctx, bool keep_result_in_memory) {
181dda28197Spatrick std::shared_ptr<ClangASTImporter> ast_importer;
182dda28197Spatrick auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage(
183dda28197Spatrick lldb::eLanguageTypeC);
184dda28197Spatrick if (state) {
185dda28197Spatrick auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);
186dda28197Spatrick ast_importer = persistent_vars->GetClangASTImporter();
187dda28197Spatrick }
188dda28197Spatrick m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>(
189dda28197Spatrick keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer,
190dda28197Spatrick nullptr);
191061da546Spatrick }
192