xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1  //===-- ClangUtilityFunction.cpp ------------------------------------------===//
2  //
3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4  // See https://llvm.org/LICENSE.txt for license information.
5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6  //
7  //===----------------------------------------------------------------------===//
8  
9  #include "ClangUtilityFunction.h"
10  #include "ClangExpressionDeclMap.h"
11  #include "ClangExpressionParser.h"
12  #include "ClangExpressionSourceCode.h"
13  #include "ClangPersistentVariables.h"
14  
15  #include <cstdio>
16  #include <sys/types.h>
17  
18  
19  #include "lldb/Core/Module.h"
20  #include "lldb/Expression/IRExecutionUnit.h"
21  #include "lldb/Host/Host.h"
22  #include "lldb/Target/ExecutionContext.h"
23  #include "lldb/Target/Target.h"
24  #include "lldb/Utility/ConstString.h"
25  #include "lldb/Utility/Log.h"
26  #include "lldb/Utility/Stream.h"
27  
28  using namespace lldb_private;
29  
30  char ClangUtilityFunction::ID;
31  
ClangUtilityFunction(ExecutionContextScope & exe_scope,std::string text,std::string name,bool enable_debugging)32  ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope,
33                                             std::string text, std::string name,
34                                             bool enable_debugging)
35      : UtilityFunction(
36            exe_scope,
37            std::string(ClangExpressionSourceCode::g_expression_prefix) + text +
38                std::string(ClangExpressionSourceCode::g_expression_suffix),
39            std::move(name), enable_debugging) {
40    // Write the source code to a file so that LLDB's source manager can display
41    // it when debugging the code.
42    if (enable_debugging) {
43      int temp_fd = -1;
44      llvm::SmallString<128> result_path;
45      llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path);
46      if (temp_fd != -1) {
47        lldb_private::NativeFile file(temp_fd, File::eOpenOptionWriteOnly, true);
48        text = "#line 1 \"" + std::string(result_path) + "\"\n" + text;
49        size_t bytes_written = text.size();
50        file.Write(text.c_str(), bytes_written);
51        if (bytes_written == text.size()) {
52          // If we successfully wrote the source to a temporary file, replace the
53          // function text with the next text containing the line directive.
54          m_function_text =
55              std::string(ClangExpressionSourceCode::g_expression_prefix) + text +
56              std::string(ClangExpressionSourceCode::g_expression_suffix);
57        }
58        file.Close();
59      }
60    }
61  }
62  
63  ClangUtilityFunction::~ClangUtilityFunction() = default;
64  
65  /// Install the utility function into a process
66  ///
67  /// \param[in] diagnostic_manager
68  ///     A diagnostic manager to report errors and warnings to.
69  ///
70  /// \param[in] exe_ctx
71  ///     The execution context to install the utility function to.
72  ///
73  /// \return
74  ///     True on success (no errors); false otherwise.
Install(DiagnosticManager & diagnostic_manager,ExecutionContext & exe_ctx)75  bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,
76                                     ExecutionContext &exe_ctx) {
77    if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
78      diagnostic_manager.PutString(lldb::eSeverityWarning, "already installed");
79      return false;
80    }
81  
82    ////////////////////////////////////
83    // Set up the target and compiler
84    //
85  
86    Target *target = exe_ctx.GetTargetPtr();
87  
88    if (!target) {
89      diagnostic_manager.PutString(lldb::eSeverityError, "invalid target");
90      return false;
91    }
92  
93    Process *process = exe_ctx.GetProcessPtr();
94  
95    if (!process) {
96      diagnostic_manager.PutString(lldb::eSeverityError, "invalid process");
97      return false;
98    }
99  
100    // Since we might need to call allocate memory and maybe call code to make
101    // the caller, we need to be stopped.
102    if (process->GetState() != lldb::eStateStopped) {
103      diagnostic_manager.PutString(lldb::eSeverityError, "process running");
104      return false;
105    }
106    //////////////////////////
107    // Parse the expression
108    //
109  
110    bool keep_result_in_memory = false;
111  
112    ResetDeclMap(exe_ctx, keep_result_in_memory);
113  
114    if (!DeclMap()->WillParse(exe_ctx, nullptr)) {
115      diagnostic_manager.PutString(
116          lldb::eSeverityError,
117          "current process state is unsuitable for expression parsing");
118      return false;
119    }
120  
121    const bool generate_debug_info = true;
122    ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
123                                 generate_debug_info);
124  
125    unsigned num_errors = parser.Parse(diagnostic_manager);
126  
127    if (num_errors) {
128      ResetDeclMap();
129  
130      return false;
131    }
132  
133    //////////////////////////////////
134    // JIT the output of the parser
135    //
136  
137    bool can_interpret = false; // should stay that way
138  
139    Status jit_error = parser.PrepareForExecution(
140        m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
141        can_interpret, eExecutionPolicyAlways);
142  
143    if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
144      m_jit_process_wp = process->shared_from_this();
145      if (parser.GetGenerateDebugInfo()) {
146        lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());
147  
148        if (jit_module_sp) {
149          ConstString const_func_name(FunctionName());
150          FileSpec jit_file;
151          jit_file.SetFilename(const_func_name);
152          jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());
153          m_jit_module_wp = jit_module_sp;
154          target->GetImages().Append(jit_module_sp);
155        }
156      }
157    }
158  
159    DeclMap()->DidParse();
160  
161    ResetDeclMap();
162  
163    if (jit_error.Success()) {
164      return true;
165    } else {
166      const char *error_cstr = jit_error.AsCString();
167      if (error_cstr && error_cstr[0]) {
168        diagnostic_manager.Printf(lldb::eSeverityError, "%s", error_cstr);
169      } else {
170        diagnostic_manager.PutString(lldb::eSeverityError,
171                                     "expression can't be interpreted or run");
172      }
173      return false;
174    }
175  }
176  
177  char ClangUtilityFunction::ClangUtilityFunctionHelper::ID;
178  
ResetDeclMap(ExecutionContext & exe_ctx,bool keep_result_in_memory)179  void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(
180      ExecutionContext &exe_ctx, bool keep_result_in_memory) {
181    std::shared_ptr<ClangASTImporter> ast_importer;
182    auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage(
183        lldb::eLanguageTypeC);
184    if (state) {
185      auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);
186      ast_importer = persistent_vars->GetClangASTImporter();
187    }
188    m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>(
189        keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer,
190        nullptr);
191  }
192