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" 18*11f2ef4dSJonas Devlieghere #if defined(_WIN32) 19*11f2ef4dSJonas Devlieghere #include "lldb/Host/windows/ConnectionGenericFileWindows.h" 20*11f2ef4dSJonas Devlieghere #endif 21*11f2ef4dSJonas Devlieghere #include <memory> 22*11f2ef4dSJonas Devlieghere #include <stdio.h> 23*11f2ef4dSJonas Devlieghere #include <stdlib.h> 24*11f2ef4dSJonas Devlieghere #include <string> 2530fdc8d8SChris Lattner 2630fdc8d8SChris Lattner using namespace lldb; 2730fdc8d8SChris Lattner using namespace lldb_private; 2830fdc8d8SChris Lattner 298d1fb843SJonas Devlieghere ScriptInterpreter::ScriptInterpreter(Debugger &debugger, 30b9c1b51eSKate Stone lldb::ScriptLanguage script_lang) 318d1fb843SJonas Devlieghere : m_debugger(debugger), m_script_lang(script_lang) {} 3230fdc8d8SChris Lattner 33b9c1b51eSKate Stone ScriptInterpreter::~ScriptInterpreter() {} 3430fdc8d8SChris Lattner 35b9c1b51eSKate Stone void ScriptInterpreter::CollectDataForBreakpointCommandCallback( 36b5796cb4SJim Ingham std::vector<BreakpointOptions *> &bp_options_vec, 37b9c1b51eSKate Stone CommandReturnObject &result) { 3830fdc8d8SChris Lattner result.SetStatus(eReturnStatusFailed); 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) { 45e9a5627eSJohnny Chen result.SetStatus(eReturnStatusFailed); 46b9c1b51eSKate Stone result.AppendError( 47ba0eb7b6SJonas Devlieghere "This script interpreter does not support watchpoint callbacks."); 48e9a5627eSJohnny Chen } 49e9a5627eSJohnny Chen 50bd5c8d16SJonas Devlieghere bool ScriptInterpreter::LoadScriptingModule( 5115625112SJonas Devlieghere const char *filename, bool init_session, lldb_private::Status &error, 5215625112SJonas Devlieghere StructuredData::ObjectSP *module_sp) { 53bd5c8d16SJonas Devlieghere error.SetErrorString( 54bd5c8d16SJonas Devlieghere "This script interpreter does not support importing modules."); 55bd5c8d16SJonas Devlieghere return false; 56bd5c8d16SJonas Devlieghere } 57bd5c8d16SJonas Devlieghere 58b9c1b51eSKate Stone std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) { 59b9c1b51eSKate Stone switch (language) { 603df9a8dfSCaroline Tice case eScriptLanguageNone: 61acdda134SJonas Devlieghere return "None"; 623df9a8dfSCaroline Tice case eScriptLanguagePython: 63acdda134SJonas Devlieghere return "Python"; 64acdda134SJonas Devlieghere case eScriptLanguageLua: 65acdda134SJonas Devlieghere return "Lua"; 66f7e07256SJim Ingham case eScriptLanguageUnknown: 67acdda134SJonas Devlieghere return "Unknown"; 683df9a8dfSCaroline Tice } 69fbccef6bSPavel Labath llvm_unreachable("Unhandled ScriptInterpreter!"); 703df9a8dfSCaroline Tice } 712f88aadfSCaroline Tice 72f7e07256SJim Ingham lldb::ScriptLanguage 73f7e07256SJim Ingham ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) { 74f7e07256SJim Ingham if (language.equals_lower(LanguageToString(eScriptLanguageNone))) 75f7e07256SJim Ingham return eScriptLanguageNone; 7645188dd9SDavide Italiano if (language.equals_lower(LanguageToString(eScriptLanguagePython))) 77f7e07256SJim Ingham return eScriptLanguagePython; 78acdda134SJonas Devlieghere if (language.equals_lower(LanguageToString(eScriptLanguageLua))) 79acdda134SJonas Devlieghere return eScriptLanguageLua; 80f7e07256SJim Ingham return eScriptLanguageUnknown; 81f7e07256SJim Ingham } 82f7e07256SJim Ingham 8397206d57SZachary Turner Status ScriptInterpreter::SetBreakpointCommandCallback( 84b9c1b51eSKate Stone std::vector<BreakpointOptions *> &bp_options_vec, 85b9c1b51eSKate Stone const char *callback_text) { 8697206d57SZachary Turner Status return_error; 87b9c1b51eSKate Stone for (BreakpointOptions *bp_options : bp_options_vec) { 88b5796cb4SJim Ingham return_error = SetBreakpointCommandCallback(bp_options, callback_text); 89b5796cb4SJim Ingham if (return_error.Success()) 90b5796cb4SJim Ingham break; 91b5796cb4SJim Ingham } 92b5796cb4SJim Ingham return return_error; 93b5796cb4SJim Ingham } 94b5796cb4SJim Ingham 95738af7a6SJim Ingham Status ScriptInterpreter::SetBreakpointCommandCallbackFunction( 96acdda134SJonas Devlieghere std::vector<BreakpointOptions *> &bp_options_vec, const char *function_name, 97738af7a6SJim Ingham StructuredData::ObjectSP extra_args_sp) { 98738af7a6SJim Ingham Status error; 99b9c1b51eSKate Stone for (BreakpointOptions *bp_options : bp_options_vec) { 100738af7a6SJim Ingham error = SetBreakpointCommandCallbackFunction(bp_options, function_name, 101738af7a6SJim Ingham extra_args_sp); 102738af7a6SJim Ingham if (!error.Success()) 103738af7a6SJim Ingham return error; 104b5796cb4SJim Ingham } 105738af7a6SJim Ingham return error; 106b5796cb4SJim Ingham } 107b5796cb4SJim Ingham 1087b0992d9SGreg Clayton std::unique_ptr<ScriptInterpreterLocker> 109b9c1b51eSKate Stone ScriptInterpreter::AcquireInterpreterLock() { 11006412daeSJonas Devlieghere return std::make_unique<ScriptInterpreterLocker>(); 111360cc318SEnrico Granata } 112d79273c9SJonas Devlieghere 113d79273c9SJonas Devlieghere static void ReadThreadBytesReceived(void *baton, const void *src, 114d79273c9SJonas Devlieghere size_t src_len) { 115d79273c9SJonas Devlieghere if (src && src_len) { 116d79273c9SJonas Devlieghere Stream *strm = (Stream *)baton; 117d79273c9SJonas Devlieghere strm->Write(src, src_len); 118d79273c9SJonas Devlieghere strm->Flush(); 119d79273c9SJonas Devlieghere } 120d79273c9SJonas Devlieghere } 121d79273c9SJonas Devlieghere 122d79273c9SJonas Devlieghere llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 12384228365SJonas Devlieghere ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger, 12484228365SJonas Devlieghere CommandReturnObject *result) { 12584228365SJonas Devlieghere if (enable_io) 12684228365SJonas Devlieghere return std::unique_ptr<ScriptInterpreterIORedirect>( 12784228365SJonas Devlieghere new ScriptInterpreterIORedirect(debugger, result)); 12884228365SJonas Devlieghere 129d79273c9SJonas Devlieghere auto nullin = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL), 130d79273c9SJonas Devlieghere File::eOpenOptionRead); 131d79273c9SJonas Devlieghere if (!nullin) 132d79273c9SJonas Devlieghere return nullin.takeError(); 133d79273c9SJonas Devlieghere 134d79273c9SJonas Devlieghere auto nullout = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL), 135d79273c9SJonas Devlieghere File::eOpenOptionWrite); 136d79273c9SJonas Devlieghere if (!nullout) 137d79273c9SJonas Devlieghere return nullin.takeError(); 138d79273c9SJonas Devlieghere 139d79273c9SJonas Devlieghere return std::unique_ptr<ScriptInterpreterIORedirect>( 140d79273c9SJonas Devlieghere new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout))); 141d79273c9SJonas Devlieghere } 142d79273c9SJonas Devlieghere 143d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( 144d79273c9SJonas Devlieghere std::unique_ptr<File> input, std::unique_ptr<File> output) 145d79273c9SJonas Devlieghere : m_input_file_sp(std::move(input)), 146d79273c9SJonas Devlieghere m_output_file_sp(std::make_shared<StreamFile>(std::move(output))), 147d79273c9SJonas Devlieghere m_error_file_sp(m_output_file_sp), 148d79273c9SJonas Devlieghere m_communication("lldb.ScriptInterpreterIORedirect.comm"), 149d79273c9SJonas Devlieghere m_disconnect(false) {} 150d79273c9SJonas Devlieghere 151d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( 152d79273c9SJonas Devlieghere Debugger &debugger, CommandReturnObject *result) 153d79273c9SJonas Devlieghere : m_communication("lldb.ScriptInterpreterIORedirect.comm"), 154d79273c9SJonas Devlieghere m_disconnect(false) { 155d79273c9SJonas Devlieghere 156d79273c9SJonas Devlieghere if (result) { 157d79273c9SJonas Devlieghere m_input_file_sp = debugger.GetInputFileSP(); 158d79273c9SJonas Devlieghere 159d79273c9SJonas Devlieghere Pipe pipe; 160d79273c9SJonas Devlieghere Status pipe_result = pipe.CreateNew(false); 161d79273c9SJonas Devlieghere #if defined(_WIN32) 162d79273c9SJonas Devlieghere lldb::file_t read_file = pipe.GetReadNativeHandle(); 163d79273c9SJonas Devlieghere pipe.ReleaseReadFileDescriptor(); 164d79273c9SJonas Devlieghere std::unique_ptr<ConnectionGenericFile> conn_up = 165d79273c9SJonas Devlieghere std::make_unique<ConnectionGenericFile>(read_file, true); 166d79273c9SJonas Devlieghere #else 167d79273c9SJonas Devlieghere std::unique_ptr<ConnectionFileDescriptor> conn_up = 168d79273c9SJonas Devlieghere std::make_unique<ConnectionFileDescriptor>( 169d79273c9SJonas Devlieghere pipe.ReleaseReadFileDescriptor(), true); 170d79273c9SJonas Devlieghere #endif 171d79273c9SJonas Devlieghere 172d79273c9SJonas Devlieghere if (conn_up->IsConnected()) { 173d79273c9SJonas Devlieghere m_communication.SetConnection(std::move(conn_up)); 174d79273c9SJonas Devlieghere m_communication.SetReadThreadBytesReceivedCallback( 175d79273c9SJonas Devlieghere ReadThreadBytesReceived, &result->GetOutputStream()); 176d79273c9SJonas Devlieghere m_communication.StartReadThread(); 177d79273c9SJonas Devlieghere m_disconnect = true; 178d79273c9SJonas Devlieghere 179d79273c9SJonas Devlieghere FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w"); 180d79273c9SJonas Devlieghere m_output_file_sp = std::make_shared<StreamFile>(outfile_handle, true); 181d79273c9SJonas Devlieghere m_error_file_sp = m_output_file_sp; 182d79273c9SJonas Devlieghere if (outfile_handle) 183d79273c9SJonas Devlieghere ::setbuf(outfile_handle, nullptr); 184d79273c9SJonas Devlieghere 185d79273c9SJonas Devlieghere result->SetImmediateOutputFile(debugger.GetOutputStream().GetFileSP()); 186d79273c9SJonas Devlieghere result->SetImmediateErrorFile(debugger.GetErrorStream().GetFileSP()); 187d79273c9SJonas Devlieghere } 188d79273c9SJonas Devlieghere } 189d79273c9SJonas Devlieghere 190d79273c9SJonas Devlieghere if (!m_input_file_sp || !m_output_file_sp || !m_error_file_sp) 191d79273c9SJonas Devlieghere debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp, m_output_file_sp, 192d79273c9SJonas Devlieghere m_error_file_sp); 193d79273c9SJonas Devlieghere } 194d79273c9SJonas Devlieghere 195d79273c9SJonas Devlieghere void ScriptInterpreterIORedirect::Flush() { 196d79273c9SJonas Devlieghere if (m_output_file_sp) 197d79273c9SJonas Devlieghere m_output_file_sp->Flush(); 198d79273c9SJonas Devlieghere if (m_error_file_sp) 199d79273c9SJonas Devlieghere m_error_file_sp->Flush(); 200d79273c9SJonas Devlieghere } 201d79273c9SJonas Devlieghere 202d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() { 203d79273c9SJonas Devlieghere if (!m_disconnect) 204d79273c9SJonas Devlieghere return; 205d79273c9SJonas Devlieghere 206d79273c9SJonas Devlieghere assert(m_output_file_sp); 207d79273c9SJonas Devlieghere assert(m_error_file_sp); 208d79273c9SJonas Devlieghere assert(m_output_file_sp == m_error_file_sp); 209d79273c9SJonas Devlieghere 210d79273c9SJonas Devlieghere // Close the write end of the pipe since we are done with our one line 211d79273c9SJonas Devlieghere // script. This should cause the read thread that output_comm is using to 212d79273c9SJonas Devlieghere // exit. 213d79273c9SJonas Devlieghere m_output_file_sp->GetFile().Close(); 214d79273c9SJonas Devlieghere // The close above should cause this thread to exit when it gets to the end 215d79273c9SJonas Devlieghere // of file, so let it get all its data. 216d79273c9SJonas Devlieghere m_communication.JoinReadThread(); 217d79273c9SJonas Devlieghere // Now we can close the read end of the pipe. 218d79273c9SJonas Devlieghere m_communication.Disconnect(); 219d79273c9SJonas Devlieghere } 220