15ffd83dbSDimitry Andric //===-- UtilityFunction.cpp -----------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 9fe6060f1SDimitry Andric #include <cstdio> 100b57cec5SDimitry Andric #include <sys/types.h> 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "lldb/Core/Module.h" 130b57cec5SDimitry Andric #include "lldb/Expression/DiagnosticManager.h" 140b57cec5SDimitry Andric #include "lldb/Expression/FunctionCaller.h" 150b57cec5SDimitry Andric #include "lldb/Expression/IRExecutionUnit.h" 160b57cec5SDimitry Andric #include "lldb/Expression/UtilityFunction.h" 170b57cec5SDimitry Andric #include "lldb/Host/Host.h" 180b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h" 190b57cec5SDimitry Andric #include "lldb/Target/Process.h" 200b57cec5SDimitry Andric #include "lldb/Target/Target.h" 210b57cec5SDimitry Andric #include "lldb/Utility/ConstString.h" 220b57cec5SDimitry Andric #include "lldb/Utility/Log.h" 2306c3fb27SDimitry Andric #include "lldb/Utility/State.h" 240b57cec5SDimitry Andric #include "lldb/Utility/Stream.h" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace lldb_private; 270b57cec5SDimitry Andric using namespace lldb; 280b57cec5SDimitry Andric 29480093f4SDimitry Andric char UtilityFunction::ID; 30480093f4SDimitry Andric 310b57cec5SDimitry Andric /// Constructor 320b57cec5SDimitry Andric /// 330b57cec5SDimitry Andric /// \param[in] text 340b57cec5SDimitry Andric /// The text of the function. Must be a full translation unit. 350b57cec5SDimitry Andric /// 360b57cec5SDimitry Andric /// \param[in] name 370b57cec5SDimitry Andric /// The name of the function, as used in the text. 380b57cec5SDimitry Andric UtilityFunction::UtilityFunction(ExecutionContextScope &exe_scope, 39fe6060f1SDimitry Andric std::string text, std::string name, 40fe6060f1SDimitry Andric bool enable_debugging) 41480093f4SDimitry Andric : Expression(exe_scope), m_execution_unit_sp(), m_jit_module_wp(), 42e8d8bef9SDimitry Andric m_function_text(std::move(text)), m_function_name(std::move(name)) {} 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric UtilityFunction::~UtilityFunction() { 450b57cec5SDimitry Andric lldb::ProcessSP process_sp(m_jit_process_wp.lock()); 460b57cec5SDimitry Andric if (process_sp) { 470b57cec5SDimitry Andric lldb::ModuleSP jit_module_sp(m_jit_module_wp.lock()); 480b57cec5SDimitry Andric if (jit_module_sp) 490b57cec5SDimitry Andric process_sp->GetTarget().GetImages().Remove(jit_module_sp); 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric // FIXME: We should check that every time this is called it is called with the 540b57cec5SDimitry Andric // same return type & arguments... 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric FunctionCaller *UtilityFunction::MakeFunctionCaller( 570b57cec5SDimitry Andric const CompilerType &return_type, const ValueList &arg_value_list, 580b57cec5SDimitry Andric lldb::ThreadSP thread_to_use_sp, Status &error) { 590b57cec5SDimitry Andric if (m_caller_up) 600b57cec5SDimitry Andric return m_caller_up.get(); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric ProcessSP process_sp = m_jit_process_wp.lock(); 630b57cec5SDimitry Andric if (!process_sp) { 640b57cec5SDimitry Andric error.SetErrorString("Can't make a function caller without a process."); 650b57cec5SDimitry Andric return nullptr; 660b57cec5SDimitry Andric } 6706c3fb27SDimitry Andric // Since we might need to allocate memory and maybe call code to make 68bdd1243dSDimitry Andric // the caller, we need to be stopped. 69bdd1243dSDimitry Andric if (process_sp->GetState() != lldb::eStateStopped) { 7006c3fb27SDimitry Andric error.SetErrorStringWithFormatv( 7106c3fb27SDimitry Andric "Can't make a function caller while the process is {0}: the process " 7206c3fb27SDimitry Andric "must be stopped to allocate memory.", 7306c3fb27SDimitry Andric StateAsCString(process_sp->GetState())); 74bdd1243dSDimitry Andric return nullptr; 75bdd1243dSDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric Address impl_code_address; 780b57cec5SDimitry Andric impl_code_address.SetOffset(StartAddress()); 790b57cec5SDimitry Andric std::string name(m_function_name); 800b57cec5SDimitry Andric name.append("-caller"); 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric m_caller_up.reset(process_sp->GetTarget().GetFunctionCallerForLanguage( 83*0fca6ea1SDimitry Andric Language().AsLanguageType(), return_type, impl_code_address, 84*0fca6ea1SDimitry Andric arg_value_list, name.c_str(), error)); 850b57cec5SDimitry Andric if (error.Fail()) { 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric return nullptr; 880b57cec5SDimitry Andric } 890b57cec5SDimitry Andric if (m_caller_up) { 900b57cec5SDimitry Andric DiagnosticManager diagnostics; 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric unsigned num_errors = 930b57cec5SDimitry Andric m_caller_up->CompileFunction(thread_to_use_sp, diagnostics); 940b57cec5SDimitry Andric if (num_errors) { 950b57cec5SDimitry Andric error.SetErrorStringWithFormat( 960b57cec5SDimitry Andric "Error compiling %s caller function: \"%s\".", 970b57cec5SDimitry Andric m_function_name.c_str(), diagnostics.GetString().c_str()); 980b57cec5SDimitry Andric m_caller_up.reset(); 990b57cec5SDimitry Andric return nullptr; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric diagnostics.Clear(); 1030b57cec5SDimitry Andric ExecutionContext exe_ctx(process_sp); 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric if (!m_caller_up->WriteFunctionWrapper(exe_ctx, diagnostics)) { 1060b57cec5SDimitry Andric error.SetErrorStringWithFormat( 1070b57cec5SDimitry Andric "Error inserting caller function for %s: \"%s\".", 1080b57cec5SDimitry Andric m_function_name.c_str(), diagnostics.GetString().c_str()); 1090b57cec5SDimitry Andric m_caller_up.reset(); 1100b57cec5SDimitry Andric return nullptr; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric return m_caller_up.get(); 1140b57cec5SDimitry Andric } 115