Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / source / Interpreter / ScriptInterpreter.cpp
blobfb3fa74d0b97804651bf99fdb7788314ab542859
1 //===-- ScriptInterpreter.cpp ---------------------------------------------===//
2 //
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
6 //
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"
18 #if defined(_WIN32)
19 #include "lldb/Host/windows/ConnectionGenericFileWindows.h"
20 #endif
21 #include <cstdio>
22 #include <cstdlib>
23 #include <memory>
24 #include <optional>
25 #include <string>
27 using namespace lldb;
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) {
40 result.AppendError(
41 "This script interpreter does not support breakpoint callbacks.");
44 void ScriptInterpreter::CollectDataForWatchpointCommandCallback(
45 WatchpointOptions *bp_options, CommandReturnObject &result) {
46 result.AppendError(
47 "This script interpreter does not support watchpoint callbacks.");
50 StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() {
51 return nullptr;
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) {
59 error.SetErrorString(
60 "This script interpreter does not support importing modules.");
61 return false;
64 std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) {
65 switch (language) {
66 case eScriptLanguageNone:
67 return "None";
68 case eScriptLanguagePython:
69 return "Python";
70 case eScriptLanguageLua:
71 return "Lua";
72 case eScriptLanguageUnknown:
73 return "Unknown";
75 llvm_unreachable("Unhandled ScriptInterpreter!");
78 lldb::DataExtractorSP
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()));
99 Status
100 ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
101 if (error.m_opaque_up)
102 return *error.m_opaque_up;
104 return Status();
107 std::optional<MemoryRegionInfo>
108 ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
109 const lldb::SBMemoryRegionInfo &mem_region) const {
110 if (!mem_region.m_opaque_up)
111 return std::nullopt;
112 return *mem_region.m_opaque_up.get();
115 lldb::ScriptLanguage
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) {
129 Status error;
130 for (BreakpointOptions &bp_options : bp_options_vec) {
131 error = SetBreakpointCommandCallback(bp_options, callback_text,
132 /*is_callback=*/false);
133 if (!error.Success())
134 break;
136 return error;
139 Status ScriptInterpreter::SetBreakpointCommandCallbackFunction(
140 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
141 const char *function_name, StructuredData::ObjectSP extra_args_sp) {
142 Status error;
143 for (BreakpointOptions &bp_options : bp_options_vec) {
144 error = SetBreakpointCommandCallbackFunction(bp_options, function_name,
145 extra_args_sp);
146 if (!error.Success())
147 return error;
149 return error;
152 std::unique_ptr<ScriptInterpreterLocker>
153 ScriptInterpreter::AcquireInterpreterLock() {
154 return std::make_unique<ScriptInterpreterLocker>();
157 static void ReadThreadBytesReceived(void *baton, const void *src,
158 size_t src_len) {
159 if (src && src_len) {
160 Stream *strm = (Stream *)baton;
161 strm->Write(src, src_len);
162 strm->Flush();
166 llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
167 ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger,
168 CommandReturnObject *result) {
169 if (enable_io)
170 return std::unique_ptr<ScriptInterpreterIORedirect>(
171 new ScriptInterpreterIORedirect(debugger, result));
173 auto nullin = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
174 File::eOpenOptionReadOnly);
175 if (!nullin)
176 return nullin.takeError();
178 auto nullout = FileSystem::Instance().Open(FileSpec(FileSystem::DEV_NULL),
179 File::eOpenOptionWriteOnly);
180 if (!nullout)
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) {
200 if (result) {
201 m_input_file_sp = debugger.GetInputFileSP();
203 Pipe pipe;
204 Status pipe_result = pipe.CreateNew(false);
205 #if defined(_WIN32)
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);
210 #else
211 std::unique_ptr<ConnectionFileDescriptor> conn_up =
212 std::make_unique<ConnectionFileDescriptor>(
213 pipe.ReleaseReadFileDescriptor(), true);
214 #endif
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();
221 m_disconnect = true;
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;
226 if (outfile_handle)
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,
236 m_error_file_sp);
239 void ScriptInterpreterIORedirect::Flush() {
240 if (m_output_file_sp)
241 m_output_file_sp->Flush();
242 if (m_error_file_sp)
243 m_error_file_sp->Flush();
246 ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() {
247 if (!m_disconnect)
248 return;
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
256 // exit.
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();