xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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