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