/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- ClangFunctionCaller.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 "ClangFunctionCaller.h" |
10 | | |
11 | | #include "ASTStructExtractor.h" |
12 | | #include "ClangExpressionParser.h" |
13 | | |
14 | | #include "clang/AST/ASTContext.h" |
15 | | #include "clang/AST/RecordLayout.h" |
16 | | #include "clang/CodeGen/CodeGenAction.h" |
17 | | #include "clang/CodeGen/ModuleBuilder.h" |
18 | | #include "clang/Frontend/CompilerInstance.h" |
19 | | #include "llvm/ADT/StringRef.h" |
20 | | #include "llvm/ExecutionEngine/ExecutionEngine.h" |
21 | | #include "llvm/IR/Module.h" |
22 | | #include "llvm/TargetParser/Triple.h" |
23 | | |
24 | | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
25 | | #include "lldb/Core/Module.h" |
26 | | #include "lldb/Core/ValueObject.h" |
27 | | #include "lldb/Core/ValueObjectList.h" |
28 | | #include "lldb/Expression/IRExecutionUnit.h" |
29 | | #include "lldb/Interpreter/CommandReturnObject.h" |
30 | | #include "lldb/Symbol/Function.h" |
31 | | #include "lldb/Symbol/Type.h" |
32 | | #include "lldb/Target/ExecutionContext.h" |
33 | | #include "lldb/Target/Process.h" |
34 | | #include "lldb/Target/RegisterContext.h" |
35 | | #include "lldb/Target/Target.h" |
36 | | #include "lldb/Target/Thread.h" |
37 | | #include "lldb/Target/ThreadPlan.h" |
38 | | #include "lldb/Target/ThreadPlanCallFunction.h" |
39 | | #include "lldb/Utility/DataExtractor.h" |
40 | | #include "lldb/Utility/LLDBLog.h" |
41 | | #include "lldb/Utility/Log.h" |
42 | | #include "lldb/Utility/State.h" |
43 | | |
44 | | using namespace lldb_private; |
45 | | |
46 | | char ClangFunctionCaller::ID; |
47 | | |
48 | | // ClangFunctionCaller constructor |
49 | | ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope, |
50 | | const CompilerType &return_type, |
51 | | const Address &functionAddress, |
52 | | const ValueList &arg_value_list, |
53 | | const char *name) |
54 | 2.00k | : FunctionCaller(exe_scope, return_type, functionAddress, arg_value_list, |
55 | 2.00k | name), |
56 | 2.00k | m_type_system_helper(*this) { |
57 | 2.00k | m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess()); |
58 | | // Can't make a ClangFunctionCaller without a process. |
59 | 2.00k | assert(m_jit_process_wp.lock()); |
60 | 2.00k | } |
61 | | |
62 | | // Destructor |
63 | 1.97k | ClangFunctionCaller::~ClangFunctionCaller() = default; |
64 | | |
65 | | unsigned |
66 | | |
67 | | ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp, |
68 | 4.13k | DiagnosticManager &diagnostic_manager) { |
69 | 4.13k | if (m_compiled) |
70 | 2.13k | return 0; |
71 | | |
72 | | // Compilation might call code, make sure to keep on the thread the caller |
73 | | // indicated. |
74 | 2.00k | ThreadList::ExpressionExecutionThreadPusher execution_thread_pusher( |
75 | 2.00k | thread_to_use_sp); |
76 | | |
77 | | // FIXME: How does clang tell us there's no return value? We need to handle |
78 | | // that case. |
79 | 2.00k | unsigned num_errors = 0; |
80 | | |
81 | 2.00k | std::string return_type_str( |
82 | 2.00k | m_function_return_type.GetTypeName().AsCString("")); |
83 | | |
84 | | // Cons up the function we're going to wrap our call in, then compile it... |
85 | | // We declare the function "extern "C"" because the compiler might be in C++ |
86 | | // mode which would mangle the name and then we couldn't find it again... |
87 | 2.00k | m_wrapper_function_text.clear(); |
88 | 2.00k | m_wrapper_function_text.append("extern \"C\" void "); |
89 | 2.00k | m_wrapper_function_text.append(m_wrapper_function_name); |
90 | 2.00k | m_wrapper_function_text.append(" (void *input)\n{\n struct "); |
91 | 2.00k | m_wrapper_function_text.append(m_wrapper_struct_name); |
92 | 2.00k | m_wrapper_function_text.append(" \n {\n"); |
93 | 2.00k | m_wrapper_function_text.append(" "); |
94 | 2.00k | m_wrapper_function_text.append(return_type_str); |
95 | 2.00k | m_wrapper_function_text.append(" (*fn_ptr) ("); |
96 | | |
97 | | // Get the number of arguments. If we have a function type and it is |
98 | | // prototyped, trust that, otherwise use the values we were given. |
99 | | |
100 | | // FIXME: This will need to be extended to handle Variadic functions. We'll |
101 | | // need |
102 | | // to pull the defined arguments out of the function, then add the types from |
103 | | // the arguments list for the variable arguments. |
104 | | |
105 | 2.00k | uint32_t num_args = UINT32_MAX; |
106 | 2.00k | bool trust_function = false; |
107 | | // GetArgumentCount returns -1 for an unprototyped function. |
108 | 2.00k | CompilerType function_clang_type; |
109 | 2.00k | if (m_function_ptr) { |
110 | 0 | function_clang_type = m_function_ptr->GetCompilerType(); |
111 | 0 | if (function_clang_type) { |
112 | 0 | int num_func_args = function_clang_type.GetFunctionArgumentCount(); |
113 | 0 | if (num_func_args >= 0) { |
114 | 0 | trust_function = true; |
115 | 0 | num_args = num_func_args; |
116 | 0 | } |
117 | 0 | } |
118 | 0 | } |
119 | | |
120 | 2.00k | if (num_args == UINT32_MAX) |
121 | 2.00k | num_args = m_arg_values.GetSize(); |
122 | | |
123 | 2.00k | std::string args_buffer; // This one stores the definition of all the args in |
124 | | // "struct caller". |
125 | 2.00k | std::string args_list_buffer; // This one stores the argument list called from |
126 | | // the structure. |
127 | 11.6k | for (size_t i = 0; i < num_args; i++9.68k ) { |
128 | 9.68k | std::string type_name; |
129 | | |
130 | 9.68k | if (trust_function) { |
131 | 0 | type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i) |
132 | 0 | .GetTypeName() |
133 | 0 | .AsCString(""); |
134 | 9.68k | } else { |
135 | 9.68k | CompilerType clang_qual_type = |
136 | 9.68k | m_arg_values.GetValueAtIndex(i)->GetCompilerType(); |
137 | 9.68k | if (clang_qual_type) { |
138 | 9.68k | type_name = clang_qual_type.GetTypeName().AsCString(""); |
139 | 9.68k | } else { |
140 | 0 | diagnostic_manager.Printf( |
141 | 0 | eDiagnosticSeverityError, |
142 | 0 | "Could not determine type of input value %" PRIu64 ".", |
143 | 0 | (uint64_t)i); |
144 | 0 | return 1; |
145 | 0 | } |
146 | 9.68k | } |
147 | | |
148 | 9.68k | m_wrapper_function_text.append(type_name); |
149 | 9.68k | if (i < num_args - 1) |
150 | 7.70k | m_wrapper_function_text.append(", "); |
151 | | |
152 | 9.68k | char arg_buf[32]; |
153 | 9.68k | args_buffer.append(" "); |
154 | 9.68k | args_buffer.append(type_name); |
155 | 9.68k | snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i); |
156 | 9.68k | args_buffer.push_back(' '); |
157 | 9.68k | args_buffer.append(arg_buf); |
158 | 9.68k | args_buffer.append(";\n"); |
159 | | |
160 | 9.68k | args_list_buffer.append("__lldb_fn_data->"); |
161 | 9.68k | args_list_buffer.append(arg_buf); |
162 | 9.68k | if (i < num_args - 1) |
163 | 7.70k | args_list_buffer.append(", "); |
164 | 9.68k | } |
165 | 2.00k | m_wrapper_function_text.append( |
166 | 2.00k | ");\n"); // Close off the function calling prototype. |
167 | | |
168 | 2.00k | m_wrapper_function_text.append(args_buffer); |
169 | | |
170 | 2.00k | m_wrapper_function_text.append(" "); |
171 | 2.00k | m_wrapper_function_text.append(return_type_str); |
172 | 2.00k | m_wrapper_function_text.append(" return_value;"); |
173 | 2.00k | m_wrapper_function_text.append("\n };\n struct "); |
174 | 2.00k | m_wrapper_function_text.append(m_wrapper_struct_name); |
175 | 2.00k | m_wrapper_function_text.append("* __lldb_fn_data = (struct "); |
176 | 2.00k | m_wrapper_function_text.append(m_wrapper_struct_name); |
177 | 2.00k | m_wrapper_function_text.append(" *) input;\n"); |
178 | | |
179 | 2.00k | m_wrapper_function_text.append( |
180 | 2.00k | " __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); |
181 | 2.00k | m_wrapper_function_text.append(args_list_buffer); |
182 | 2.00k | m_wrapper_function_text.append(");\n}\n"); |
183 | | |
184 | 2.00k | Log *log = GetLog(LLDBLog::Expressions); |
185 | 2.00k | LLDB_LOGF(log, "Expression: \n\n%s\n\n", m_wrapper_function_text.c_str()); |
186 | | |
187 | | // Okay, now compile this expression |
188 | | |
189 | 2.00k | lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); |
190 | 2.00k | if (jit_process_sp) { |
191 | 2.00k | const bool generate_debug_info = true; |
192 | 2.00k | auto *clang_parser = new ClangExpressionParser(jit_process_sp.get(), *this, |
193 | 2.00k | generate_debug_info); |
194 | 2.00k | num_errors = clang_parser->Parse(diagnostic_manager); |
195 | 2.00k | m_parser.reset(clang_parser); |
196 | 2.00k | } else { |
197 | 0 | diagnostic_manager.PutString(eDiagnosticSeverityError, |
198 | 0 | "no process - unable to inject function"); |
199 | 0 | num_errors = 1; |
200 | 0 | } |
201 | | |
202 | 2.00k | m_compiled = (num_errors == 0); |
203 | | |
204 | 2.00k | if (!m_compiled) |
205 | 0 | return num_errors; |
206 | | |
207 | 2.00k | return num_errors; |
208 | 2.00k | } |
209 | | |
210 | | char ClangFunctionCaller::ClangFunctionCallerHelper::ID; |
211 | | |
212 | | clang::ASTConsumer * |
213 | | ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer( |
214 | 2.00k | clang::ASTConsumer *passthrough) { |
215 | 2.00k | m_struct_extractor = std::make_unique<ASTStructExtractor>( |
216 | 2.00k | passthrough, m_owner.GetWrapperStructName(), m_owner); |
217 | | |
218 | 2.00k | return m_struct_extractor.get(); |
219 | 2.00k | } |