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
2176e47d48SRaphael Isemann #include <cstdio>
2276e47d48SRaphael Isemann #include <cstdlib>
2311f2ef4dSJonas Devlieghere #include <memory>
2411f2ef4dSJonas Devlieghere #include <string>
2530fdc8d8SChris Lattner
2630fdc8d8SChris Lattner using namespace lldb;
2730fdc8d8SChris Lattner using namespace lldb_private;
2830fdc8d8SChris Lattner
ScriptInterpreter(Debugger & debugger,lldb::ScriptLanguage script_lang,lldb::ScriptedProcessInterfaceUP scripted_process_interface_up)291f6a57c1SMed Ismail Bennani ScriptInterpreter::ScriptInterpreter(
301f6a57c1SMed Ismail Bennani Debugger &debugger, lldb::ScriptLanguage script_lang,
311f6a57c1SMed Ismail Bennani lldb::ScriptedProcessInterfaceUP scripted_process_interface_up)
321f6a57c1SMed Ismail Bennani : m_debugger(debugger), m_script_lang(script_lang),
331f6a57c1SMed Ismail Bennani m_scripted_process_interface_up(
341f6a57c1SMed Ismail Bennani std::move(scripted_process_interface_up)) {}
3530fdc8d8SChris Lattner
CollectDataForBreakpointCommandCallback(std::vector<std::reference_wrapper<BreakpointOptions>> & bp_options_vec,CommandReturnObject & result)36b9c1b51eSKate Stone void ScriptInterpreter::CollectDataForBreakpointCommandCallback(
37cfb96d84SJim Ingham std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
38b9c1b51eSKate Stone CommandReturnObject &result) {
39b9c1b51eSKate Stone result.AppendError(
40ba0eb7b6SJonas Devlieghere "This script interpreter does not support breakpoint callbacks.");
4130fdc8d8SChris Lattner }
4230fdc8d8SChris Lattner
CollectDataForWatchpointCommandCallback(WatchpointOptions * bp_options,CommandReturnObject & result)43b9c1b51eSKate Stone void ScriptInterpreter::CollectDataForWatchpointCommandCallback(
44b9c1b51eSKate Stone WatchpointOptions *bp_options, CommandReturnObject &result) {
45b9c1b51eSKate Stone result.AppendError(
46ba0eb7b6SJonas Devlieghere "This script interpreter does not support watchpoint callbacks.");
47e9a5627eSJohnny Chen }
48e9a5627eSJohnny Chen
GetInterpreterInfo()49bbef51ebSLawrence D'Anna StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() {
50bbef51ebSLawrence D'Anna return nullptr;
51bbef51ebSLawrence D'Anna }
52bbef51ebSLawrence D'Anna
LoadScriptingModule(const char * filename,const LoadScriptOptions & options,lldb_private::Status & error,StructuredData::ObjectSP * module_sp,FileSpec extra_search_dir)5300bb397bSJonas Devlieghere bool ScriptInterpreter::LoadScriptingModule(const char *filename,
54f9517353SJonas Devlieghere const LoadScriptOptions &options,
5500bb397bSJonas Devlieghere lldb_private::Status &error,
5600bb397bSJonas Devlieghere StructuredData::ObjectSP *module_sp,
5700bb397bSJonas Devlieghere FileSpec extra_search_dir) {
58bd5c8d16SJonas Devlieghere error.SetErrorString(
59bd5c8d16SJonas Devlieghere "This script interpreter does not support importing modules.");
60bd5c8d16SJonas Devlieghere return false;
61bd5c8d16SJonas Devlieghere }
62bd5c8d16SJonas Devlieghere
LanguageToString(lldb::ScriptLanguage language)63b9c1b51eSKate Stone std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) {
64b9c1b51eSKate Stone switch (language) {
653df9a8dfSCaroline Tice case eScriptLanguageNone:
66acdda134SJonas Devlieghere return "None";
673df9a8dfSCaroline Tice case eScriptLanguagePython:
68acdda134SJonas Devlieghere return "Python";
69acdda134SJonas Devlieghere case eScriptLanguageLua:
70acdda134SJonas Devlieghere return "Lua";
71f7e07256SJim Ingham case eScriptLanguageUnknown:
72acdda134SJonas Devlieghere return "Unknown";
733df9a8dfSCaroline Tice }
74fbccef6bSPavel Labath llvm_unreachable("Unhandled ScriptInterpreter!");
753df9a8dfSCaroline Tice }
762f88aadfSCaroline Tice
771f6a57c1SMed Ismail Bennani lldb::DataExtractorSP
GetDataExtractorFromSBData(const lldb::SBData & data) const781f6a57c1SMed Ismail Bennani ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData &data) const {
791f6a57c1SMed Ismail Bennani return data.m_opaque_sp;
801f6a57c1SMed Ismail Bennani }
811f6a57c1SMed Ismail Bennani
821f6a57c1SMed Ismail Bennani Status
GetStatusFromSBError(const lldb::SBError & error) const831f6a57c1SMed Ismail Bennani ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
841f6a57c1SMed Ismail Bennani if (error.m_opaque_up)
851f6a57c1SMed Ismail Bennani return *error.m_opaque_up.get();
861f6a57c1SMed Ismail Bennani
871f6a57c1SMed Ismail Bennani return Status();
881f6a57c1SMed Ismail Bennani }
891f6a57c1SMed Ismail Bennani
90a758c9f7SMed Ismail Bennani llvm::Optional<MemoryRegionInfo>
GetOpaqueTypeFromSBMemoryRegionInfo(const lldb::SBMemoryRegionInfo & mem_region) const91a758c9f7SMed Ismail Bennani ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
92a758c9f7SMed Ismail Bennani const lldb::SBMemoryRegionInfo &mem_region) const {
93a758c9f7SMed Ismail Bennani if (!mem_region.m_opaque_up)
94a758c9f7SMed Ismail Bennani return llvm::None;
95a758c9f7SMed Ismail Bennani return *mem_region.m_opaque_up.get();
96a758c9f7SMed Ismail Bennani }
97a758c9f7SMed Ismail Bennani
98f7e07256SJim Ingham lldb::ScriptLanguage
StringToLanguage(const llvm::StringRef & language)99f7e07256SJim Ingham ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
100e50f9c41SMartin Storsjö if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))
101f7e07256SJim Ingham return eScriptLanguageNone;
102e50f9c41SMartin Storsjö if (language.equals_insensitive(LanguageToString(eScriptLanguagePython)))
103f7e07256SJim Ingham return eScriptLanguagePython;
104e50f9c41SMartin Storsjö if (language.equals_insensitive(LanguageToString(eScriptLanguageLua)))
105acdda134SJonas Devlieghere return eScriptLanguageLua;
106f7e07256SJim Ingham return eScriptLanguageUnknown;
107f7e07256SJim Ingham }
108f7e07256SJim Ingham
SetBreakpointCommandCallback(std::vector<std::reference_wrapper<BreakpointOptions>> & bp_options_vec,const char * callback_text)10997206d57SZachary Turner Status ScriptInterpreter::SetBreakpointCommandCallback(
110cfb96d84SJim Ingham std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
111b9c1b51eSKate Stone const char *callback_text) {
112*d92f7f79SJim Ingham Status error;
113cfb96d84SJim Ingham for (BreakpointOptions &bp_options : bp_options_vec) {
114*d92f7f79SJim Ingham error = SetBreakpointCommandCallback(bp_options, callback_text);
115*d92f7f79SJim Ingham if (!error.Success())
116b5796cb4SJim Ingham break;
117b5796cb4SJim Ingham }
118*d92f7f79SJim Ingham return error;
119b5796cb4SJim Ingham }
120b5796cb4SJim Ingham
SetBreakpointCommandCallbackFunction(std::vector<std::reference_wrapper<BreakpointOptions>> & bp_options_vec,const char * function_name,StructuredData::ObjectSP extra_args_sp)121738af7a6SJim Ingham Status ScriptInterpreter::SetBreakpointCommandCallbackFunction(
122cfb96d84SJim Ingham std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
123cfb96d84SJim Ingham const char *function_name, StructuredData::ObjectSP extra_args_sp) {
124738af7a6SJim Ingham Status error;
125cfb96d84SJim Ingham for (BreakpointOptions &bp_options : bp_options_vec) {
126738af7a6SJim Ingham error = SetBreakpointCommandCallbackFunction(bp_options, function_name,
127738af7a6SJim Ingham extra_args_sp);
128738af7a6SJim Ingham if (!error.Success())
129738af7a6SJim Ingham return error;
130b5796cb4SJim Ingham }
131738af7a6SJim Ingham return error;
132b5796cb4SJim Ingham }
133b5796cb4SJim Ingham
1347b0992d9SGreg Clayton std::unique_ptr<ScriptInterpreterLocker>
AcquireInterpreterLock()135b9c1b51eSKate Stone ScriptInterpreter::AcquireInterpreterLock() {
13606412daeSJonas Devlieghere return std::make_unique<ScriptInterpreterLocker>();
137360cc318SEnrico Granata }
138d79273c9SJonas Devlieghere
ReadThreadBytesReceived(void * baton,const void * src,size_t src_len)139d79273c9SJonas Devlieghere static void ReadThreadBytesReceived(void *baton, const void *src,
140d79273c9SJonas Devlieghere size_t src_len) {
141d79273c9SJonas Devlieghere if (src && src_len) {
142d79273c9SJonas Devlieghere Stream *strm = (Stream *)baton;
143d79273c9SJonas Devlieghere strm->Write(src, src_len);
144d79273c9SJonas Devlieghere strm->Flush();
145d79273c9SJonas Devlieghere }
146d79273c9SJonas Devlieghere }
147d79273c9SJonas Devlieghere
148d79273c9SJonas Devlieghere llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
Create(bool enable_io,Debugger & debugger,CommandReturnObject * result)14984228365SJonas Devlieghere ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger,
15084228365SJonas Devlieghere CommandReturnObject *result) {
15184228365SJonas Devlieghere if (enable_io)
15284228365SJonas Devlieghere return std::unique_ptr<ScriptInterpreterIORedirect>(
15384228365SJonas Devlieghere new ScriptInterpreterIORedirect(debugger, result));
15484228365SJonas Devlieghere
155d79273c9SJonas Devlieghere auto nullin = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
15614735cabSMichał Górny File::eOpenOptionReadOnly);
157d79273c9SJonas Devlieghere if (!nullin)
158d79273c9SJonas Devlieghere return nullin.takeError();
159d79273c9SJonas Devlieghere
160d79273c9SJonas Devlieghere auto nullout = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
16114735cabSMichał Górny File::eOpenOptionWriteOnly);
162d79273c9SJonas Devlieghere if (!nullout)
163d79273c9SJonas Devlieghere return nullin.takeError();
164d79273c9SJonas Devlieghere
165d79273c9SJonas Devlieghere return std::unique_ptr<ScriptInterpreterIORedirect>(
166d79273c9SJonas Devlieghere new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout)));
167d79273c9SJonas Devlieghere }
168d79273c9SJonas Devlieghere
ScriptInterpreterIORedirect(std::unique_ptr<File> input,std::unique_ptr<File> output)169d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
170d79273c9SJonas Devlieghere std::unique_ptr<File> input, std::unique_ptr<File> output)
171d79273c9SJonas Devlieghere : m_input_file_sp(std::move(input)),
172d79273c9SJonas Devlieghere m_output_file_sp(std::make_shared<StreamFile>(std::move(output))),
173d79273c9SJonas Devlieghere m_error_file_sp(m_output_file_sp),
174d79273c9SJonas Devlieghere m_communication("lldb.ScriptInterpreterIORedirect.comm"),
175d79273c9SJonas Devlieghere m_disconnect(false) {}
176d79273c9SJonas Devlieghere
ScriptInterpreterIORedirect(Debugger & debugger,CommandReturnObject * result)177d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
178d79273c9SJonas Devlieghere Debugger &debugger, CommandReturnObject *result)
179d79273c9SJonas Devlieghere : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
180d79273c9SJonas Devlieghere m_disconnect(false) {
181d79273c9SJonas Devlieghere
182d79273c9SJonas Devlieghere if (result) {
183d79273c9SJonas Devlieghere m_input_file_sp = debugger.GetInputFileSP();
184d79273c9SJonas Devlieghere
185d79273c9SJonas Devlieghere Pipe pipe;
186d79273c9SJonas Devlieghere Status pipe_result = pipe.CreateNew(false);
187d79273c9SJonas Devlieghere #if defined(_WIN32)
188d79273c9SJonas Devlieghere lldb::file_t read_file = pipe.GetReadNativeHandle();
189d79273c9SJonas Devlieghere pipe.ReleaseReadFileDescriptor();
190d79273c9SJonas Devlieghere std::unique_ptr<ConnectionGenericFile> conn_up =
191d79273c9SJonas Devlieghere std::make_unique<ConnectionGenericFile>(read_file, true);
192d79273c9SJonas Devlieghere #else
193d79273c9SJonas Devlieghere std::unique_ptr<ConnectionFileDescriptor> conn_up =
194d79273c9SJonas Devlieghere std::make_unique<ConnectionFileDescriptor>(
195d79273c9SJonas Devlieghere pipe.ReleaseReadFileDescriptor(), true);
196d79273c9SJonas Devlieghere #endif
197d79273c9SJonas Devlieghere
198d79273c9SJonas Devlieghere if (conn_up->IsConnected()) {
199d79273c9SJonas Devlieghere m_communication.SetConnection(std::move(conn_up));
200d79273c9SJonas Devlieghere m_communication.SetReadThreadBytesReceivedCallback(
201d79273c9SJonas Devlieghere ReadThreadBytesReceived, &result->GetOutputStream());
202d79273c9SJonas Devlieghere m_communication.StartReadThread();
203d79273c9SJonas Devlieghere m_disconnect = true;
204d79273c9SJonas Devlieghere
205d79273c9SJonas Devlieghere FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w");
206d79273c9SJonas Devlieghere m_output_file_sp = std::make_shared<StreamFile>(outfile_handle, true);
207d79273c9SJonas Devlieghere m_error_file_sp = m_output_file_sp;
208d79273c9SJonas Devlieghere if (outfile_handle)
209d79273c9SJonas Devlieghere ::setbuf(outfile_handle, nullptr);
210d79273c9SJonas Devlieghere
211d79273c9SJonas Devlieghere result->SetImmediateOutputFile(debugger.GetOutputStream().GetFileSP());
212d79273c9SJonas Devlieghere result->SetImmediateErrorFile(debugger.GetErrorStream().GetFileSP());
213d79273c9SJonas Devlieghere }
214d79273c9SJonas Devlieghere }
215d79273c9SJonas Devlieghere
216d79273c9SJonas Devlieghere if (!m_input_file_sp || !m_output_file_sp || !m_error_file_sp)
217d79273c9SJonas Devlieghere debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp, m_output_file_sp,
218d79273c9SJonas Devlieghere m_error_file_sp);
219d79273c9SJonas Devlieghere }
220d79273c9SJonas Devlieghere
Flush()221d79273c9SJonas Devlieghere void ScriptInterpreterIORedirect::Flush() {
222d79273c9SJonas Devlieghere if (m_output_file_sp)
223d79273c9SJonas Devlieghere m_output_file_sp->Flush();
224d79273c9SJonas Devlieghere if (m_error_file_sp)
225d79273c9SJonas Devlieghere m_error_file_sp->Flush();
226d79273c9SJonas Devlieghere }
227d79273c9SJonas Devlieghere
~ScriptInterpreterIORedirect()228d79273c9SJonas Devlieghere ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() {
229d79273c9SJonas Devlieghere if (!m_disconnect)
230d79273c9SJonas Devlieghere return;
231d79273c9SJonas Devlieghere
232d79273c9SJonas Devlieghere assert(m_output_file_sp);
233d79273c9SJonas Devlieghere assert(m_error_file_sp);
234d79273c9SJonas Devlieghere assert(m_output_file_sp == m_error_file_sp);
235d79273c9SJonas Devlieghere
236d79273c9SJonas Devlieghere // Close the write end of the pipe since we are done with our one line
237d79273c9SJonas Devlieghere // script. This should cause the read thread that output_comm is using to
238d79273c9SJonas Devlieghere // exit.
239d79273c9SJonas Devlieghere m_output_file_sp->GetFile().Close();
240d79273c9SJonas Devlieghere // The close above should cause this thread to exit when it gets to the end
241d79273c9SJonas Devlieghere // of file, so let it get all its data.
242d79273c9SJonas Devlieghere m_communication.JoinReadThread();
243d79273c9SJonas Devlieghere // Now we can close the read end of the pipe.
244d79273c9SJonas Devlieghere m_communication.Disconnect();
245d79273c9SJonas Devlieghere }
246