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 2111f2ef4dSJonas Devlieghere #include <memory> 2211f2ef4dSJonas Devlieghere #include <stdio.h> 2311f2ef4dSJonas Devlieghere #include <stdlib.h> 2411f2ef4dSJonas 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 50*00bb397bSJonas Devlieghere bool ScriptInterpreter::LoadScriptingModule(const char *filename, 51*00bb397bSJonas Devlieghere bool init_session, 52*00bb397bSJonas Devlieghere lldb_private::Status &error, 53*00bb397bSJonas Devlieghere StructuredData::ObjectSP *module_sp, 54*00bb397bSJonas Devlieghere FileSpec extra_search_dir) { 55bd5c8d16SJonas Devlieghere error.SetErrorString( 56bd5c8d16SJonas Devlieghere "This script interpreter does not support importing modules."); 57bd5c8d16SJonas Devlieghere return false; 58bd5c8d16SJonas Devlieghere } 59bd5c8d16SJonas Devlieghere 60b9c1b51eSKate Stone std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) { 61b9c1b51eSKate Stone switch (language) { 623df9a8dfSCaroline Tice case eScriptLanguageNone: 63acdda134SJonas Devlieghere return "None"; 643df9a8dfSCaroline Tice case eScriptLanguagePython: 65acdda134SJonas Devlieghere return "Python"; 66acdda134SJonas Devlieghere case eScriptLanguageLua: 67acdda134SJonas Devlieghere return "Lua"; 68f7e07256SJim Ingham case eScriptLanguageUnknown: 69acdda134SJonas Devlieghere return "Unknown"; 703df9a8dfSCaroline Tice } 71fbccef6bSPavel Labath llvm_unreachable("Unhandled ScriptInterpreter!"); 723df9a8dfSCaroline Tice } 732f88aadfSCaroline Tice 74f7e07256SJim Ingham lldb::ScriptLanguage 75f7e07256SJim Ingham ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) { 76f7e07256SJim Ingham if (language.equals_lower(LanguageToString(eScriptLanguageNone))) 77f7e07256SJim Ingham return eScriptLanguageNone; 7845188dd9SDavide Italiano if (language.equals_lower(LanguageToString(eScriptLanguagePython))) 79f7e07256SJim Ingham return eScriptLanguagePython; 80acdda134SJonas Devlieghere if (language.equals_lower(LanguageToString(eScriptLanguageLua))) 81acdda134SJonas Devlieghere return eScriptLanguageLua; 82f7e07256SJim Ingham return eScriptLanguageUnknown; 83f7e07256SJim Ingham } 84f7e07256SJim Ingham 8597206d57SZachary Turner Status ScriptInterpreter::SetBreakpointCommandCallback( 86b9c1b51eSKate Stone std::vector<BreakpointOptions *> &bp_options_vec, 87b9c1b51eSKate Stone const char *callback_text) { 8897206d57SZachary Turner Status return_error; 89b9c1b51eSKate Stone for (BreakpointOptions *bp_options : bp_options_vec) { 90b5796cb4SJim Ingham return_error = SetBreakpointCommandCallback(bp_options, callback_text); 91b5796cb4SJim Ingham if (return_error.Success()) 92b5796cb4SJim Ingham break; 93b5796cb4SJim Ingham } 94b5796cb4SJim Ingham return return_error; 95b5796cb4SJim Ingham } 96b5796cb4SJim Ingham 97738af7a6SJim Ingham Status ScriptInterpreter::SetBreakpointCommandCallbackFunction( 98acdda134SJonas Devlieghere std::vector<BreakpointOptions *> &bp_options_vec, const char *function_name, 99738af7a6SJim Ingham StructuredData::ObjectSP extra_args_sp) { 100738af7a6SJim Ingham Status error; 101b9c1b51eSKate Stone for (BreakpointOptions *bp_options : bp_options_vec) { 102738af7a6SJim Ingham error = SetBreakpointCommandCallbackFunction(bp_options, function_name, 103738af7a6SJim Ingham extra_args_sp); 104738af7a6SJim Ingham if (!error.Success()) 105738af7a6SJim Ingham return error; 106b5796cb4SJim Ingham } 107738af7a6SJim Ingham return error; 108b5796cb4SJim Ingham } 109b5796cb4SJim Ingham 1107b0992d9SGreg Clayton std::unique_ptr<ScriptInterpreterLocker> 111b9c1b51eSKate Stone ScriptInterpreter::AcquireInterpreterLock() { 11206412daeSJonas Devlieghere return std::make_unique<ScriptInterpreterLocker>(); 113360cc318SEnrico Granata } 114d79273c9SJonas Devlieghere 115d79273c9SJonas Devlieghere static void ReadThreadBytesReceived(void *baton, const void *src, 116d79273c9SJonas Devlieghere size_t src_len) { 117d79273c9SJonas Devlieghere if (src && src_len) { 118d79273c9SJonas Devlieghere Stream *strm = (Stream *)baton; 119d79273c9SJonas Devlieghere strm->Write(src, src_len); 120d79273c9SJonas Devlieghere strm->Flush(); 121d79273c9SJonas Devlieghere } 122d79273c9SJonas Devlieghere } 123d79273c9SJonas Devlieghere 124d79273c9SJonas Devlieghere llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 12584228365SJonas Devlieghere ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger, 12684228365SJonas Devlieghere CommandReturnObject *result) { 12784228365SJonas Devlieghere if (enable_io) 12884228365SJonas Devlieghere return std::unique_ptr<ScriptInterpreterIORedirect>( 12984228365SJonas Devlieghere new ScriptInterpreterIORedirect(debugger, result)); 13084228365SJonas Devlieghere 131d79273c9SJonas Devlieghere auto nullin = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL), 132d79273c9SJonas Devlieghere File::eOpenOptionRead); 133d79273c9SJonas Devlieghere if (!nullin) 134d79273c9SJonas Devlieghere return nullin.takeError(); 135d79273c9SJonas Devlieghere 136d79273c9SJonas Devlieghere auto nullout = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL), 137d79273c9SJonas Devlieghere File::eOpenOptionWrite); 138d79273c9SJonas Devlieghere if (!nullout) 139d79273c9SJonas Devlieghere return nullin.takeError(); 140d79273c9SJonas Devlieghere 141d79273c9SJonas Devlieghere return std::unique_ptr<ScriptInterpreterIORedirect>( 142d79273c9SJonas Devlieghere new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout))); 143d79273c9SJonas Devlieghere } 144d79273c9SJonas Devlieghere 145d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( 146d79273c9SJonas Devlieghere std::unique_ptr<File> input, std::unique_ptr<File> output) 147d79273c9SJonas Devlieghere : m_input_file_sp(std::move(input)), 148d79273c9SJonas Devlieghere m_output_file_sp(std::make_shared<StreamFile>(std::move(output))), 149d79273c9SJonas Devlieghere m_error_file_sp(m_output_file_sp), 150d79273c9SJonas Devlieghere m_communication("lldb.ScriptInterpreterIORedirect.comm"), 151d79273c9SJonas Devlieghere m_disconnect(false) {} 152d79273c9SJonas Devlieghere 153d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( 154d79273c9SJonas Devlieghere Debugger &debugger, CommandReturnObject *result) 155d79273c9SJonas Devlieghere : m_communication("lldb.ScriptInterpreterIORedirect.comm"), 156d79273c9SJonas Devlieghere m_disconnect(false) { 157d79273c9SJonas Devlieghere 158d79273c9SJonas Devlieghere if (result) { 159d79273c9SJonas Devlieghere m_input_file_sp = debugger.GetInputFileSP(); 160d79273c9SJonas Devlieghere 161d79273c9SJonas Devlieghere Pipe pipe; 162d79273c9SJonas Devlieghere Status pipe_result = pipe.CreateNew(false); 163d79273c9SJonas Devlieghere #if defined(_WIN32) 164d79273c9SJonas Devlieghere lldb::file_t read_file = pipe.GetReadNativeHandle(); 165d79273c9SJonas Devlieghere pipe.ReleaseReadFileDescriptor(); 166d79273c9SJonas Devlieghere std::unique_ptr<ConnectionGenericFile> conn_up = 167d79273c9SJonas Devlieghere std::make_unique<ConnectionGenericFile>(read_file, true); 168d79273c9SJonas Devlieghere #else 169d79273c9SJonas Devlieghere std::unique_ptr<ConnectionFileDescriptor> conn_up = 170d79273c9SJonas Devlieghere std::make_unique<ConnectionFileDescriptor>( 171d79273c9SJonas Devlieghere pipe.ReleaseReadFileDescriptor(), true); 172d79273c9SJonas Devlieghere #endif 173d79273c9SJonas Devlieghere 174d79273c9SJonas Devlieghere if (conn_up->IsConnected()) { 175d79273c9SJonas Devlieghere m_communication.SetConnection(std::move(conn_up)); 176d79273c9SJonas Devlieghere m_communication.SetReadThreadBytesReceivedCallback( 177d79273c9SJonas Devlieghere ReadThreadBytesReceived, &result->GetOutputStream()); 178d79273c9SJonas Devlieghere m_communication.StartReadThread(); 179d79273c9SJonas Devlieghere m_disconnect = true; 180d79273c9SJonas Devlieghere 181d79273c9SJonas Devlieghere FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w"); 182d79273c9SJonas Devlieghere m_output_file_sp = std::make_shared<StreamFile>(outfile_handle, true); 183d79273c9SJonas Devlieghere m_error_file_sp = m_output_file_sp; 184d79273c9SJonas Devlieghere if (outfile_handle) 185d79273c9SJonas Devlieghere ::setbuf(outfile_handle, nullptr); 186d79273c9SJonas Devlieghere 187d79273c9SJonas Devlieghere result->SetImmediateOutputFile(debugger.GetOutputStream().GetFileSP()); 188d79273c9SJonas Devlieghere result->SetImmediateErrorFile(debugger.GetErrorStream().GetFileSP()); 189d79273c9SJonas Devlieghere } 190d79273c9SJonas Devlieghere } 191d79273c9SJonas Devlieghere 192d79273c9SJonas Devlieghere if (!m_input_file_sp || !m_output_file_sp || !m_error_file_sp) 193d79273c9SJonas Devlieghere debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp, m_output_file_sp, 194d79273c9SJonas Devlieghere m_error_file_sp); 195d79273c9SJonas Devlieghere } 196d79273c9SJonas Devlieghere 197d79273c9SJonas Devlieghere void ScriptInterpreterIORedirect::Flush() { 198d79273c9SJonas Devlieghere if (m_output_file_sp) 199d79273c9SJonas Devlieghere m_output_file_sp->Flush(); 200d79273c9SJonas Devlieghere if (m_error_file_sp) 201d79273c9SJonas Devlieghere m_error_file_sp->Flush(); 202d79273c9SJonas Devlieghere } 203d79273c9SJonas Devlieghere 204d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() { 205d79273c9SJonas Devlieghere if (!m_disconnect) 206d79273c9SJonas Devlieghere return; 207d79273c9SJonas Devlieghere 208d79273c9SJonas Devlieghere assert(m_output_file_sp); 209d79273c9SJonas Devlieghere assert(m_error_file_sp); 210d79273c9SJonas Devlieghere assert(m_output_file_sp == m_error_file_sp); 211d79273c9SJonas Devlieghere 212d79273c9SJonas Devlieghere // Close the write end of the pipe since we are done with our one line 213d79273c9SJonas Devlieghere // script. This should cause the read thread that output_comm is using to 214d79273c9SJonas Devlieghere // exit. 215d79273c9SJonas Devlieghere m_output_file_sp->GetFile().Close(); 216d79273c9SJonas Devlieghere // The close above should cause this thread to exit when it gets to the end 217d79273c9SJonas Devlieghere // of file, so let it get all its data. 218d79273c9SJonas Devlieghere m_communication.JoinReadThread(); 219d79273c9SJonas Devlieghere // Now we can close the read end of the pipe. 220d79273c9SJonas Devlieghere m_communication.Disconnect(); 221d79273c9SJonas Devlieghere } 222