180814287SRaphael Isemann //===-- ScriptInterpreter.cpp ---------------------------------------------===// 230fdc8d8SChris Lattner // 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 630fdc8d8SChris Lattner // 730fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 830fdc8d8SChris Lattner 930fdc8d8SChris Lattner #include "lldb/Interpreter/ScriptInterpreter.h" 10d79273c9SJonas Devlieghere #include "lldb/Core/Debugger.h" 11d79273c9SJonas Devlieghere #include "lldb/Host/ConnectionFileDescriptor.h" 12d79273c9SJonas Devlieghere #include "lldb/Host/Pipe.h" 1324ae6294SZachary Turner #include "lldb/Host/PseudoTerminal.h" 1430fdc8d8SChris Lattner #include "lldb/Interpreter/CommandReturnObject.h" 1597206d57SZachary Turner #include "lldb/Utility/Status.h" 16bf9a7730SZachary Turner #include "lldb/Utility/Stream.h" 17573ab909SZachary Turner #include "lldb/Utility/StringList.h" 1811f2ef4dSJonas Devlieghere #if defined(_WIN32) 1911f2ef4dSJonas Devlieghere #include "lldb/Host/windows/ConnectionGenericFileWindows.h" 2011f2ef4dSJonas Devlieghere #endif 2176e47d48SRaphael Isemann #include <cstdio> 2276e47d48SRaphael Isemann #include <cstdlib> 2311f2ef4dSJonas Devlieghere #include <memory> 2411f2ef4dSJonas Devlieghere #include <string> 2530fdc8d8SChris Lattner 2630fdc8d8SChris Lattner using namespace lldb; 2730fdc8d8SChris Lattner using namespace lldb_private; 2830fdc8d8SChris Lattner 291f6a57c1SMed Ismail Bennani ScriptInterpreter::ScriptInterpreter( 301f6a57c1SMed Ismail Bennani Debugger &debugger, lldb::ScriptLanguage script_lang, 311f6a57c1SMed Ismail Bennani lldb::ScriptedProcessInterfaceUP scripted_process_interface_up) 321f6a57c1SMed Ismail Bennani : m_debugger(debugger), m_script_lang(script_lang), 331f6a57c1SMed Ismail Bennani m_scripted_process_interface_up( 341f6a57c1SMed Ismail Bennani std::move(scripted_process_interface_up)) {} 3530fdc8d8SChris Lattner 36b9c1b51eSKate Stone void ScriptInterpreter::CollectDataForBreakpointCommandCallback( 37cfb96d84SJim Ingham std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, 38b9c1b51eSKate Stone CommandReturnObject &result) { 39b9c1b51eSKate Stone result.AppendError( 40ba0eb7b6SJonas Devlieghere "This script interpreter does not support breakpoint callbacks."); 4130fdc8d8SChris Lattner } 4230fdc8d8SChris Lattner 43b9c1b51eSKate Stone void ScriptInterpreter::CollectDataForWatchpointCommandCallback( 44b9c1b51eSKate Stone WatchpointOptions *bp_options, CommandReturnObject &result) { 45b9c1b51eSKate Stone result.AppendError( 46ba0eb7b6SJonas Devlieghere "This script interpreter does not support watchpoint callbacks."); 47e9a5627eSJohnny Chen } 48e9a5627eSJohnny Chen 49*bbef51ebSLawrence D'Anna StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() { 50*bbef51ebSLawrence D'Anna return nullptr; 51*bbef51ebSLawrence D'Anna } 52*bbef51ebSLawrence D'Anna 5300bb397bSJonas Devlieghere bool ScriptInterpreter::LoadScriptingModule(const char *filename, 54f9517353SJonas Devlieghere const LoadScriptOptions &options, 5500bb397bSJonas Devlieghere lldb_private::Status &error, 5600bb397bSJonas Devlieghere StructuredData::ObjectSP *module_sp, 5700bb397bSJonas Devlieghere FileSpec extra_search_dir) { 58bd5c8d16SJonas Devlieghere error.SetErrorString( 59bd5c8d16SJonas Devlieghere "This script interpreter does not support importing modules."); 60bd5c8d16SJonas Devlieghere return false; 61bd5c8d16SJonas Devlieghere } 62bd5c8d16SJonas Devlieghere 63b9c1b51eSKate Stone std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) { 64b9c1b51eSKate Stone switch (language) { 653df9a8dfSCaroline Tice case eScriptLanguageNone: 66acdda134SJonas Devlieghere return "None"; 673df9a8dfSCaroline Tice case eScriptLanguagePython: 68acdda134SJonas Devlieghere return "Python"; 69acdda134SJonas Devlieghere case eScriptLanguageLua: 70acdda134SJonas Devlieghere return "Lua"; 71f7e07256SJim Ingham case eScriptLanguageUnknown: 72acdda134SJonas Devlieghere return "Unknown"; 733df9a8dfSCaroline Tice } 74fbccef6bSPavel Labath llvm_unreachable("Unhandled ScriptInterpreter!"); 753df9a8dfSCaroline Tice } 762f88aadfSCaroline Tice 771f6a57c1SMed Ismail Bennani lldb::DataExtractorSP 781f6a57c1SMed Ismail Bennani ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData &data) const { 791f6a57c1SMed Ismail Bennani return data.m_opaque_sp; 801f6a57c1SMed Ismail Bennani } 811f6a57c1SMed Ismail Bennani 821f6a57c1SMed Ismail Bennani Status 831f6a57c1SMed Ismail Bennani ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const { 841f6a57c1SMed Ismail Bennani if (error.m_opaque_up) 851f6a57c1SMed Ismail Bennani return *error.m_opaque_up.get(); 861f6a57c1SMed Ismail Bennani 871f6a57c1SMed Ismail Bennani return Status(); 881f6a57c1SMed Ismail Bennani } 891f6a57c1SMed Ismail Bennani 90a758c9f7SMed Ismail Bennani llvm::Optional<MemoryRegionInfo> 91a758c9f7SMed Ismail Bennani ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo( 92a758c9f7SMed Ismail Bennani const lldb::SBMemoryRegionInfo &mem_region) const { 93a758c9f7SMed Ismail Bennani if (!mem_region.m_opaque_up) 94a758c9f7SMed Ismail Bennani return llvm::None; 95a758c9f7SMed Ismail Bennani return *mem_region.m_opaque_up.get(); 96a758c9f7SMed Ismail Bennani } 97a758c9f7SMed Ismail Bennani 98f7e07256SJim Ingham lldb::ScriptLanguage 99f7e07256SJim Ingham ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) { 100e50f9c41SMartin Storsjö if (language.equals_insensitive(LanguageToString(eScriptLanguageNone))) 101f7e07256SJim Ingham return eScriptLanguageNone; 102e50f9c41SMartin Storsjö if (language.equals_insensitive(LanguageToString(eScriptLanguagePython))) 103f7e07256SJim Ingham return eScriptLanguagePython; 104e50f9c41SMartin Storsjö if (language.equals_insensitive(LanguageToString(eScriptLanguageLua))) 105acdda134SJonas Devlieghere return eScriptLanguageLua; 106f7e07256SJim Ingham return eScriptLanguageUnknown; 107f7e07256SJim Ingham } 108f7e07256SJim Ingham 10997206d57SZachary Turner Status ScriptInterpreter::SetBreakpointCommandCallback( 110cfb96d84SJim Ingham std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, 111b9c1b51eSKate Stone const char *callback_text) { 11297206d57SZachary Turner Status return_error; 113cfb96d84SJim Ingham for (BreakpointOptions &bp_options : bp_options_vec) { 114b5796cb4SJim Ingham return_error = SetBreakpointCommandCallback(bp_options, callback_text); 115b5796cb4SJim Ingham if (return_error.Success()) 116b5796cb4SJim Ingham break; 117b5796cb4SJim Ingham } 118b5796cb4SJim Ingham return return_error; 119b5796cb4SJim Ingham } 120b5796cb4SJim Ingham 121738af7a6SJim Ingham Status ScriptInterpreter::SetBreakpointCommandCallbackFunction( 122cfb96d84SJim Ingham std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, 123cfb96d84SJim Ingham const char *function_name, StructuredData::ObjectSP extra_args_sp) { 124738af7a6SJim Ingham Status error; 125cfb96d84SJim Ingham for (BreakpointOptions &bp_options : bp_options_vec) { 126738af7a6SJim Ingham error = SetBreakpointCommandCallbackFunction(bp_options, function_name, 127738af7a6SJim Ingham extra_args_sp); 128738af7a6SJim Ingham if (!error.Success()) 129738af7a6SJim Ingham return error; 130b5796cb4SJim Ingham } 131738af7a6SJim Ingham return error; 132b5796cb4SJim Ingham } 133b5796cb4SJim Ingham 1347b0992d9SGreg Clayton std::unique_ptr<ScriptInterpreterLocker> 135b9c1b51eSKate Stone ScriptInterpreter::AcquireInterpreterLock() { 13606412daeSJonas Devlieghere return std::make_unique<ScriptInterpreterLocker>(); 137360cc318SEnrico Granata } 138d79273c9SJonas Devlieghere 139d79273c9SJonas Devlieghere static void ReadThreadBytesReceived(void *baton, const void *src, 140d79273c9SJonas Devlieghere size_t src_len) { 141d79273c9SJonas Devlieghere if (src && src_len) { 142d79273c9SJonas Devlieghere Stream *strm = (Stream *)baton; 143d79273c9SJonas Devlieghere strm->Write(src, src_len); 144d79273c9SJonas Devlieghere strm->Flush(); 145d79273c9SJonas Devlieghere } 146d79273c9SJonas Devlieghere } 147d79273c9SJonas Devlieghere 148d79273c9SJonas Devlieghere llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 14984228365SJonas Devlieghere ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger, 15084228365SJonas Devlieghere CommandReturnObject *result) { 15184228365SJonas Devlieghere if (enable_io) 15284228365SJonas Devlieghere return std::unique_ptr<ScriptInterpreterIORedirect>( 15384228365SJonas Devlieghere new ScriptInterpreterIORedirect(debugger, result)); 15484228365SJonas Devlieghere 155d79273c9SJonas Devlieghere auto nullin = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL), 15614735cabSMichał Górny File::eOpenOptionReadOnly); 157d79273c9SJonas Devlieghere if (!nullin) 158d79273c9SJonas Devlieghere return nullin.takeError(); 159d79273c9SJonas Devlieghere 160d79273c9SJonas Devlieghere auto nullout = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL), 16114735cabSMichał Górny File::eOpenOptionWriteOnly); 162d79273c9SJonas Devlieghere if (!nullout) 163d79273c9SJonas Devlieghere return nullin.takeError(); 164d79273c9SJonas Devlieghere 165d79273c9SJonas Devlieghere return std::unique_ptr<ScriptInterpreterIORedirect>( 166d79273c9SJonas Devlieghere new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout))); 167d79273c9SJonas Devlieghere } 168d79273c9SJonas Devlieghere 169d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( 170d79273c9SJonas Devlieghere std::unique_ptr<File> input, std::unique_ptr<File> output) 171d79273c9SJonas Devlieghere : m_input_file_sp(std::move(input)), 172d79273c9SJonas Devlieghere m_output_file_sp(std::make_shared<StreamFile>(std::move(output))), 173d79273c9SJonas Devlieghere m_error_file_sp(m_output_file_sp), 174d79273c9SJonas Devlieghere m_communication("lldb.ScriptInterpreterIORedirect.comm"), 175d79273c9SJonas Devlieghere m_disconnect(false) {} 176d79273c9SJonas Devlieghere 177d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( 178d79273c9SJonas Devlieghere Debugger &debugger, CommandReturnObject *result) 179d79273c9SJonas Devlieghere : m_communication("lldb.ScriptInterpreterIORedirect.comm"), 180d79273c9SJonas Devlieghere m_disconnect(false) { 181d79273c9SJonas Devlieghere 182d79273c9SJonas Devlieghere if (result) { 183d79273c9SJonas Devlieghere m_input_file_sp = debugger.GetInputFileSP(); 184d79273c9SJonas Devlieghere 185d79273c9SJonas Devlieghere Pipe pipe; 186d79273c9SJonas Devlieghere Status pipe_result = pipe.CreateNew(false); 187d79273c9SJonas Devlieghere #if defined(_WIN32) 188d79273c9SJonas Devlieghere lldb::file_t read_file = pipe.GetReadNativeHandle(); 189d79273c9SJonas Devlieghere pipe.ReleaseReadFileDescriptor(); 190d79273c9SJonas Devlieghere std::unique_ptr<ConnectionGenericFile> conn_up = 191d79273c9SJonas Devlieghere std::make_unique<ConnectionGenericFile>(read_file, true); 192d79273c9SJonas Devlieghere #else 193d79273c9SJonas Devlieghere std::unique_ptr<ConnectionFileDescriptor> conn_up = 194d79273c9SJonas Devlieghere std::make_unique<ConnectionFileDescriptor>( 195d79273c9SJonas Devlieghere pipe.ReleaseReadFileDescriptor(), true); 196d79273c9SJonas Devlieghere #endif 197d79273c9SJonas Devlieghere 198d79273c9SJonas Devlieghere if (conn_up->IsConnected()) { 199d79273c9SJonas Devlieghere m_communication.SetConnection(std::move(conn_up)); 200d79273c9SJonas Devlieghere m_communication.SetReadThreadBytesReceivedCallback( 201d79273c9SJonas Devlieghere ReadThreadBytesReceived, &result->GetOutputStream()); 202d79273c9SJonas Devlieghere m_communication.StartReadThread(); 203d79273c9SJonas Devlieghere m_disconnect = true; 204d79273c9SJonas Devlieghere 205d79273c9SJonas Devlieghere FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w"); 206d79273c9SJonas Devlieghere m_output_file_sp = std::make_shared<StreamFile>(outfile_handle, true); 207d79273c9SJonas Devlieghere m_error_file_sp = m_output_file_sp; 208d79273c9SJonas Devlieghere if (outfile_handle) 209d79273c9SJonas Devlieghere ::setbuf(outfile_handle, nullptr); 210d79273c9SJonas Devlieghere 211d79273c9SJonas Devlieghere result->SetImmediateOutputFile(debugger.GetOutputStream().GetFileSP()); 212d79273c9SJonas Devlieghere result->SetImmediateErrorFile(debugger.GetErrorStream().GetFileSP()); 213d79273c9SJonas Devlieghere } 214d79273c9SJonas Devlieghere } 215d79273c9SJonas Devlieghere 216d79273c9SJonas Devlieghere if (!m_input_file_sp || !m_output_file_sp || !m_error_file_sp) 217d79273c9SJonas Devlieghere debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp, m_output_file_sp, 218d79273c9SJonas Devlieghere m_error_file_sp); 219d79273c9SJonas Devlieghere } 220d79273c9SJonas Devlieghere 221d79273c9SJonas Devlieghere void ScriptInterpreterIORedirect::Flush() { 222d79273c9SJonas Devlieghere if (m_output_file_sp) 223d79273c9SJonas Devlieghere m_output_file_sp->Flush(); 224d79273c9SJonas Devlieghere if (m_error_file_sp) 225d79273c9SJonas Devlieghere m_error_file_sp->Flush(); 226d79273c9SJonas Devlieghere } 227d79273c9SJonas Devlieghere 228d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() { 229d79273c9SJonas Devlieghere if (!m_disconnect) 230d79273c9SJonas Devlieghere return; 231d79273c9SJonas Devlieghere 232d79273c9SJonas Devlieghere assert(m_output_file_sp); 233d79273c9SJonas Devlieghere assert(m_error_file_sp); 234d79273c9SJonas Devlieghere assert(m_output_file_sp == m_error_file_sp); 235d79273c9SJonas Devlieghere 236d79273c9SJonas Devlieghere // Close the write end of the pipe since we are done with our one line 237d79273c9SJonas Devlieghere // script. This should cause the read thread that output_comm is using to 238d79273c9SJonas Devlieghere // exit. 239d79273c9SJonas Devlieghere m_output_file_sp->GetFile().Close(); 240d79273c9SJonas Devlieghere // The close above should cause this thread to exit when it gets to the end 241d79273c9SJonas Devlieghere // of file, so let it get all its data. 242d79273c9SJonas Devlieghere m_communication.JoinReadThread(); 243d79273c9SJonas Devlieghere // Now we can close the read end of the pipe. 244d79273c9SJonas Devlieghere m_communication.Disconnect(); 245d79273c9SJonas Devlieghere } 246