1 //===-- ScriptInterpreter.cpp ---------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Interpreter/ScriptInterpreter.h"
10 #include "lldb/Core/Debugger.h"
11 #include "lldb/Host/ConnectionFileDescriptor.h"
12 #include "lldb/Host/Pipe.h"
13 #include "lldb/Host/PseudoTerminal.h"
14 #include "lldb/Interpreter/CommandReturnObject.h"
15 #include "lldb/Utility/Status.h"
16 #include "lldb/Utility/Stream.h"
17 #include "lldb/Utility/StringList.h"
19 #include "lldb/Host/windows/ConnectionGenericFileWindows.h"
27 using namespace lldb_private;
29 ScriptInterpreter::ScriptInterpreter(
30 Debugger &debugger, lldb::ScriptLanguage script_lang,
31 lldb::ScriptedProcessInterfaceUP scripted_process_interface_up)
32 : m_debugger(debugger), m_script_lang(script_lang),
33 m_scripted_process_interface_up(
34 std::move(scripted_process_interface_up)) {}
36 void ScriptInterpreter::CollectDataForBreakpointCommandCallback(
37 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
38 CommandReturnObject &result) {
40 "This script interpreter does not support breakpoint callbacks.");
43 void ScriptInterpreter::CollectDataForWatchpointCommandCallback(
44 WatchpointOptions *bp_options, CommandReturnObject &result) {
46 "This script interpreter does not support watchpoint callbacks.");
49 StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() {
53 bool ScriptInterpreter::LoadScriptingModule(const char *filename,
54 const LoadScriptOptions &options,
55 lldb_private::Status &error,
56 StructuredData::ObjectSP *module_sp,
57 FileSpec extra_search_dir) {
59 "This script interpreter does not support importing modules.");
63 std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) {
65 case eScriptLanguageNone:
67 case eScriptLanguagePython:
69 case eScriptLanguageLua:
71 case eScriptLanguageUnknown:
74 llvm_unreachable("Unhandled ScriptInterpreter!");
78 ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData &data) const {
79 return data.m_opaque_sp;
83 ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
84 if (error.m_opaque_up)
85 return *error.m_opaque_up.get();
90 llvm::Optional<MemoryRegionInfo>
91 ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
92 const lldb::SBMemoryRegionInfo &mem_region) const {
93 if (!mem_region.m_opaque_up)
95 return *mem_region.m_opaque_up.get();
99 ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
100 if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))
101 return eScriptLanguageNone;
102 if (language.equals_insensitive(LanguageToString(eScriptLanguagePython)))
103 return eScriptLanguagePython;
104 if (language.equals_insensitive(LanguageToString(eScriptLanguageLua)))
105 return eScriptLanguageLua;
106 return eScriptLanguageUnknown;
109 Status ScriptInterpreter::SetBreakpointCommandCallback(
110 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
111 const char *callback_text) {
113 for (BreakpointOptions &bp_options : bp_options_vec) {
114 return_error = SetBreakpointCommandCallback(bp_options, callback_text);
115 if (return_error.Success())
121 Status ScriptInterpreter::SetBreakpointCommandCallbackFunction(
122 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
123 const char *function_name, StructuredData::ObjectSP extra_args_sp) {
125 for (BreakpointOptions &bp_options : bp_options_vec) {
126 error = SetBreakpointCommandCallbackFunction(bp_options, function_name,
128 if (!error.Success())
134 std::unique_ptr<ScriptInterpreterLocker>
135 ScriptInterpreter::AcquireInterpreterLock() {
136 return std::make_unique<ScriptInterpreterLocker>();
139 static void ReadThreadBytesReceived(void *baton, const void *src,
141 if (src && src_len) {
142 Stream *strm = (Stream *)baton;
143 strm->Write(src, src_len);
148 llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
149 ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger,
150 CommandReturnObject *result) {
152 return std::unique_ptr<ScriptInterpreterIORedirect>(
153 new ScriptInterpreterIORedirect(debugger, result));
155 auto nullin = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
156 File::eOpenOptionReadOnly);
158 return nullin.takeError();
160 auto nullout = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
161 File::eOpenOptionWriteOnly);
163 return nullin.takeError();
165 return std::unique_ptr<ScriptInterpreterIORedirect>(
166 new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout)));
169 ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
170 std::unique_ptr<File> input, std::unique_ptr<File> output)
171 : m_input_file_sp(std::move(input)),
172 m_output_file_sp(std::make_shared<StreamFile>(std::move(output))),
173 m_error_file_sp(m_output_file_sp),
174 m_communication("lldb.ScriptInterpreterIORedirect.comm"),
175 m_disconnect(false) {}
177 ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
178 Debugger &debugger, CommandReturnObject *result)
179 : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
180 m_disconnect(false) {
183 m_input_file_sp = debugger.GetInputFileSP();
186 Status pipe_result = pipe.CreateNew(false);
188 lldb::file_t read_file = pipe.GetReadNativeHandle();
189 pipe.ReleaseReadFileDescriptor();
190 std::unique_ptr<ConnectionGenericFile> conn_up =
191 std::make_unique<ConnectionGenericFile>(read_file, true);
193 std::unique_ptr<ConnectionFileDescriptor> conn_up =
194 std::make_unique<ConnectionFileDescriptor>(
195 pipe.ReleaseReadFileDescriptor(), true);
198 if (conn_up->IsConnected()) {
199 m_communication.SetConnection(std::move(conn_up));
200 m_communication.SetReadThreadBytesReceivedCallback(
201 ReadThreadBytesReceived, &result->GetOutputStream());
202 m_communication.StartReadThread();
205 FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w");
206 m_output_file_sp = std::make_shared<StreamFile>(outfile_handle, true);
207 m_error_file_sp = m_output_file_sp;
209 ::setbuf(outfile_handle, nullptr);
211 result->SetImmediateOutputFile(debugger.GetOutputStream().GetFileSP());
212 result->SetImmediateErrorFile(debugger.GetErrorStream().GetFileSP());
216 if (!m_input_file_sp || !m_output_file_sp || !m_error_file_sp)
217 debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp, m_output_file_sp,
221 void ScriptInterpreterIORedirect::Flush() {
222 if (m_output_file_sp)
223 m_output_file_sp->Flush();
225 m_error_file_sp->Flush();
228 ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() {
232 assert(m_output_file_sp);
233 assert(m_error_file_sp);
234 assert(m_output_file_sp == m_error_file_sp);
236 // Close the write end of the pipe since we are done with our one line
237 // script. This should cause the read thread that output_comm is using to
239 m_output_file_sp->GetFile().Close();
240 // The close above should cause this thread to exit when it gets to the end
241 // of file, so let it get all its data.
242 m_communication.JoinReadThread();
243 // Now we can close the read end of the pipe.
244 m_communication.Disconnect();