15ffd83dbSDimitry Andric //===-- ScriptInterpreter.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 90b57cec5SDimitry Andric #include "lldb/Interpreter/ScriptInterpreter.h" 105ffd83dbSDimitry Andric #include "lldb/Core/Debugger.h" 115ffd83dbSDimitry Andric #include "lldb/Host/ConnectionFileDescriptor.h" 125ffd83dbSDimitry Andric #include "lldb/Host/Pipe.h" 130b57cec5SDimitry Andric #include "lldb/Host/PseudoTerminal.h" 140b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h" 150b57cec5SDimitry Andric #include "lldb/Utility/Status.h" 160b57cec5SDimitry Andric #include "lldb/Utility/Stream.h" 170b57cec5SDimitry Andric #include "lldb/Utility/StringList.h" 185ffd83dbSDimitry Andric #if defined(_WIN32) 195ffd83dbSDimitry Andric #include "lldb/Host/windows/ConnectionGenericFileWindows.h" 205ffd83dbSDimitry Andric #endif 21fe6060f1SDimitry Andric #include <cstdio> 22fe6060f1SDimitry Andric #include <cstdlib> 235ffd83dbSDimitry Andric #include <memory> 24bdd1243dSDimitry Andric #include <optional> 255ffd83dbSDimitry Andric #include <string> 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace lldb; 280b57cec5SDimitry Andric using namespace lldb_private; 290b57cec5SDimitry Andric 305f757f3fSDimitry Andric ScriptInterpreter::ScriptInterpreter(Debugger &debugger, 315f757f3fSDimitry Andric lldb::ScriptLanguage script_lang) 325f757f3fSDimitry Andric : m_debugger(debugger), m_script_lang(script_lang) {} 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric void ScriptInterpreter::CollectDataForBreakpointCommandCallback( 35fe6060f1SDimitry Andric std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, 360b57cec5SDimitry Andric CommandReturnObject &result) { 370b57cec5SDimitry Andric result.AppendError( 38480093f4SDimitry Andric "This script interpreter does not support breakpoint callbacks."); 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric void ScriptInterpreter::CollectDataForWatchpointCommandCallback( 420b57cec5SDimitry Andric WatchpointOptions *bp_options, CommandReturnObject &result) { 430b57cec5SDimitry Andric result.AppendError( 44480093f4SDimitry Andric "This script interpreter does not support watchpoint callbacks."); 45480093f4SDimitry Andric } 46480093f4SDimitry Andric 47349cc55cSDimitry Andric StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() { 48349cc55cSDimitry Andric return nullptr; 49349cc55cSDimitry Andric } 50349cc55cSDimitry Andric 51e8d8bef9SDimitry Andric bool ScriptInterpreter::LoadScriptingModule(const char *filename, 52fe6060f1SDimitry Andric const LoadScriptOptions &options, 53e8d8bef9SDimitry Andric lldb_private::Status &error, 54e8d8bef9SDimitry Andric StructuredData::ObjectSP *module_sp, 55e8d8bef9SDimitry Andric FileSpec extra_search_dir) { 56480093f4SDimitry Andric error.SetErrorString( 57480093f4SDimitry Andric "This script interpreter does not support importing modules."); 58480093f4SDimitry Andric return false; 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) { 620b57cec5SDimitry Andric switch (language) { 630b57cec5SDimitry Andric case eScriptLanguageNone: 64480093f4SDimitry Andric return "None"; 650b57cec5SDimitry Andric case eScriptLanguagePython: 66480093f4SDimitry Andric return "Python"; 67480093f4SDimitry Andric case eScriptLanguageLua: 68480093f4SDimitry Andric return "Lua"; 690b57cec5SDimitry Andric case eScriptLanguageUnknown: 70480093f4SDimitry Andric return "Unknown"; 710b57cec5SDimitry Andric } 72480093f4SDimitry Andric llvm_unreachable("Unhandled ScriptInterpreter!"); 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric 75fe6060f1SDimitry Andric lldb::DataExtractorSP 76fe6060f1SDimitry Andric ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData &data) const { 77fe6060f1SDimitry Andric return data.m_opaque_sp; 78fe6060f1SDimitry Andric } 79fe6060f1SDimitry Andric 8006c3fb27SDimitry Andric lldb::BreakpointSP ScriptInterpreter::GetOpaqueTypeFromSBBreakpoint( 8106c3fb27SDimitry Andric const lldb::SBBreakpoint &breakpoint) const { 8206c3fb27SDimitry Andric return breakpoint.m_opaque_wp.lock(); 8306c3fb27SDimitry Andric } 8406c3fb27SDimitry Andric 8506c3fb27SDimitry Andric lldb::ProcessAttachInfoSP ScriptInterpreter::GetOpaqueTypeFromSBAttachInfo( 8606c3fb27SDimitry Andric const lldb::SBAttachInfo &attach_info) const { 8706c3fb27SDimitry Andric return attach_info.m_opaque_sp; 8806c3fb27SDimitry Andric } 8906c3fb27SDimitry Andric 9006c3fb27SDimitry Andric lldb::ProcessLaunchInfoSP ScriptInterpreter::GetOpaqueTypeFromSBLaunchInfo( 9106c3fb27SDimitry Andric const lldb::SBLaunchInfo &launch_info) const { 9206c3fb27SDimitry Andric return std::make_shared<ProcessLaunchInfo>( 9306c3fb27SDimitry Andric *reinterpret_cast<ProcessLaunchInfo *>(launch_info.m_opaque_sp.get())); 9406c3fb27SDimitry Andric } 9506c3fb27SDimitry Andric 96fe6060f1SDimitry Andric Status 97fe6060f1SDimitry Andric ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const { 98fe6060f1SDimitry Andric if (error.m_opaque_up) 99bdd1243dSDimitry Andric return *error.m_opaque_up; 100fe6060f1SDimitry Andric 101fe6060f1SDimitry Andric return Status(); 102fe6060f1SDimitry Andric } 103fe6060f1SDimitry Andric 104*0fca6ea1SDimitry Andric Event * 105*0fca6ea1SDimitry Andric ScriptInterpreter::GetOpaqueTypeFromSBEvent(const lldb::SBEvent &event) const { 106*0fca6ea1SDimitry Andric return event.m_opaque_ptr; 107*0fca6ea1SDimitry Andric } 108*0fca6ea1SDimitry Andric 109*0fca6ea1SDimitry Andric lldb::StreamSP ScriptInterpreter::GetOpaqueTypeFromSBStream( 110*0fca6ea1SDimitry Andric const lldb::SBStream &stream) const { 111*0fca6ea1SDimitry Andric if (stream.m_opaque_up) { 112*0fca6ea1SDimitry Andric lldb::StreamSP s = std::make_shared<lldb_private::StreamString>(); 113*0fca6ea1SDimitry Andric *s << reinterpret_cast<StreamString *>(stream.m_opaque_up.get())->m_packet; 114*0fca6ea1SDimitry Andric return s; 115*0fca6ea1SDimitry Andric } 116*0fca6ea1SDimitry Andric 117*0fca6ea1SDimitry Andric return nullptr; 118*0fca6ea1SDimitry Andric } 119*0fca6ea1SDimitry Andric 120bdd1243dSDimitry Andric std::optional<MemoryRegionInfo> 121349cc55cSDimitry Andric ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo( 122349cc55cSDimitry Andric const lldb::SBMemoryRegionInfo &mem_region) const { 123349cc55cSDimitry Andric if (!mem_region.m_opaque_up) 124bdd1243dSDimitry Andric return std::nullopt; 125349cc55cSDimitry Andric return *mem_region.m_opaque_up.get(); 126349cc55cSDimitry Andric } 127349cc55cSDimitry Andric 1280b57cec5SDimitry Andric lldb::ScriptLanguage 1290b57cec5SDimitry Andric ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) { 130fe6060f1SDimitry Andric if (language.equals_insensitive(LanguageToString(eScriptLanguageNone))) 1310b57cec5SDimitry Andric return eScriptLanguageNone; 132fe6060f1SDimitry Andric if (language.equals_insensitive(LanguageToString(eScriptLanguagePython))) 1330b57cec5SDimitry Andric return eScriptLanguagePython; 134fe6060f1SDimitry Andric if (language.equals_insensitive(LanguageToString(eScriptLanguageLua))) 135480093f4SDimitry Andric return eScriptLanguageLua; 1360b57cec5SDimitry Andric return eScriptLanguageUnknown; 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric Status ScriptInterpreter::SetBreakpointCommandCallback( 140fe6060f1SDimitry Andric std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, 1410b57cec5SDimitry Andric const char *callback_text) { 14281ad6265SDimitry Andric Status error; 143fe6060f1SDimitry Andric for (BreakpointOptions &bp_options : bp_options_vec) { 14406c3fb27SDimitry Andric error = SetBreakpointCommandCallback(bp_options, callback_text, 14506c3fb27SDimitry Andric /*is_callback=*/false); 14681ad6265SDimitry Andric if (!error.Success()) 1470b57cec5SDimitry Andric break; 1480b57cec5SDimitry Andric } 14981ad6265SDimitry Andric return error; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 152480093f4SDimitry Andric Status ScriptInterpreter::SetBreakpointCommandCallbackFunction( 153fe6060f1SDimitry Andric std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, 154fe6060f1SDimitry Andric const char *function_name, StructuredData::ObjectSP extra_args_sp) { 155480093f4SDimitry Andric Status error; 156fe6060f1SDimitry Andric for (BreakpointOptions &bp_options : bp_options_vec) { 157480093f4SDimitry Andric error = SetBreakpointCommandCallbackFunction(bp_options, function_name, 158480093f4SDimitry Andric extra_args_sp); 159480093f4SDimitry Andric if (!error.Success()) 160480093f4SDimitry Andric return error; 1610b57cec5SDimitry Andric } 162480093f4SDimitry Andric return error; 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric std::unique_ptr<ScriptInterpreterLocker> 1660b57cec5SDimitry Andric ScriptInterpreter::AcquireInterpreterLock() { 1675ffd83dbSDimitry Andric return std::make_unique<ScriptInterpreterLocker>(); 1685ffd83dbSDimitry Andric } 1695ffd83dbSDimitry Andric 1705ffd83dbSDimitry Andric static void ReadThreadBytesReceived(void *baton, const void *src, 1715ffd83dbSDimitry Andric size_t src_len) { 1725ffd83dbSDimitry Andric if (src && src_len) { 1735ffd83dbSDimitry Andric Stream *strm = (Stream *)baton; 1745ffd83dbSDimitry Andric strm->Write(src, src_len); 1755ffd83dbSDimitry Andric strm->Flush(); 1765ffd83dbSDimitry Andric } 1775ffd83dbSDimitry Andric } 1785ffd83dbSDimitry Andric 1795ffd83dbSDimitry Andric llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>> 1805ffd83dbSDimitry Andric ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger, 1815ffd83dbSDimitry Andric CommandReturnObject *result) { 1825ffd83dbSDimitry Andric if (enable_io) 1835ffd83dbSDimitry Andric return std::unique_ptr<ScriptInterpreterIORedirect>( 1845ffd83dbSDimitry Andric new ScriptInterpreterIORedirect(debugger, result)); 1855ffd83dbSDimitry Andric 1865ffd83dbSDimitry Andric auto nullin = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL), 187349cc55cSDimitry Andric File::eOpenOptionReadOnly); 1885ffd83dbSDimitry Andric if (!nullin) 1895ffd83dbSDimitry Andric return nullin.takeError(); 1905ffd83dbSDimitry Andric 1915ffd83dbSDimitry Andric auto nullout = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL), 192349cc55cSDimitry Andric File::eOpenOptionWriteOnly); 1935ffd83dbSDimitry Andric if (!nullout) 1945ffd83dbSDimitry Andric return nullin.takeError(); 1955ffd83dbSDimitry Andric 1965ffd83dbSDimitry Andric return std::unique_ptr<ScriptInterpreterIORedirect>( 1975ffd83dbSDimitry Andric new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout))); 1985ffd83dbSDimitry Andric } 1995ffd83dbSDimitry Andric 2005ffd83dbSDimitry Andric ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( 2015ffd83dbSDimitry Andric std::unique_ptr<File> input, std::unique_ptr<File> output) 2025ffd83dbSDimitry Andric : m_input_file_sp(std::move(input)), 2035ffd83dbSDimitry Andric m_output_file_sp(std::make_shared<StreamFile>(std::move(output))), 2045ffd83dbSDimitry Andric m_error_file_sp(m_output_file_sp), 2055ffd83dbSDimitry Andric m_communication("lldb.ScriptInterpreterIORedirect.comm"), 2065ffd83dbSDimitry Andric m_disconnect(false) {} 2075ffd83dbSDimitry Andric 2085ffd83dbSDimitry Andric ScriptInterpreterIORedirect::ScriptInterpreterIORedirect( 2095ffd83dbSDimitry Andric Debugger &debugger, CommandReturnObject *result) 2105ffd83dbSDimitry Andric : m_communication("lldb.ScriptInterpreterIORedirect.comm"), 2115ffd83dbSDimitry Andric m_disconnect(false) { 2125ffd83dbSDimitry Andric 2135ffd83dbSDimitry Andric if (result) { 2145ffd83dbSDimitry Andric m_input_file_sp = debugger.GetInputFileSP(); 2155ffd83dbSDimitry Andric 2165ffd83dbSDimitry Andric Pipe pipe; 2175ffd83dbSDimitry Andric Status pipe_result = pipe.CreateNew(false); 2185ffd83dbSDimitry Andric #if defined(_WIN32) 2195ffd83dbSDimitry Andric lldb::file_t read_file = pipe.GetReadNativeHandle(); 2205ffd83dbSDimitry Andric pipe.ReleaseReadFileDescriptor(); 2215ffd83dbSDimitry Andric std::unique_ptr<ConnectionGenericFile> conn_up = 2225ffd83dbSDimitry Andric std::make_unique<ConnectionGenericFile>(read_file, true); 2235ffd83dbSDimitry Andric #else 2245ffd83dbSDimitry Andric std::unique_ptr<ConnectionFileDescriptor> conn_up = 2255ffd83dbSDimitry Andric std::make_unique<ConnectionFileDescriptor>( 2265ffd83dbSDimitry Andric pipe.ReleaseReadFileDescriptor(), true); 2275ffd83dbSDimitry Andric #endif 2285ffd83dbSDimitry Andric 2295ffd83dbSDimitry Andric if (conn_up->IsConnected()) { 2305ffd83dbSDimitry Andric m_communication.SetConnection(std::move(conn_up)); 2315ffd83dbSDimitry Andric m_communication.SetReadThreadBytesReceivedCallback( 2325ffd83dbSDimitry Andric ReadThreadBytesReceived, &result->GetOutputStream()); 2335ffd83dbSDimitry Andric m_communication.StartReadThread(); 2345ffd83dbSDimitry Andric m_disconnect = true; 2355ffd83dbSDimitry Andric 2365ffd83dbSDimitry Andric FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w"); 2375ffd83dbSDimitry Andric m_output_file_sp = std::make_shared<StreamFile>(outfile_handle, true); 2385ffd83dbSDimitry Andric m_error_file_sp = m_output_file_sp; 2395ffd83dbSDimitry Andric if (outfile_handle) 2405ffd83dbSDimitry Andric ::setbuf(outfile_handle, nullptr); 2415ffd83dbSDimitry Andric 2425ffd83dbSDimitry Andric result->SetImmediateOutputFile(debugger.GetOutputStream().GetFileSP()); 2435ffd83dbSDimitry Andric result->SetImmediateErrorFile(debugger.GetErrorStream().GetFileSP()); 2445ffd83dbSDimitry Andric } 2455ffd83dbSDimitry Andric } 2465ffd83dbSDimitry Andric 2475ffd83dbSDimitry Andric if (!m_input_file_sp || !m_output_file_sp || !m_error_file_sp) 2485ffd83dbSDimitry Andric debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp, m_output_file_sp, 2495ffd83dbSDimitry Andric m_error_file_sp); 2505ffd83dbSDimitry Andric } 2515ffd83dbSDimitry Andric 2525ffd83dbSDimitry Andric void ScriptInterpreterIORedirect::Flush() { 2535ffd83dbSDimitry Andric if (m_output_file_sp) 2545ffd83dbSDimitry Andric m_output_file_sp->Flush(); 2555ffd83dbSDimitry Andric if (m_error_file_sp) 2565ffd83dbSDimitry Andric m_error_file_sp->Flush(); 2575ffd83dbSDimitry Andric } 2585ffd83dbSDimitry Andric 2595ffd83dbSDimitry Andric ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() { 2605ffd83dbSDimitry Andric if (!m_disconnect) 2615ffd83dbSDimitry Andric return; 2625ffd83dbSDimitry Andric 2635ffd83dbSDimitry Andric assert(m_output_file_sp); 2645ffd83dbSDimitry Andric assert(m_error_file_sp); 2655ffd83dbSDimitry Andric assert(m_output_file_sp == m_error_file_sp); 2665ffd83dbSDimitry Andric 2675ffd83dbSDimitry Andric // Close the write end of the pipe since we are done with our one line 2685ffd83dbSDimitry Andric // script. This should cause the read thread that output_comm is using to 2695ffd83dbSDimitry Andric // exit. 2705ffd83dbSDimitry Andric m_output_file_sp->GetFile().Close(); 2715ffd83dbSDimitry Andric // The close above should cause this thread to exit when it gets to the end 2725ffd83dbSDimitry Andric // of file, so let it get all its data. 2735ffd83dbSDimitry Andric m_communication.JoinReadThread(); 2745ffd83dbSDimitry Andric // Now we can close the read end of the pipe. 2755ffd83dbSDimitry Andric m_communication.Disconnect(); 2760b57cec5SDimitry Andric } 277