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 "lldb/Host/Config.h"
10
11 #include "ClangUtilityFunction.h"
12 #include "ClangExpressionDeclMap.h"
13 #include "ClangExpressionParser.h"
14 #include "ClangExpressionSourceCode.h"
15 #include "ClangPersistentVariables.h"
16
17 #include <stdio.h>
18 #if HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #endif
21
22
23 #include "lldb/Core/Module.h"
24 #include "lldb/Core/StreamFile.h"
25 #include "lldb/Expression/IRExecutionUnit.h"
26 #include "lldb/Host/Host.h"
27 #include "lldb/Target/ExecutionContext.h"
28 #include "lldb/Target/Target.h"
29 #include "lldb/Utility/ConstString.h"
30 #include "lldb/Utility/Log.h"
31 #include "lldb/Utility/Stream.h"
32
33 using namespace lldb_private;
34
35 char ClangUtilityFunction::ID;
36
37 /// Constructor
38 ///
39 /// \param[in] text
40 /// The text of the function. Must be a full translation unit.
41 ///
42 /// \param[in] name
43 /// The name of the function, as used in the text.
ClangUtilityFunction(ExecutionContextScope & exe_scope,std::string text,std::string name)44 ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope,
45 std::string text, std::string name)
46 : UtilityFunction(
47 exe_scope,
48 std::string(ClangExpressionSourceCode::g_expression_prefix) + text,
49 std::move(name)) {}
50
~ClangUtilityFunction()51 ClangUtilityFunction::~ClangUtilityFunction() {}
52
53 /// Install the utility function into a process
54 ///
55 /// \param[in] diagnostic_manager
56 /// A diagnostic manager to report errors and warnings to.
57 ///
58 /// \param[in] exe_ctx
59 /// The execution context to install the utility function to.
60 ///
61 /// \return
62 /// True on success (no errors); false otherwise.
Install(DiagnosticManager & diagnostic_manager,ExecutionContext & exe_ctx)63 bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager,
64 ExecutionContext &exe_ctx) {
65 if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
66 diagnostic_manager.PutString(eDiagnosticSeverityWarning,
67 "already installed");
68 return false;
69 }
70
71 ////////////////////////////////////
72 // Set up the target and compiler
73 //
74
75 Target *target = exe_ctx.GetTargetPtr();
76
77 if (!target) {
78 diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target");
79 return false;
80 }
81
82 Process *process = exe_ctx.GetProcessPtr();
83
84 if (!process) {
85 diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid process");
86 return false;
87 }
88
89 //////////////////////////
90 // Parse the expression
91 //
92
93 bool keep_result_in_memory = false;
94
95 ResetDeclMap(exe_ctx, keep_result_in_memory);
96
97 if (!DeclMap()->WillParse(exe_ctx, nullptr)) {
98 diagnostic_manager.PutString(
99 eDiagnosticSeverityError,
100 "current process state is unsuitable for expression parsing");
101 return false;
102 }
103
104 const bool generate_debug_info = true;
105 ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this,
106 generate_debug_info);
107
108 unsigned num_errors = parser.Parse(diagnostic_manager);
109
110 if (num_errors) {
111 ResetDeclMap();
112
113 return false;
114 }
115
116 //////////////////////////////////
117 // JIT the output of the parser
118 //
119
120 bool can_interpret = false; // should stay that way
121
122 Status jit_error = parser.PrepareForExecution(
123 m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx,
124 can_interpret, eExecutionPolicyAlways);
125
126 if (m_jit_start_addr != LLDB_INVALID_ADDRESS) {
127 m_jit_process_wp = process->shared_from_this();
128 if (parser.GetGenerateDebugInfo()) {
129 lldb::ModuleSP jit_module_sp(m_execution_unit_sp->GetJITModule());
130
131 if (jit_module_sp) {
132 ConstString const_func_name(FunctionName());
133 FileSpec jit_file;
134 jit_file.GetFilename() = const_func_name;
135 jit_module_sp->SetFileSpecAndObjectName(jit_file, ConstString());
136 m_jit_module_wp = jit_module_sp;
137 target->GetImages().Append(jit_module_sp);
138 }
139 }
140 }
141
142 DeclMap()->DidParse();
143
144 ResetDeclMap();
145
146 if (jit_error.Success()) {
147 return true;
148 } else {
149 const char *error_cstr = jit_error.AsCString();
150 if (error_cstr && error_cstr[0]) {
151 diagnostic_manager.Printf(eDiagnosticSeverityError, "%s", error_cstr);
152 } else {
153 diagnostic_manager.PutString(eDiagnosticSeverityError,
154 "expression can't be interpreted or run");
155 }
156 return false;
157 }
158 }
159
ResetDeclMap(ExecutionContext & exe_ctx,bool keep_result_in_memory)160 void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(
161 ExecutionContext &exe_ctx, bool keep_result_in_memory) {
162 std::shared_ptr<ClangASTImporter> ast_importer;
163 auto *state = exe_ctx.GetTargetSP()->GetPersistentExpressionStateForLanguage(
164 lldb::eLanguageTypeC);
165 if (state) {
166 auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);
167 ast_importer = persistent_vars->GetClangASTImporter();
168 }
169 m_expr_decl_map_up = std::make_unique<ClangExpressionDeclMap>(
170 keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(), ast_importer,
171 nullptr);
172 }
173