1 | //===-- UtilityFunction.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 <cstdio> |
10 | #include <sys/types.h> |
11 | |
12 | #include "lldb/Core/Module.h" |
13 | #include "lldb/Expression/DiagnosticManager.h" |
14 | #include "lldb/Expression/FunctionCaller.h" |
15 | #include "lldb/Expression/IRExecutionUnit.h" |
16 | #include "lldb/Expression/UtilityFunction.h" |
17 | #include "lldb/Host/Host.h" |
18 | #include "lldb/Target/ExecutionContext.h" |
19 | #include "lldb/Target/Process.h" |
20 | #include "lldb/Target/Target.h" |
21 | #include "lldb/Utility/ConstString.h" |
22 | #include "lldb/Utility/Log.h" |
23 | #include "lldb/Utility/State.h" |
24 | #include "lldb/Utility/Stream.h" |
25 | |
26 | using namespace lldb_private; |
27 | using namespace lldb; |
28 | |
29 | char UtilityFunction::ID; |
30 | |
31 | /// Constructor |
32 | /// |
33 | /// \param[in] text |
34 | /// The text of the function. Must be a full translation unit. |
35 | /// |
36 | /// \param[in] name |
37 | /// The name of the function, as used in the text. |
38 | UtilityFunction::UtilityFunction(ExecutionContextScope &exe_scope, |
39 | std::string text, std::string name, |
40 | bool enable_debugging) |
41 | : Expression(exe_scope), m_execution_unit_sp(), m_jit_module_wp(), |
42 | m_function_text(std::move(text)), m_function_name(std::move(name)) {} |
43 | |
44 | UtilityFunction::~UtilityFunction() { |
45 | lldb::ProcessSP process_sp(m_jit_process_wp.lock()); |
46 | if (process_sp) { |
47 | lldb::ModuleSP jit_module_sp(m_jit_module_wp.lock()); |
48 | if (jit_module_sp) |
49 | process_sp->GetTarget().GetImages().Remove(module_sp: jit_module_sp); |
50 | } |
51 | } |
52 | |
53 | // FIXME: We should check that every time this is called it is called with the |
54 | // same return type & arguments... |
55 | |
56 | FunctionCaller *UtilityFunction::MakeFunctionCaller( |
57 | const CompilerType &return_type, const ValueList &arg_value_list, |
58 | lldb::ThreadSP thread_to_use_sp, Status &error) { |
59 | if (m_caller_up) |
60 | return m_caller_up.get(); |
61 | |
62 | ProcessSP process_sp = m_jit_process_wp.lock(); |
63 | if (!process_sp) { |
64 | error.SetErrorString("Can't make a function caller without a process." ); |
65 | return nullptr; |
66 | } |
67 | // Since we might need to allocate memory and maybe call code to make |
68 | // the caller, we need to be stopped. |
69 | if (process_sp->GetState() != lldb::eStateStopped) { |
70 | error.SetErrorStringWithFormatv( |
71 | format: "Can't make a function caller while the process is {0}: the process " |
72 | "must be stopped to allocate memory." , |
73 | args: StateAsCString(state: process_sp->GetState())); |
74 | return nullptr; |
75 | } |
76 | |
77 | Address impl_code_address; |
78 | impl_code_address.SetOffset(StartAddress()); |
79 | std::string name(m_function_name); |
80 | name.append(s: "-caller" ); |
81 | |
82 | m_caller_up.reset(p: process_sp->GetTarget().GetFunctionCallerForLanguage( |
83 | language: Language(), return_type, function_address: impl_code_address, arg_value_list, name: name.c_str(), |
84 | error)); |
85 | if (error.Fail()) { |
86 | |
87 | return nullptr; |
88 | } |
89 | if (m_caller_up) { |
90 | DiagnosticManager diagnostics; |
91 | |
92 | unsigned num_errors = |
93 | m_caller_up->CompileFunction(thread_to_use_sp, diagnostic_manager&: diagnostics); |
94 | if (num_errors) { |
95 | error.SetErrorStringWithFormat( |
96 | "Error compiling %s caller function: \"%s\"." , |
97 | m_function_name.c_str(), diagnostics.GetString().c_str()); |
98 | m_caller_up.reset(); |
99 | return nullptr; |
100 | } |
101 | |
102 | diagnostics.Clear(); |
103 | ExecutionContext exe_ctx(process_sp); |
104 | |
105 | if (!m_caller_up->WriteFunctionWrapper(exe_ctx, diagnostic_manager&: diagnostics)) { |
106 | error.SetErrorStringWithFormat( |
107 | "Error inserting caller function for %s: \"%s\"." , |
108 | m_function_name.c_str(), diagnostics.GetString().c_str()); |
109 | m_caller_up.reset(); |
110 | return nullptr; |
111 | } |
112 | } |
113 | return m_caller_up.get(); |
114 | } |
115 | |