xref: /freebsd-src/contrib/llvm-project/lldb/source/Interpreter/ScriptInterpreter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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