1cfca06d7SDimitry Andric //===-- ScriptInterpreter.cpp ---------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste
9f034231aSEd Maste #include "lldb/Interpreter/ScriptInterpreter.h"
10cfca06d7SDimitry Andric #include "lldb/Core/Debugger.h"
11cfca06d7SDimitry Andric #include "lldb/Host/ConnectionFileDescriptor.h"
12cfca06d7SDimitry Andric #include "lldb/Host/Pipe.h"
1374a628f7SDimitry Andric #include "lldb/Host/PseudoTerminal.h"
14f034231aSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
15b76161e4SDimitry Andric #include "lldb/Utility/Status.h"
1674a628f7SDimitry Andric #include "lldb/Utility/Stream.h"
1774a628f7SDimitry Andric #include "lldb/Utility/StringList.h"
18cfca06d7SDimitry Andric #if defined(_WIN32)
19cfca06d7SDimitry Andric #include "lldb/Host/windows/ConnectionGenericFileWindows.h"
20cfca06d7SDimitry Andric #endif
21344a3780SDimitry Andric #include <cstdio>
22344a3780SDimitry Andric #include <cstdlib>
23cfca06d7SDimitry Andric #include <memory>
24e3b55780SDimitry Andric #include <optional>
25cfca06d7SDimitry Andric #include <string>
26f034231aSEd Maste
27f034231aSEd Maste using namespace lldb;
28f034231aSEd Maste using namespace lldb_private;
29f034231aSEd Maste
ScriptInterpreter(Debugger & debugger,lldb::ScriptLanguage script_lang)30b1c73532SDimitry Andric ScriptInterpreter::ScriptInterpreter(Debugger &debugger,
31b1c73532SDimitry Andric lldb::ScriptLanguage script_lang)
32b1c73532SDimitry Andric : m_debugger(debugger), m_script_lang(script_lang) {}
33f034231aSEd Maste
CollectDataForBreakpointCommandCallback(std::vector<std::reference_wrapper<BreakpointOptions>> & bp_options_vec,CommandReturnObject & result)3414f1b3e8SDimitry Andric void ScriptInterpreter::CollectDataForBreakpointCommandCallback(
35344a3780SDimitry Andric std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
3614f1b3e8SDimitry Andric CommandReturnObject &result) {
3714f1b3e8SDimitry Andric result.AppendError(
38706b4fc4SDimitry Andric "This script interpreter does not support breakpoint callbacks.");
39f034231aSEd Maste }
40f034231aSEd Maste
CollectDataForWatchpointCommandCallback(WatchpointOptions * bp_options,CommandReturnObject & result)4114f1b3e8SDimitry Andric void ScriptInterpreter::CollectDataForWatchpointCommandCallback(
4214f1b3e8SDimitry Andric WatchpointOptions *bp_options, CommandReturnObject &result) {
4314f1b3e8SDimitry Andric result.AppendError(
44706b4fc4SDimitry Andric "This script interpreter does not support watchpoint callbacks.");
45706b4fc4SDimitry Andric }
46706b4fc4SDimitry Andric
GetInterpreterInfo()47c0981da4SDimitry Andric StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() {
48c0981da4SDimitry Andric return nullptr;
49c0981da4SDimitry Andric }
50c0981da4SDimitry Andric
LoadScriptingModule(const char * filename,const LoadScriptOptions & options,lldb_private::Status & error,StructuredData::ObjectSP * module_sp,FileSpec extra_search_dir)51b60736ecSDimitry Andric bool ScriptInterpreter::LoadScriptingModule(const char *filename,
52344a3780SDimitry Andric const LoadScriptOptions &options,
53b60736ecSDimitry Andric lldb_private::Status &error,
54b60736ecSDimitry Andric StructuredData::ObjectSP *module_sp,
55b60736ecSDimitry Andric FileSpec extra_search_dir) {
56706b4fc4SDimitry Andric error.SetErrorString(
57706b4fc4SDimitry Andric "This script interpreter does not support importing modules.");
58706b4fc4SDimitry Andric return false;
59f034231aSEd Maste }
60f034231aSEd Maste
LanguageToString(lldb::ScriptLanguage language)6114f1b3e8SDimitry Andric std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) {
6214f1b3e8SDimitry Andric switch (language) {
63f034231aSEd Maste case eScriptLanguageNone:
64706b4fc4SDimitry Andric return "None";
65f034231aSEd Maste case eScriptLanguagePython:
66706b4fc4SDimitry Andric return "Python";
67706b4fc4SDimitry Andric case eScriptLanguageLua:
68706b4fc4SDimitry Andric return "Lua";
6914f1b3e8SDimitry Andric case eScriptLanguageUnknown:
70706b4fc4SDimitry Andric return "Unknown";
71f034231aSEd Maste }
72706b4fc4SDimitry Andric llvm_unreachable("Unhandled ScriptInterpreter!");
73f034231aSEd Maste }
74f034231aSEd Maste
75344a3780SDimitry Andric lldb::DataExtractorSP
GetDataExtractorFromSBData(const lldb::SBData & data) const76344a3780SDimitry Andric ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData &data) const {
77344a3780SDimitry Andric return data.m_opaque_sp;
78344a3780SDimitry Andric }
79344a3780SDimitry Andric
GetOpaqueTypeFromSBBreakpoint(const lldb::SBBreakpoint & breakpoint) const807fa27ce4SDimitry Andric lldb::BreakpointSP ScriptInterpreter::GetOpaqueTypeFromSBBreakpoint(
817fa27ce4SDimitry Andric const lldb::SBBreakpoint &breakpoint) const {
827fa27ce4SDimitry Andric return breakpoint.m_opaque_wp.lock();
837fa27ce4SDimitry Andric }
847fa27ce4SDimitry Andric
GetOpaqueTypeFromSBAttachInfo(const lldb::SBAttachInfo & attach_info) const857fa27ce4SDimitry Andric lldb::ProcessAttachInfoSP ScriptInterpreter::GetOpaqueTypeFromSBAttachInfo(
867fa27ce4SDimitry Andric const lldb::SBAttachInfo &attach_info) const {
877fa27ce4SDimitry Andric return attach_info.m_opaque_sp;
887fa27ce4SDimitry Andric }
897fa27ce4SDimitry Andric
GetOpaqueTypeFromSBLaunchInfo(const lldb::SBLaunchInfo & launch_info) const907fa27ce4SDimitry Andric lldb::ProcessLaunchInfoSP ScriptInterpreter::GetOpaqueTypeFromSBLaunchInfo(
917fa27ce4SDimitry Andric const lldb::SBLaunchInfo &launch_info) const {
927fa27ce4SDimitry Andric return std::make_shared<ProcessLaunchInfo>(
937fa27ce4SDimitry Andric *reinterpret_cast<ProcessLaunchInfo *>(launch_info.m_opaque_sp.get()));
947fa27ce4SDimitry Andric }
957fa27ce4SDimitry Andric
96344a3780SDimitry Andric Status
GetStatusFromSBError(const lldb::SBError & error) const97344a3780SDimitry Andric ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
98344a3780SDimitry Andric if (error.m_opaque_up)
99e3b55780SDimitry Andric return *error.m_opaque_up;
100344a3780SDimitry Andric
101344a3780SDimitry Andric return Status();
102344a3780SDimitry Andric }
103344a3780SDimitry Andric
104ac9a064cSDimitry Andric Event *
GetOpaqueTypeFromSBEvent(const lldb::SBEvent & event) const105ac9a064cSDimitry Andric ScriptInterpreter::GetOpaqueTypeFromSBEvent(const lldb::SBEvent &event) const {
106ac9a064cSDimitry Andric return event.m_opaque_ptr;
107ac9a064cSDimitry Andric }
108ac9a064cSDimitry Andric
GetOpaqueTypeFromSBStream(const lldb::SBStream & stream) const109ac9a064cSDimitry Andric lldb::StreamSP ScriptInterpreter::GetOpaqueTypeFromSBStream(
110ac9a064cSDimitry Andric const lldb::SBStream &stream) const {
111ac9a064cSDimitry Andric if (stream.m_opaque_up) {
112ac9a064cSDimitry Andric lldb::StreamSP s = std::make_shared<lldb_private::StreamString>();
113ac9a064cSDimitry Andric *s << reinterpret_cast<StreamString *>(stream.m_opaque_up.get())->m_packet;
114ac9a064cSDimitry Andric return s;
115ac9a064cSDimitry Andric }
116ac9a064cSDimitry Andric
117ac9a064cSDimitry Andric return nullptr;
118ac9a064cSDimitry Andric }
119ac9a064cSDimitry Andric
120e3b55780SDimitry Andric std::optional<MemoryRegionInfo>
GetOpaqueTypeFromSBMemoryRegionInfo(const lldb::SBMemoryRegionInfo & mem_region) const121c0981da4SDimitry Andric ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
122c0981da4SDimitry Andric const lldb::SBMemoryRegionInfo &mem_region) const {
123c0981da4SDimitry Andric if (!mem_region.m_opaque_up)
124e3b55780SDimitry Andric return std::nullopt;
125c0981da4SDimitry Andric return *mem_region.m_opaque_up.get();
126c0981da4SDimitry Andric }
127c0981da4SDimitry Andric
12814f1b3e8SDimitry Andric lldb::ScriptLanguage
StringToLanguage(const llvm::StringRef & language)12914f1b3e8SDimitry Andric ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
130344a3780SDimitry Andric if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))
13114f1b3e8SDimitry Andric return eScriptLanguageNone;
132344a3780SDimitry Andric if (language.equals_insensitive(LanguageToString(eScriptLanguagePython)))
13314f1b3e8SDimitry Andric return eScriptLanguagePython;
134344a3780SDimitry Andric if (language.equals_insensitive(LanguageToString(eScriptLanguageLua)))
135706b4fc4SDimitry Andric return eScriptLanguageLua;
13614f1b3e8SDimitry Andric return eScriptLanguageUnknown;
13714f1b3e8SDimitry Andric }
13814f1b3e8SDimitry Andric
SetBreakpointCommandCallback(std::vector<std::reference_wrapper<BreakpointOptions>> & bp_options_vec,const char * callback_text)139b76161e4SDimitry Andric Status ScriptInterpreter::SetBreakpointCommandCallback(
140344a3780SDimitry Andric std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
14114f1b3e8SDimitry Andric const char *callback_text) {
142145449b1SDimitry Andric Status error;
143344a3780SDimitry Andric for (BreakpointOptions &bp_options : bp_options_vec) {
1447fa27ce4SDimitry Andric error = SetBreakpointCommandCallback(bp_options, callback_text,
1457fa27ce4SDimitry Andric /*is_callback=*/false);
146145449b1SDimitry Andric if (!error.Success())
1470cac4ca3SEd Maste break;
1480cac4ca3SEd Maste }
149145449b1SDimitry Andric return error;
1500cac4ca3SEd Maste }
1510cac4ca3SEd Maste
SetBreakpointCommandCallbackFunction(std::vector<std::reference_wrapper<BreakpointOptions>> & bp_options_vec,const char * function_name,StructuredData::ObjectSP extra_args_sp)152706b4fc4SDimitry Andric Status ScriptInterpreter::SetBreakpointCommandCallbackFunction(
153344a3780SDimitry Andric std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
154344a3780SDimitry Andric const char *function_name, StructuredData::ObjectSP extra_args_sp) {
155706b4fc4SDimitry Andric Status error;
156344a3780SDimitry Andric for (BreakpointOptions &bp_options : bp_options_vec) {
157706b4fc4SDimitry Andric error = SetBreakpointCommandCallbackFunction(bp_options, function_name,
158706b4fc4SDimitry Andric extra_args_sp);
159706b4fc4SDimitry Andric if (!error.Success())
160706b4fc4SDimitry Andric return error;
1610cac4ca3SEd Maste }
162706b4fc4SDimitry Andric return error;
1630cac4ca3SEd Maste }
1640cac4ca3SEd Maste
165f034231aSEd Maste std::unique_ptr<ScriptInterpreterLocker>
AcquireInterpreterLock()16614f1b3e8SDimitry Andric ScriptInterpreter::AcquireInterpreterLock() {
167cfca06d7SDimitry Andric return std::make_unique<ScriptInterpreterLocker>();
168cfca06d7SDimitry Andric }
169cfca06d7SDimitry Andric
ReadThreadBytesReceived(void * baton,const void * src,size_t src_len)170cfca06d7SDimitry Andric static void ReadThreadBytesReceived(void *baton, const void *src,
171cfca06d7SDimitry Andric size_t src_len) {
172cfca06d7SDimitry Andric if (src && src_len) {
173cfca06d7SDimitry Andric Stream *strm = (Stream *)baton;
174cfca06d7SDimitry Andric strm->Write(src, src_len);
175cfca06d7SDimitry Andric strm->Flush();
176cfca06d7SDimitry Andric }
177cfca06d7SDimitry Andric }
178cfca06d7SDimitry Andric
179cfca06d7SDimitry Andric llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
Create(bool enable_io,Debugger & debugger,CommandReturnObject * result)180cfca06d7SDimitry Andric ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger,
181cfca06d7SDimitry Andric CommandReturnObject *result) {
182cfca06d7SDimitry Andric if (enable_io)
183cfca06d7SDimitry Andric return std::unique_ptr<ScriptInterpreterIORedirect>(
184cfca06d7SDimitry Andric new ScriptInterpreterIORedirect(debugger, result));
185cfca06d7SDimitry Andric
186cfca06d7SDimitry Andric auto nullin = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
187c0981da4SDimitry Andric File::eOpenOptionReadOnly);
188cfca06d7SDimitry Andric if (!nullin)
189cfca06d7SDimitry Andric return nullin.takeError();
190cfca06d7SDimitry Andric
191cfca06d7SDimitry Andric auto nullout = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
192c0981da4SDimitry Andric File::eOpenOptionWriteOnly);
193cfca06d7SDimitry Andric if (!nullout)
194cfca06d7SDimitry Andric return nullin.takeError();
195cfca06d7SDimitry Andric
196cfca06d7SDimitry Andric return std::unique_ptr<ScriptInterpreterIORedirect>(
197cfca06d7SDimitry Andric new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout)));
198cfca06d7SDimitry Andric }
199cfca06d7SDimitry Andric
ScriptInterpreterIORedirect(std::unique_ptr<File> input,std::unique_ptr<File> output)200cfca06d7SDimitry Andric ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
201cfca06d7SDimitry Andric std::unique_ptr<File> input, std::unique_ptr<File> output)
202cfca06d7SDimitry Andric : m_input_file_sp(std::move(input)),
203cfca06d7SDimitry Andric m_output_file_sp(std::make_shared<StreamFile>(std::move(output))),
204cfca06d7SDimitry Andric m_error_file_sp(m_output_file_sp),
205cfca06d7SDimitry Andric m_communication("lldb.ScriptInterpreterIORedirect.comm"),
206cfca06d7SDimitry Andric m_disconnect(false) {}
207cfca06d7SDimitry Andric
ScriptInterpreterIORedirect(Debugger & debugger,CommandReturnObject * result)208cfca06d7SDimitry Andric ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
209cfca06d7SDimitry Andric Debugger &debugger, CommandReturnObject *result)
210cfca06d7SDimitry Andric : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
211cfca06d7SDimitry Andric m_disconnect(false) {
212cfca06d7SDimitry Andric
213cfca06d7SDimitry Andric if (result) {
214cfca06d7SDimitry Andric m_input_file_sp = debugger.GetInputFileSP();
215cfca06d7SDimitry Andric
216cfca06d7SDimitry Andric Pipe pipe;
217cfca06d7SDimitry Andric Status pipe_result = pipe.CreateNew(false);
218cfca06d7SDimitry Andric #if defined(_WIN32)
219cfca06d7SDimitry Andric lldb::file_t read_file = pipe.GetReadNativeHandle();
220cfca06d7SDimitry Andric pipe.ReleaseReadFileDescriptor();
221cfca06d7SDimitry Andric std::unique_ptr<ConnectionGenericFile> conn_up =
222cfca06d7SDimitry Andric std::make_unique<ConnectionGenericFile>(read_file, true);
223cfca06d7SDimitry Andric #else
224cfca06d7SDimitry Andric std::unique_ptr<ConnectionFileDescriptor> conn_up =
225cfca06d7SDimitry Andric std::make_unique<ConnectionFileDescriptor>(
226cfca06d7SDimitry Andric pipe.ReleaseReadFileDescriptor(), true);
227cfca06d7SDimitry Andric #endif
228cfca06d7SDimitry Andric
229cfca06d7SDimitry Andric if (conn_up->IsConnected()) {
230cfca06d7SDimitry Andric m_communication.SetConnection(std::move(conn_up));
231cfca06d7SDimitry Andric m_communication.SetReadThreadBytesReceivedCallback(
232cfca06d7SDimitry Andric ReadThreadBytesReceived, &result->GetOutputStream());
233cfca06d7SDimitry Andric m_communication.StartReadThread();
234cfca06d7SDimitry Andric m_disconnect = true;
235cfca06d7SDimitry Andric
236cfca06d7SDimitry Andric FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w");
237cfca06d7SDimitry Andric m_output_file_sp = std::make_shared<StreamFile>(outfile_handle, true);
238cfca06d7SDimitry Andric m_error_file_sp = m_output_file_sp;
239cfca06d7SDimitry Andric if (outfile_handle)
240cfca06d7SDimitry Andric ::setbuf(outfile_handle, nullptr);
241cfca06d7SDimitry Andric
242cfca06d7SDimitry Andric result->SetImmediateOutputFile(debugger.GetOutputStream().GetFileSP());
243cfca06d7SDimitry Andric result->SetImmediateErrorFile(debugger.GetErrorStream().GetFileSP());
244cfca06d7SDimitry Andric }
245cfca06d7SDimitry Andric }
246cfca06d7SDimitry Andric
247cfca06d7SDimitry Andric if (!m_input_file_sp || !m_output_file_sp || !m_error_file_sp)
248cfca06d7SDimitry Andric debugger.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp, m_output_file_sp,
249cfca06d7SDimitry Andric m_error_file_sp);
250cfca06d7SDimitry Andric }
251cfca06d7SDimitry Andric
Flush()252cfca06d7SDimitry Andric void ScriptInterpreterIORedirect::Flush() {
253cfca06d7SDimitry Andric if (m_output_file_sp)
254cfca06d7SDimitry Andric m_output_file_sp->Flush();
255cfca06d7SDimitry Andric if (m_error_file_sp)
256cfca06d7SDimitry Andric m_error_file_sp->Flush();
257cfca06d7SDimitry Andric }
258cfca06d7SDimitry Andric
~ScriptInterpreterIORedirect()259cfca06d7SDimitry Andric ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() {
260cfca06d7SDimitry Andric if (!m_disconnect)
261cfca06d7SDimitry Andric return;
262cfca06d7SDimitry Andric
263cfca06d7SDimitry Andric assert(m_output_file_sp);
264cfca06d7SDimitry Andric assert(m_error_file_sp);
265cfca06d7SDimitry Andric assert(m_output_file_sp == m_error_file_sp);
266cfca06d7SDimitry Andric
267cfca06d7SDimitry Andric // Close the write end of the pipe since we are done with our one line
268cfca06d7SDimitry Andric // script. This should cause the read thread that output_comm is using to
269cfca06d7SDimitry Andric // exit.
270cfca06d7SDimitry Andric m_output_file_sp->GetFile().Close();
271cfca06d7SDimitry Andric // The close above should cause this thread to exit when it gets to the end
272cfca06d7SDimitry Andric // of file, so let it get all its data.
273cfca06d7SDimitry Andric m_communication.JoinReadThread();
274cfca06d7SDimitry Andric // Now we can close the read end of the pipe.
275cfca06d7SDimitry Andric m_communication.Disconnect();
276f034231aSEd Maste }
277