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(
31 Debugger
&debugger
, lldb::ScriptLanguage script_lang
,
32 lldb::ScriptedPlatformInterfaceUP scripted_platform_interface_up
)
33 : m_debugger(debugger
), m_script_lang(script_lang
),
34 m_scripted_platform_interface_up(
35 std::move(scripted_platform_interface_up
)) {}
37 void ScriptInterpreter::CollectDataForBreakpointCommandCallback(
38 std::vector
<std::reference_wrapper
<BreakpointOptions
>> &bp_options_vec
,
39 CommandReturnObject
&result
) {
41 "This script interpreter does not support breakpoint callbacks.");
44 void ScriptInterpreter::CollectDataForWatchpointCommandCallback(
45 WatchpointOptions
*bp_options
, CommandReturnObject
&result
) {
47 "This script interpreter does not support watchpoint callbacks.");
50 StructuredData::DictionarySP
ScriptInterpreter::GetInterpreterInfo() {
54 bool ScriptInterpreter::LoadScriptingModule(const char *filename
,
55 const LoadScriptOptions
&options
,
56 lldb_private::Status
&error
,
57 StructuredData::ObjectSP
*module_sp
,
58 FileSpec extra_search_dir
) {
60 "This script interpreter does not support importing modules.");
64 std::string
ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language
) {
66 case eScriptLanguageNone
:
68 case eScriptLanguagePython
:
70 case eScriptLanguageLua
:
72 case eScriptLanguageUnknown
:
75 llvm_unreachable("Unhandled ScriptInterpreter!");
79 ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData
&data
) const {
80 return data
.m_opaque_sp
;
83 lldb::BreakpointSP
ScriptInterpreter::GetOpaqueTypeFromSBBreakpoint(
84 const lldb::SBBreakpoint
&breakpoint
) const {
85 return breakpoint
.m_opaque_wp
.lock();
88 lldb::ProcessAttachInfoSP
ScriptInterpreter::GetOpaqueTypeFromSBAttachInfo(
89 const lldb::SBAttachInfo
&attach_info
) const {
90 return attach_info
.m_opaque_sp
;
93 lldb::ProcessLaunchInfoSP
ScriptInterpreter::GetOpaqueTypeFromSBLaunchInfo(
94 const lldb::SBLaunchInfo
&launch_info
) const {
95 return std::make_shared
<ProcessLaunchInfo
>(
96 *reinterpret_cast<ProcessLaunchInfo
*>(launch_info
.m_opaque_sp
.get()));
100 ScriptInterpreter::GetStatusFromSBError(const lldb::SBError
&error
) const {
101 if (error
.m_opaque_up
)
102 return *error
.m_opaque_up
;
107 std::optional
<MemoryRegionInfo
>
108 ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
109 const lldb::SBMemoryRegionInfo
&mem_region
) const {
110 if (!mem_region
.m_opaque_up
)
112 return *mem_region
.m_opaque_up
.get();
116 ScriptInterpreter::StringToLanguage(const llvm::StringRef
&language
) {
117 if (language
.equals_insensitive(LanguageToString(eScriptLanguageNone
)))
118 return eScriptLanguageNone
;
119 if (language
.equals_insensitive(LanguageToString(eScriptLanguagePython
)))
120 return eScriptLanguagePython
;
121 if (language
.equals_insensitive(LanguageToString(eScriptLanguageLua
)))
122 return eScriptLanguageLua
;
123 return eScriptLanguageUnknown
;
126 Status
ScriptInterpreter::SetBreakpointCommandCallback(
127 std::vector
<std::reference_wrapper
<BreakpointOptions
>> &bp_options_vec
,
128 const char *callback_text
) {
130 for (BreakpointOptions
&bp_options
: bp_options_vec
) {
131 error
= SetBreakpointCommandCallback(bp_options
, callback_text
,
132 /*is_callback=*/false);
133 if (!error
.Success())
139 Status
ScriptInterpreter::SetBreakpointCommandCallbackFunction(
140 std::vector
<std::reference_wrapper
<BreakpointOptions
>> &bp_options_vec
,
141 const char *function_name
, StructuredData::ObjectSP extra_args_sp
) {
143 for (BreakpointOptions
&bp_options
: bp_options_vec
) {
144 error
= SetBreakpointCommandCallbackFunction(bp_options
, function_name
,
146 if (!error
.Success())
152 std::unique_ptr
<ScriptInterpreterLocker
>
153 ScriptInterpreter::AcquireInterpreterLock() {
154 return std::make_unique
<ScriptInterpreterLocker
>();
157 static void ReadThreadBytesReceived(void *baton
, const void *src
,
159 if (src
&& src_len
) {
160 Stream
*strm
= (Stream
*)baton
;
161 strm
->Write(src
, src_len
);
166 llvm::Expected
<std::unique_ptr
<ScriptInterpreterIORedirect
>>
167 ScriptInterpreterIORedirect::Create(bool enable_io
, Debugger
&debugger
,
168 CommandReturnObject
*result
) {
170 return std::unique_ptr
<ScriptInterpreterIORedirect
>(
171 new ScriptInterpreterIORedirect(debugger
, result
));
173 auto nullin
= FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL
),
174 File::eOpenOptionReadOnly
);
176 return nullin
.takeError();
178 auto nullout
= FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL
),
179 File::eOpenOptionWriteOnly
);
181 return nullin
.takeError();
183 return std::unique_ptr
<ScriptInterpreterIORedirect
>(
184 new ScriptInterpreterIORedirect(std::move(*nullin
), std::move(*nullout
)));
187 ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
188 std::unique_ptr
<File
> input
, std::unique_ptr
<File
> output
)
189 : m_input_file_sp(std::move(input
)),
190 m_output_file_sp(std::make_shared
<StreamFile
>(std::move(output
))),
191 m_error_file_sp(m_output_file_sp
),
192 m_communication("lldb.ScriptInterpreterIORedirect.comm"),
193 m_disconnect(false) {}
195 ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
196 Debugger
&debugger
, CommandReturnObject
*result
)
197 : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
198 m_disconnect(false) {
201 m_input_file_sp
= debugger
.GetInputFileSP();
204 Status pipe_result
= pipe
.CreateNew(false);
206 lldb::file_t read_file
= pipe
.GetReadNativeHandle();
207 pipe
.ReleaseReadFileDescriptor();
208 std::unique_ptr
<ConnectionGenericFile
> conn_up
=
209 std::make_unique
<ConnectionGenericFile
>(read_file
, true);
211 std::unique_ptr
<ConnectionFileDescriptor
> conn_up
=
212 std::make_unique
<ConnectionFileDescriptor
>(
213 pipe
.ReleaseReadFileDescriptor(), true);
216 if (conn_up
->IsConnected()) {
217 m_communication
.SetConnection(std::move(conn_up
));
218 m_communication
.SetReadThreadBytesReceivedCallback(
219 ReadThreadBytesReceived
, &result
->GetOutputStream());
220 m_communication
.StartReadThread();
223 FILE *outfile_handle
= fdopen(pipe
.ReleaseWriteFileDescriptor(), "w");
224 m_output_file_sp
= std::make_shared
<StreamFile
>(outfile_handle
, true);
225 m_error_file_sp
= m_output_file_sp
;
227 ::setbuf(outfile_handle
, nullptr);
229 result
->SetImmediateOutputFile(debugger
.GetOutputStream().GetFileSP());
230 result
->SetImmediateErrorFile(debugger
.GetErrorStream().GetFileSP());
234 if (!m_input_file_sp
|| !m_output_file_sp
|| !m_error_file_sp
)
235 debugger
.AdoptTopIOHandlerFilesIfInvalid(m_input_file_sp
, m_output_file_sp
,
239 void ScriptInterpreterIORedirect::Flush() {
240 if (m_output_file_sp
)
241 m_output_file_sp
->Flush();
243 m_error_file_sp
->Flush();
246 ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() {
250 assert(m_output_file_sp
);
251 assert(m_error_file_sp
);
252 assert(m_output_file_sp
== m_error_file_sp
);
254 // Close the write end of the pipe since we are done with our one line
255 // script. This should cause the read thread that output_comm is using to
257 m_output_file_sp
->GetFile().Close();
258 // The close above should cause this thread to exit when it gets to the end
259 // of file, so let it get all its data.
260 m_communication
.JoinReadThread();
261 // Now we can close the read end of the pipe.
262 m_communication
.Disconnect();