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
32using namespace lldb_private;
33
34char ClangUtilityFunction::ID;
35
36/// Constructor
37///
38/// \param[in] text
39///     The text of the function.  Must be a full translation unit.
40///
41/// \param[in] name
42///     The name of the function, as used in the text.
43ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope,
44                                           const char *text, const char *name)
45    : UtilityFunction(exe_scope, text, name) {
46  m_function_text.assign(ClangExpressionSourceCode::g_expression_prefix);
47  if (text && text[0])
48    m_function_text.append(text);
49}
50
51ClangUtilityFunction::~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.
63bool 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
160void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(
161    ExecutionContext &exe_ctx, bool keep_result_in_memory) {
162  m_expr_decl_map_up.reset(new ClangExpressionDeclMap(
163      keep_result_in_memory, nullptr, exe_ctx.GetTargetSP(),
164      exe_ctx.GetTargetRef().GetClangASTImporter(), nullptr));
165}
166