180814287SRaphael Isemann //===-- ClangFunctionCaller.cpp -------------------------------------------===//
24dbb271fSSean Callanan //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64dbb271fSSean Callanan //
74dbb271fSSean Callanan //===----------------------------------------------------------------------===//
84dbb271fSSean Callanan 
94dbb271fSSean Callanan #include "ClangFunctionCaller.h"
104dbb271fSSean Callanan 
114dbb271fSSean Callanan #include "ASTStructExtractor.h"
124dbb271fSSean Callanan #include "ClangExpressionParser.h"
134dbb271fSSean Callanan 
144dbb271fSSean Callanan #include "clang/AST/ASTContext.h"
154dbb271fSSean Callanan #include "clang/AST/RecordLayout.h"
164dbb271fSSean Callanan #include "clang/CodeGen/CodeGenAction.h"
174dbb271fSSean Callanan #include "clang/CodeGen/ModuleBuilder.h"
184dbb271fSSean Callanan #include "clang/Frontend/CompilerInstance.h"
194dbb271fSSean Callanan #include "llvm/ADT/StringRef.h"
204dbb271fSSean Callanan #include "llvm/ADT/Triple.h"
214dbb271fSSean Callanan #include "llvm/ExecutionEngine/ExecutionEngine.h"
224dbb271fSSean Callanan #include "llvm/IR/Module.h"
234dbb271fSSean Callanan 
248be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
254dbb271fSSean Callanan #include "lldb/Core/Module.h"
264dbb271fSSean Callanan #include "lldb/Core/ValueObject.h"
274dbb271fSSean Callanan #include "lldb/Core/ValueObjectList.h"
284dbb271fSSean Callanan #include "lldb/Expression/IRExecutionUnit.h"
294dbb271fSSean Callanan #include "lldb/Interpreter/CommandReturnObject.h"
304dbb271fSSean Callanan #include "lldb/Symbol/Function.h"
314dbb271fSSean Callanan #include "lldb/Symbol/Type.h"
324dbb271fSSean Callanan #include "lldb/Target/ExecutionContext.h"
334dbb271fSSean Callanan #include "lldb/Target/Process.h"
344dbb271fSSean Callanan #include "lldb/Target/RegisterContext.h"
354dbb271fSSean Callanan #include "lldb/Target/Target.h"
364dbb271fSSean Callanan #include "lldb/Target/Thread.h"
374dbb271fSSean Callanan #include "lldb/Target/ThreadPlan.h"
384dbb271fSSean Callanan #include "lldb/Target/ThreadPlanCallFunction.h"
39666cc0b2SZachary Turner #include "lldb/Utility/DataExtractor.h"
40*c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
416f9e6901SZachary Turner #include "lldb/Utility/Log.h"
42d821c997SPavel Labath #include "lldb/Utility/State.h"
434dbb271fSSean Callanan 
444dbb271fSSean Callanan using namespace lldb_private;
454dbb271fSSean Callanan 
4652f3a2faSRaphael Isemann char ClangFunctionCaller::ID;
4752f3a2faSRaphael Isemann 
484dbb271fSSean Callanan // ClangFunctionCaller constructor
ClangFunctionCaller(ExecutionContextScope & exe_scope,const CompilerType & return_type,const Address & functionAddress,const ValueList & arg_value_list,const char * name)49b9c1b51eSKate Stone ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope,
504dbb271fSSean Callanan                                          const CompilerType &return_type,
514dbb271fSSean Callanan                                          const Address &functionAddress,
524dbb271fSSean Callanan                                          const ValueList &arg_value_list,
53b9c1b51eSKate Stone                                          const char *name)
54b9c1b51eSKate Stone     : FunctionCaller(exe_scope, return_type, functionAddress, arg_value_list,
55b9c1b51eSKate Stone                      name),
56b9c1b51eSKate Stone       m_type_system_helper(*this) {
574dbb271fSSean Callanan   m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess());
584dbb271fSSean Callanan   // Can't make a ClangFunctionCaller without a process.
594dbb271fSSean Callanan   assert(m_jit_process_wp.lock());
604dbb271fSSean Callanan }
614dbb271fSSean Callanan 
624dbb271fSSean Callanan // Destructor
63fd2433e1SJonas Devlieghere ClangFunctionCaller::~ClangFunctionCaller() = default;
644dbb271fSSean Callanan 
654dbb271fSSean Callanan unsigned
666896b355SJim Ingham 
CompileFunction(lldb::ThreadSP thread_to_use_sp,DiagnosticManager & diagnostic_manager)676896b355SJim Ingham ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp,
68b9c1b51eSKate Stone                                      DiagnosticManager &diagnostic_manager) {
694dbb271fSSean Callanan   if (m_compiled)
704dbb271fSSean Callanan     return 0;
714dbb271fSSean Callanan 
72b9c1b51eSKate Stone   // Compilation might call code, make sure to keep on the thread the caller
73b9c1b51eSKate Stone   // indicated.
74b9c1b51eSKate Stone   ThreadList::ExpressionExecutionThreadPusher execution_thread_pusher(
75b9c1b51eSKate Stone       thread_to_use_sp);
766896b355SJim Ingham 
77b9c1b51eSKate Stone   // FIXME: How does clang tell us there's no return value?  We need to handle
78b9c1b51eSKate Stone   // that case.
794dbb271fSSean Callanan   unsigned num_errors = 0;
804dbb271fSSean Callanan 
81b9c1b51eSKate Stone   std::string return_type_str(
82b9c1b51eSKate Stone       m_function_return_type.GetTypeName().AsCString(""));
834dbb271fSSean Callanan 
844dbb271fSSean Callanan   // Cons up the function we're going to wrap our call in, then compile it...
854dbb271fSSean Callanan   // We declare the function "extern "C"" because the compiler might be in C++
864dbb271fSSean Callanan   // mode which would mangle the name and then we couldn't find it again...
874dbb271fSSean Callanan   m_wrapper_function_text.clear();
884dbb271fSSean Callanan   m_wrapper_function_text.append("extern \"C\" void ");
894dbb271fSSean Callanan   m_wrapper_function_text.append(m_wrapper_function_name);
904dbb271fSSean Callanan   m_wrapper_function_text.append(" (void *input)\n{\n    struct ");
914dbb271fSSean Callanan   m_wrapper_function_text.append(m_wrapper_struct_name);
924dbb271fSSean Callanan   m_wrapper_function_text.append(" \n  {\n");
934dbb271fSSean Callanan   m_wrapper_function_text.append("    ");
944dbb271fSSean Callanan   m_wrapper_function_text.append(return_type_str);
954dbb271fSSean Callanan   m_wrapper_function_text.append(" (*fn_ptr) (");
964dbb271fSSean Callanan 
97b9c1b51eSKate Stone   // Get the number of arguments.  If we have a function type and it is
9805097246SAdrian Prantl   // prototyped, trust that, otherwise use the values we were given.
994dbb271fSSean Callanan 
100b9c1b51eSKate Stone   // FIXME: This will need to be extended to handle Variadic functions.  We'll
101b9c1b51eSKate Stone   // need
102b9c1b51eSKate Stone   // to pull the defined arguments out of the function, then add the types from
10305097246SAdrian Prantl   // the arguments list for the variable arguments.
1044dbb271fSSean Callanan 
1054dbb271fSSean Callanan   uint32_t num_args = UINT32_MAX;
1064dbb271fSSean Callanan   bool trust_function = false;
1074dbb271fSSean Callanan   // GetArgumentCount returns -1 for an unprototyped function.
1084dbb271fSSean Callanan   CompilerType function_clang_type;
109b9c1b51eSKate Stone   if (m_function_ptr) {
1104dbb271fSSean Callanan     function_clang_type = m_function_ptr->GetCompilerType();
111b9c1b51eSKate Stone     if (function_clang_type) {
1124dbb271fSSean Callanan       int num_func_args = function_clang_type.GetFunctionArgumentCount();
113b9c1b51eSKate Stone       if (num_func_args >= 0) {
1144dbb271fSSean Callanan         trust_function = true;
1154dbb271fSSean Callanan         num_args = num_func_args;
1164dbb271fSSean Callanan       }
1174dbb271fSSean Callanan     }
1184dbb271fSSean Callanan   }
1194dbb271fSSean Callanan 
1204dbb271fSSean Callanan   if (num_args == UINT32_MAX)
1214dbb271fSSean Callanan     num_args = m_arg_values.GetSize();
1224dbb271fSSean Callanan 
123b9c1b51eSKate Stone   std::string args_buffer; // This one stores the definition of all the args in
124b9c1b51eSKate Stone                            // "struct caller".
125b9c1b51eSKate Stone   std::string args_list_buffer; // This one stores the argument list called from
126b9c1b51eSKate Stone                                 // the structure.
127b9c1b51eSKate Stone   for (size_t i = 0; i < num_args; i++) {
1284dbb271fSSean Callanan     std::string type_name;
1294dbb271fSSean Callanan 
130b9c1b51eSKate Stone     if (trust_function) {
131b9c1b51eSKate Stone       type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i)
132b9c1b51eSKate Stone                       .GetTypeName()
133b9c1b51eSKate Stone                       .AsCString("");
134b9c1b51eSKate Stone     } else {
135b9c1b51eSKate Stone       CompilerType clang_qual_type =
136b9c1b51eSKate Stone           m_arg_values.GetValueAtIndex(i)->GetCompilerType();
137b9c1b51eSKate Stone       if (clang_qual_type) {
1384dbb271fSSean Callanan         type_name = clang_qual_type.GetTypeName().AsCString("");
139b9c1b51eSKate Stone       } else {
140b9c1b51eSKate Stone         diagnostic_manager.Printf(
141b9c1b51eSKate Stone             eDiagnosticSeverityError,
142b9c1b51eSKate Stone             "Could not determine type of input value %" PRIu64 ".",
143b9c1b51eSKate Stone             (uint64_t)i);
1444dbb271fSSean Callanan         return 1;
1454dbb271fSSean Callanan       }
1464dbb271fSSean Callanan     }
1474dbb271fSSean Callanan 
1484dbb271fSSean Callanan     m_wrapper_function_text.append(type_name);
1494dbb271fSSean Callanan     if (i < num_args - 1)
1504dbb271fSSean Callanan       m_wrapper_function_text.append(", ");
1514dbb271fSSean Callanan 
1524dbb271fSSean Callanan     char arg_buf[32];
1534dbb271fSSean Callanan     args_buffer.append("    ");
1544dbb271fSSean Callanan     args_buffer.append(type_name);
1554dbb271fSSean Callanan     snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i);
1564dbb271fSSean Callanan     args_buffer.push_back(' ');
1574dbb271fSSean Callanan     args_buffer.append(arg_buf);
1584dbb271fSSean Callanan     args_buffer.append(";\n");
1594dbb271fSSean Callanan 
1604dbb271fSSean Callanan     args_list_buffer.append("__lldb_fn_data->");
1614dbb271fSSean Callanan     args_list_buffer.append(arg_buf);
1624dbb271fSSean Callanan     if (i < num_args - 1)
1634dbb271fSSean Callanan       args_list_buffer.append(", ");
1644dbb271fSSean Callanan   }
165b9c1b51eSKate Stone   m_wrapper_function_text.append(
166b9c1b51eSKate Stone       ");\n"); // Close off the function calling prototype.
1674dbb271fSSean Callanan 
1684dbb271fSSean Callanan   m_wrapper_function_text.append(args_buffer);
1694dbb271fSSean Callanan 
1704dbb271fSSean Callanan   m_wrapper_function_text.append("    ");
1714dbb271fSSean Callanan   m_wrapper_function_text.append(return_type_str);
1724dbb271fSSean Callanan   m_wrapper_function_text.append(" return_value;");
1734dbb271fSSean Callanan   m_wrapper_function_text.append("\n  };\n  struct ");
1744dbb271fSSean Callanan   m_wrapper_function_text.append(m_wrapper_struct_name);
1754dbb271fSSean Callanan   m_wrapper_function_text.append("* __lldb_fn_data = (struct ");
1764dbb271fSSean Callanan   m_wrapper_function_text.append(m_wrapper_struct_name);
1774dbb271fSSean Callanan   m_wrapper_function_text.append(" *) input;\n");
1784dbb271fSSean Callanan 
179b9c1b51eSKate Stone   m_wrapper_function_text.append(
180b9c1b51eSKate Stone       "  __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr (");
1814dbb271fSSean Callanan   m_wrapper_function_text.append(args_list_buffer);
1824dbb271fSSean Callanan   m_wrapper_function_text.append(");\n}\n");
1834dbb271fSSean Callanan 
184a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Expressions);
18563e5fb76SJonas Devlieghere   LLDB_LOGF(log, "Expression: \n\n%s\n\n", m_wrapper_function_text.c_str());
1864dbb271fSSean Callanan 
1874dbb271fSSean Callanan   // Okay, now compile this expression
1884dbb271fSSean Callanan 
1894dbb271fSSean Callanan   lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
190b9c1b51eSKate Stone   if (jit_process_sp) {
1914dbb271fSSean Callanan     const bool generate_debug_info = true;
19225b486acSRaphael Isemann     auto *clang_parser = new ClangExpressionParser(jit_process_sp.get(), *this,
19325b486acSRaphael Isemann                                                    generate_debug_info);
19425b486acSRaphael Isemann     num_errors = clang_parser->Parse(diagnostic_manager);
19525b486acSRaphael Isemann     m_parser.reset(clang_parser);
196b9c1b51eSKate Stone   } else {
197e2411fabSZachary Turner     diagnostic_manager.PutString(eDiagnosticSeverityError,
198b9c1b51eSKate Stone                                  "no process - unable to inject function");
1994dbb271fSSean Callanan     num_errors = 1;
2004dbb271fSSean Callanan   }
2014dbb271fSSean Callanan 
2024dbb271fSSean Callanan   m_compiled = (num_errors == 0);
2034dbb271fSSean Callanan 
2044dbb271fSSean Callanan   if (!m_compiled)
2054dbb271fSSean Callanan     return num_errors;
2064dbb271fSSean Callanan 
2074dbb271fSSean Callanan   return num_errors;
2084dbb271fSSean Callanan }
2094dbb271fSSean Callanan 
2104dbb271fSSean Callanan clang::ASTConsumer *
ASTTransformer(clang::ASTConsumer * passthrough)211b9c1b51eSKate Stone ClangFunctionCaller::ClangFunctionCallerHelper::ASTTransformer(
212b9c1b51eSKate Stone     clang::ASTConsumer *passthrough) {
21306412daeSJonas Devlieghere   m_struct_extractor = std::make_unique<ASTStructExtractor>(
21406412daeSJonas Devlieghere       passthrough, m_owner.GetWrapperStructName(), m_owner);
2154dbb271fSSean Callanan 
2164dbb271fSSean Callanan   return m_struct_extractor.get();
2174dbb271fSSean Callanan }
218