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"
28 using namespace lldb_private
;
30 ScriptInterpreter::ScriptInterpreter(Debugger
&debugger
,
31 lldb::ScriptLanguage script_lang
)
32 : m_debugger(debugger
), m_script_lang(script_lang
) {}
34 void ScriptInterpreter::CollectDataForBreakpointCommandCallback(
35 std::vector
<std::reference_wrapper
<BreakpointOptions
>> &bp_options_vec
,
36 CommandReturnObject
&result
) {
38 "This script interpreter does not support breakpoint callbacks.");
41 void ScriptInterpreter::CollectDataForWatchpointCommandCallback(
42 WatchpointOptions
*bp_options
, CommandReturnObject
&result
) {
44 "This script interpreter does not support watchpoint callbacks.");
47 StructuredData::DictionarySP
ScriptInterpreter::GetInterpreterInfo() {
51 bool ScriptInterpreter::LoadScriptingModule(const char *filename
,
52 const LoadScriptOptions
&options
,
53 lldb_private::Status
&error
,
54 StructuredData::ObjectSP
*module_sp
,
55 FileSpec extra_search_dir
) {
56 error
= Status::FromErrorString(
57 "This script interpreter does not support importing modules.");
61 std::string
ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language
) {
63 case eScriptLanguageNone
:
65 case eScriptLanguagePython
:
67 case eScriptLanguageLua
:
69 case eScriptLanguageUnknown
:
72 llvm_unreachable("Unhandled ScriptInterpreter!");
76 ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData
&data
) const {
77 return data
.m_opaque_sp
;
80 lldb::BreakpointSP
ScriptInterpreter::GetOpaqueTypeFromSBBreakpoint(
81 const lldb::SBBreakpoint
&breakpoint
) const {
82 return breakpoint
.m_opaque_wp
.lock();
85 lldb::ProcessAttachInfoSP
ScriptInterpreter::GetOpaqueTypeFromSBAttachInfo(
86 const lldb::SBAttachInfo
&attach_info
) const {
87 return attach_info
.m_opaque_sp
;
90 lldb::ProcessLaunchInfoSP
ScriptInterpreter::GetOpaqueTypeFromSBLaunchInfo(
91 const lldb::SBLaunchInfo
&launch_info
) const {
92 return std::make_shared
<ProcessLaunchInfo
>(
93 *reinterpret_cast<ProcessLaunchInfo
*>(launch_info
.m_opaque_sp
.get()));
97 ScriptInterpreter::GetStatusFromSBError(const lldb::SBError
&error
) const {
98 if (error
.m_opaque_up
)
99 return error
.m_opaque_up
->Clone();
105 ScriptInterpreter::GetOpaqueTypeFromSBEvent(const lldb::SBEvent
&event
) const {
106 return event
.m_opaque_ptr
;
109 lldb::StreamSP
ScriptInterpreter::GetOpaqueTypeFromSBStream(
110 const lldb::SBStream
&stream
) const {
111 if (stream
.m_opaque_up
) {
112 lldb::StreamSP s
= std::make_shared
<lldb_private::StreamString
>();
113 *s
<< reinterpret_cast<StreamString
*>(stream
.m_opaque_up
.get())->m_packet
;
120 std::optional
<MemoryRegionInfo
>
121 ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
122 const lldb::SBMemoryRegionInfo
&mem_region
) const {
123 if (!mem_region
.m_opaque_up
)
125 return *mem_region
.m_opaque_up
.get();
128 lldb::ExecutionContextRefSP
129 ScriptInterpreter::GetOpaqueTypeFromSBExecutionContext(
130 const lldb::SBExecutionContext
&exe_ctx
) const {
131 return exe_ctx
.m_exe_ctx_sp
;
135 ScriptInterpreter::StringToLanguage(const llvm::StringRef
&language
) {
136 if (language
.equals_insensitive(LanguageToString(eScriptLanguageNone
)))
137 return eScriptLanguageNone
;
138 if (language
.equals_insensitive(LanguageToString(eScriptLanguagePython
)))
139 return eScriptLanguagePython
;
140 if (language
.equals_insensitive(LanguageToString(eScriptLanguageLua
)))
141 return eScriptLanguageLua
;
142 return eScriptLanguageUnknown
;
145 Status
ScriptInterpreter::SetBreakpointCommandCallback(
146 std::vector
<std::reference_wrapper
<BreakpointOptions
>> &bp_options_vec
,
147 const char *callback_text
) {
149 for (BreakpointOptions
&bp_options
: bp_options_vec
) {
150 error
= SetBreakpointCommandCallback(bp_options
, callback_text
,
151 /*is_callback=*/false);
152 if (!error
.Success())
158 Status
ScriptInterpreter::SetBreakpointCommandCallbackFunction(
159 std::vector
<std::reference_wrapper
<BreakpointOptions
>> &bp_options_vec
,
160 const char *function_name
, StructuredData::ObjectSP extra_args_sp
) {
162 for (BreakpointOptions
&bp_options
: bp_options_vec
) {
163 error
= SetBreakpointCommandCallbackFunction(bp_options
, function_name
,
165 if (!error
.Success())
171 std::unique_ptr
<ScriptInterpreterLocker
>
172 ScriptInterpreter::AcquireInterpreterLock() {
173 return std::make_unique
<ScriptInterpreterLocker
>();
176 static void ReadThreadBytesReceived(void *baton
, const void *src
,
178 if (src
&& src_len
) {
179 Stream
*strm
= (Stream
*)baton
;
180 strm
->Write(src
, src_len
);
185 llvm::Expected
<std::unique_ptr
<ScriptInterpreterIORedirect
>>
186 ScriptInterpreterIORedirect::Create(bool enable_io
, Debugger
&debugger
,
187 CommandReturnObject
*result
) {
189 return std::unique_ptr
<ScriptInterpreterIORedirect
>(
190 new ScriptInterpreterIORedirect(debugger
, result
));
192 auto nullin
= FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL
),
193 File::eOpenOptionReadOnly
);
195 return nullin
.takeError();
197 auto nullout
= FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL
),
198 File::eOpenOptionWriteOnly
);
200 return nullin
.takeError();
202 return std::unique_ptr
<ScriptInterpreterIORedirect
>(
203 new ScriptInterpreterIORedirect(std::move(*nullin
), std::move(*nullout
)));
206 ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
207 std::unique_ptr
<File
> input
, std::unique_ptr
<File
> output
)
208 : m_input_file_sp(std::move(input
)),
209 m_output_file_sp(std::make_shared
<StreamFile
>(std::move(output
))),
210 m_error_file_sp(m_output_file_sp
),
211 m_communication("lldb.ScriptInterpreterIORedirect.comm"),
212 m_disconnect(false) {}
214 ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
215 Debugger
&debugger
, CommandReturnObject
*result
)
216 : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
217 m_disconnect(false) {
220 m_input_file_sp
= debugger
.GetInputFileSP();
223 Status pipe_result
= pipe
.CreateNew(false);
225 lldb::file_t read_file
= pipe
.GetReadNativeHandle();
226 pipe
.ReleaseReadFileDescriptor();
227 std::unique_ptr
<ConnectionGenericFile
> conn_up
=
228 std::make_unique
<ConnectionGenericFile
>(read_file
, true);
230 std::unique_ptr
<ConnectionFileDescriptor
> conn_up
=
231 std::make_unique
<ConnectionFileDescriptor
>(
232 pipe
.ReleaseReadFileDescriptor(), true);
235 if (conn_up
->IsConnected()) {
236 m_communication
.SetConnection(std::move(conn_up
));
237 m_communication
.SetReadThreadBytesReceivedCallback(
238 ReadThreadBytesReceived
, &result
->GetOutputStream());
239 m_communication
.StartReadThread();
242 FILE *outfile_handle
= fdopen(pipe
.ReleaseWriteFileDescriptor(), "w");
243 m_output_file_sp
= std::make_shared
<StreamFile
>(outfile_handle
, true);
244 m_error_file_sp
= m_output_file_sp
;
246 ::setbuf(outfile_handle
, nullptr);
248 result
->SetImmediateOutputFile(debugger
.GetOutputStream().GetFileSP());
249 result
->SetImmediateErrorFile(debugger
.GetErrorStream().GetFileSP());
253 if (!m_input_file_sp
|| !m_output_file_sp
|| !m_error_file_sp
)
254 debugger
.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp
, m_output_file_sp
,
258 void ScriptInterpreterIORedirect::Flush() {
259 if (m_output_file_sp
)
260 m_output_file_sp
->Flush();
262 m_error_file_sp
->Flush();
265 ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() {
269 assert(m_output_file_sp
);
270 assert(m_error_file_sp
);
271 assert(m_output_file_sp
== m_error_file_sp
);
273 // Close the write end of the pipe since we are done with our one line
274 // script. This should cause the read thread that output_comm is using to
276 m_output_file_sp
->GetFile().Close();
277 // The close above should cause this thread to exit when it gets to the end
278 // of file, so let it get all its data.
279 m_communication
.JoinReadThread();
280 // Now we can close the read end of the pipe.
281 m_communication
.Disconnect();