220 lines · cpp
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-exception6//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/Expression/IRExecutionUnit.h"27#include "lldb/Interpreter/CommandReturnObject.h"28#include "lldb/Symbol/Function.h"29#include "lldb/Symbol/Type.h"30#include "lldb/Target/ExecutionContext.h"31#include "lldb/Target/Process.h"32#include "lldb/Target/RegisterContext.h"33#include "lldb/Target/Target.h"34#include "lldb/Target/Thread.h"35#include "lldb/Target/ThreadPlan.h"36#include "lldb/Target/ThreadPlanCallFunction.h"37#include "lldb/Utility/DataExtractor.h"38#include "lldb/Utility/LLDBLog.h"39#include "lldb/Utility/Log.h"40#include "lldb/Utility/State.h"41#include "lldb/ValueObject/ValueObject.h"42#include "lldb/ValueObject/ValueObjectList.h"43 44using namespace lldb_private;45 46char ClangFunctionCaller::ID;47 48// ClangFunctionCaller constructor49ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope,50 const CompilerType &return_type,51 const Address &functionAddress,52 const ValueList &arg_value_list,53 const char *name)54 : FunctionCaller(exe_scope, return_type, functionAddress, arg_value_list,55 name),56 m_type_system_helper(*this) {57 m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess());58 // Can't make a ClangFunctionCaller without a process.59 assert(m_jit_process_wp.lock());60}61 62// Destructor63ClangFunctionCaller::~ClangFunctionCaller() = default;64 65unsigned66 67ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp,68 DiagnosticManager &diagnostic_manager) {69 if (m_compiled)70 return 0;71 72 // Compilation might call code, make sure to keep on the thread the caller73 // indicated.74 ThreadList::ExpressionExecutionThreadPusher execution_thread_pusher(75 thread_to_use_sp);76 77 // FIXME: How does clang tell us there's no return value? We need to handle78 // that case.79 unsigned num_errors = 0;80 81 std::string return_type_str(82 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 m_wrapper_function_text.clear();88 m_wrapper_function_text.append("extern \"C\" void ");89 m_wrapper_function_text.append(m_wrapper_function_name);90 m_wrapper_function_text.append(" (void *input)\n{\n struct ");91 m_wrapper_function_text.append(m_wrapper_struct_name);92 m_wrapper_function_text.append(" \n {\n");93 m_wrapper_function_text.append(" ");94 m_wrapper_function_text.append(return_type_str);95 m_wrapper_function_text.append(" (*fn_ptr) (");96 97 // Get the number of arguments. If we have a function type and it is98 // prototyped, trust that, otherwise use the values we were given.99 100 // FIXME: This will need to be extended to handle Variadic functions. We'll101 // need102 // to pull the defined arguments out of the function, then add the types from103 // the arguments list for the variable arguments.104 105 uint32_t num_args = UINT32_MAX;106 bool trust_function = false;107 // GetArgumentCount returns -1 for an unprototyped function.108 CompilerType function_clang_type;109 if (m_function_ptr) {110 function_clang_type = m_function_ptr->GetCompilerType();111 if (function_clang_type) {112 int num_func_args = function_clang_type.GetFunctionArgumentCount();113 if (num_func_args >= 0) {114 trust_function = true;115 num_args = num_func_args;116 }117 }118 }119 120 if (num_args == UINT32_MAX)121 num_args = m_arg_values.GetSize();122 123 std::string args_buffer; // This one stores the definition of all the args in124 // "struct caller".125 std::string args_list_buffer; // This one stores the argument list called from126 // the structure.127 for (size_t i = 0; i < num_args; i++) {128 std::string type_name;129 130 if (trust_function) {131 type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i)132 .GetTypeName()133 .AsCString("");134 } else {135 CompilerType clang_qual_type =136 m_arg_values.GetValueAtIndex(i)->GetCompilerType();137 if (clang_qual_type) {138 type_name = clang_qual_type.GetTypeName().AsCString("");139 } else {140 diagnostic_manager.Printf(141 lldb::eSeverityError,142 "Could not determine type of input value %" PRIu64 ".",143 (uint64_t)i);144 return 1;145 }146 }147 148 m_wrapper_function_text.append(type_name);149 if (i < num_args - 1)150 m_wrapper_function_text.append(", ");151 152 char arg_buf[32];153 args_buffer.append(" ");154 args_buffer.append(type_name);155 snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i);156 args_buffer.push_back(' ');157 args_buffer.append(arg_buf);158 args_buffer.append(";\n");159 160 args_list_buffer.append("__lldb_fn_data->");161 args_list_buffer.append(arg_buf);162 if (i < num_args - 1)163 args_list_buffer.append(", ");164 }165 m_wrapper_function_text.append(166 ");\n"); // Close off the function calling prototype.167 168 m_wrapper_function_text.append(args_buffer);169 170 m_wrapper_function_text.append(" ");171 m_wrapper_function_text.append(return_type_str);172 m_wrapper_function_text.append(" return_value;");173 m_wrapper_function_text.append("\n };\n struct ");174 m_wrapper_function_text.append(m_wrapper_struct_name);175 m_wrapper_function_text.append("* __lldb_fn_data = (struct ");176 m_wrapper_function_text.append(m_wrapper_struct_name);177 m_wrapper_function_text.append(" *) input;\n");178 179 m_wrapper_function_text.append(180 " __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr (");181 m_wrapper_function_text.append(args_list_buffer);182 m_wrapper_function_text.append(");\n}\n");183 184 Log *log = GetLog(LLDBLog::Expressions);185 LLDB_LOGF(log, "Expression: \n\n%s\n\n", m_wrapper_function_text.c_str());186 187 // Okay, now compile this expression188 189 lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());190 if (jit_process_sp) {191 const bool generate_debug_info = true;192 auto *clang_parser = new ClangExpressionParser(193 jit_process_sp.get(), *this, generate_debug_info, diagnostic_manager);194 num_errors = clang_parser->Parse(diagnostic_manager);195 m_parser.reset(clang_parser);196 } else {197 diagnostic_manager.PutString(lldb::eSeverityError,198 "no process - unable to inject function");199 num_errors = 1;200 }201 202 m_compiled = (num_errors == 0);203 204 if (!m_compiled)205 return num_errors;206 207 return num_errors;208}209 210char ClangFunctionCaller::ClangFunctionCallerHelper::ID;211 212clang::ASTConsumer *213ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer(214 clang::ASTConsumer *passthrough) {215 m_struct_extractor = std::make_unique<ASTStructExtractor>(216 passthrough, m_owner.GetWrapperStructName(), m_owner);217 218 return m_struct_extractor.get();219}220