diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp new file mode 100644 index 000000000000..59321e375bdc --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -0,0 +1,219 @@ +//===-- ClangFunctionCaller.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ClangFunctionCaller.h" + +#include "ASTStructExtractor.h" +#include "ClangExpressionParser.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" +#include "clang/CodeGen/CodeGenAction.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/IR/Module.h" +#include "llvm/TargetParser/Triple.h" + +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectList.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanCallFunction.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/State.h" + +using namespace lldb_private; + +char ClangFunctionCaller::ID; + +// ClangFunctionCaller constructor +ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope, + const CompilerType &return_type, + const Address &functionAddress, + const ValueList &arg_value_list, + const char *name) + : FunctionCaller(exe_scope, return_type, functionAddress, arg_value_list, + name), + m_type_system_helper(*this) { + m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess()); + // Can't make a ClangFunctionCaller without a process. + assert(m_jit_process_wp.lock()); +} + +// Destructor +ClangFunctionCaller::~ClangFunctionCaller() = default; + +unsigned + +ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp, + DiagnosticManager &diagnostic_manager) { + if (m_compiled) + return 0; + + // Compilation might call code, make sure to keep on the thread the caller + // indicated. + ThreadList::ExpressionExecutionThreadPusher execution_thread_pusher( + thread_to_use_sp); + + // FIXME: How does clang tell us there's no return value? We need to handle + // that case. + unsigned num_errors = 0; + + std::string return_type_str( + m_function_return_type.GetTypeName().AsCString("")); + + // Cons up the function we're going to wrap our call in, then compile it... + // We declare the function "extern "C"" because the compiler might be in C++ + // mode which would mangle the name and then we couldn't find it again... + m_wrapper_function_text.clear(); + m_wrapper_function_text.append("extern \"C\" void "); + m_wrapper_function_text.append(m_wrapper_function_name); + m_wrapper_function_text.append(" (void *input)\n{\n struct "); + m_wrapper_function_text.append(m_wrapper_struct_name); + m_wrapper_function_text.append(" \n {\n"); + m_wrapper_function_text.append(" "); + m_wrapper_function_text.append(return_type_str); + m_wrapper_function_text.append(" (*fn_ptr) ("); + + // Get the number of arguments. If we have a function type and it is + // prototyped, trust that, otherwise use the values we were given. + + // FIXME: This will need to be extended to handle Variadic functions. We'll + // need + // to pull the defined arguments out of the function, then add the types from + // the arguments list for the variable arguments. + + uint32_t num_args = UINT32_MAX; + bool trust_function = false; + // GetArgumentCount returns -1 for an unprototyped function. + CompilerType function_clang_type; + if (m_function_ptr) { + function_clang_type = m_function_ptr->GetCompilerType(); + if (function_clang_type) { + int num_func_args = function_clang_type.GetFunctionArgumentCount(); + if (num_func_args >= 0) { + trust_function = true; + num_args = num_func_args; + } + } + } + + if (num_args == UINT32_MAX) + num_args = m_arg_values.GetSize(); + + std::string args_buffer; // This one stores the definition of all the args in + // "struct caller". + std::string args_list_buffer; // This one stores the argument list called from + // the structure. + for (size_t i = 0; i < num_args; i++) { + std::string type_name; + + if (trust_function) { + type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i) + .GetTypeName() + .AsCString(""); + } else { + CompilerType clang_qual_type = + m_arg_values.GetValueAtIndex(i)->GetCompilerType(); + if (clang_qual_type) { + type_name = clang_qual_type.GetTypeName().AsCString(""); + } else { + diagnostic_manager.Printf( + lldb::eSeverityError, + "Could not determine type of input value %" PRIu64 ".", + (uint64_t)i); + return 1; + } + } + + m_wrapper_function_text.append(type_name); + if (i < num_args - 1) + m_wrapper_function_text.append(", "); + + char arg_buf[32]; + args_buffer.append(" "); + args_buffer.append(type_name); + snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i); + args_buffer.push_back(' '); + args_buffer.append(arg_buf); + args_buffer.append(";\n"); + + args_list_buffer.append("__lldb_fn_data->"); + args_list_buffer.append(arg_buf); + if (i < num_args - 1) + args_list_buffer.append(", "); + } + m_wrapper_function_text.append( + ");\n"); // Close off the function calling prototype. + + m_wrapper_function_text.append(args_buffer); + + m_wrapper_function_text.append(" "); + m_wrapper_function_text.append(return_type_str); + m_wrapper_function_text.append(" return_value;"); + m_wrapper_function_text.append("\n };\n struct "); + m_wrapper_function_text.append(m_wrapper_struct_name); + m_wrapper_function_text.append("* __lldb_fn_data = (struct "); + m_wrapper_function_text.append(m_wrapper_struct_name); + m_wrapper_function_text.append(" *) input;\n"); + + m_wrapper_function_text.append( + " __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr ("); + m_wrapper_function_text.append(args_list_buffer); + m_wrapper_function_text.append(");\n}\n"); + + Log *log = GetLog(LLDBLog::Expressions); + LLDB_LOGF(log, "Expression: \n\n%s\n\n", m_wrapper_function_text.c_str()); + + // Okay, now compile this expression + + lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); + if (jit_process_sp) { + const bool generate_debug_info = true; + auto *clang_parser = new ClangExpressionParser(jit_process_sp.get(), *this, + generate_debug_info); + num_errors = clang_parser->Parse(diagnostic_manager); + m_parser.reset(clang_parser); + } else { + diagnostic_manager.PutString(lldb::eSeverityError, + "no process - unable to inject function"); + num_errors = 1; + } + + m_compiled = (num_errors == 0); + + if (!m_compiled) + return num_errors; + + return num_errors; +} + +char ClangFunctionCaller::ClangFunctionCallerHelper::ID; + +clang::ASTConsumer * +ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer( + clang::ASTConsumer *passthrough) { + m_struct_extractor = std::make_unique<ASTStructExtractor>( + passthrough, m_owner.GetWrapperStructName(), m_owner); + + return m_struct_extractor.get(); +} |