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//===----------------------------------------------------------------------===//
8
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>
26
27using namespace lldb;
28using namespace lldb_private;
29
30ScriptInterpreter::ScriptInterpreter(Debugger &debugger,
31 lldb::ScriptLanguage script_lang)
32 : m_debugger(debugger), m_script_lang(script_lang) {}
33
34void ScriptInterpreter::CollectDataForBreakpointCommandCallback(
35 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
36 CommandReturnObject &result) {
37 result.AppendError(
38 in_string: "This script interpreter does not support breakpoint callbacks.");
39}
40
41void ScriptInterpreter::CollectDataForWatchpointCommandCallback(
42 WatchpointOptions *bp_options, CommandReturnObject &result) {
43 result.AppendError(
44 in_string: "This script interpreter does not support watchpoint callbacks.");
45}
46
47StructuredData::DictionarySP ScriptInterpreter::GetInterpreterInfo() {
48 return nullptr;
49}
50
51bool ScriptInterpreter::LoadScriptingModule(
52 const char *filename, const LoadScriptOptions &options,
53 lldb_private::Status &error, StructuredData::ObjectSP *module_sp,
54 FileSpec extra_search_dir, lldb::TargetSP loaded_into_target_sp) {
55 error = Status::FromErrorString(
56 str: "This script interpreter does not support importing modules.");
57 return false;
58}
59
60std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) {
61 switch (language) {
62 case eScriptLanguageNone:
63 return "None";
64 case eScriptLanguagePython:
65 return "Python";
66 case eScriptLanguageLua:
67 return "Lua";
68 case eScriptLanguageUnknown:
69 return "Unknown";
70 }
71 llvm_unreachable("Unhandled ScriptInterpreter!");
72}
73
74lldb::DataExtractorSP
75ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData &data) const {
76 return data.m_opaque_sp;
77}
78
79lldb::BreakpointSP ScriptInterpreter::GetOpaqueTypeFromSBBreakpoint(
80 const lldb::SBBreakpoint &breakpoint) const {
81 return breakpoint.m_opaque_wp.lock();
82}
83
84lldb::ProcessAttachInfoSP ScriptInterpreter::GetOpaqueTypeFromSBAttachInfo(
85 const lldb::SBAttachInfo &attach_info) const {
86 return attach_info.m_opaque_sp;
87}
88
89lldb::ProcessLaunchInfoSP ScriptInterpreter::GetOpaqueTypeFromSBLaunchInfo(
90 const lldb::SBLaunchInfo &launch_info) const {
91 return std::make_shared<ProcessLaunchInfo>(
92 args&: *reinterpret_cast<ProcessLaunchInfo *>(launch_info.m_opaque_sp.get()));
93}
94
95Status
96ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const {
97 if (error.m_opaque_up)
98 return error.m_opaque_up->Clone();
99
100 return Status();
101}
102
103Event *
104ScriptInterpreter::GetOpaqueTypeFromSBEvent(const lldb::SBEvent &event) const {
105 return event.m_opaque_ptr;
106}
107
108lldb::StreamSP ScriptInterpreter::GetOpaqueTypeFromSBStream(
109 const lldb::SBStream &stream) const {
110 if (stream.m_opaque_up) {
111 lldb::StreamSP s = std::make_shared<lldb_private::StreamString>();
112 *s << reinterpret_cast<StreamString *>(stream.m_opaque_up.get())->m_packet;
113 return s;
114 }
115
116 return nullptr;
117}
118
119std::optional<MemoryRegionInfo>
120ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo(
121 const lldb::SBMemoryRegionInfo &mem_region) const {
122 if (!mem_region.m_opaque_up)
123 return std::nullopt;
124 return *mem_region.m_opaque_up.get();
125}
126
127lldb::ExecutionContextRefSP
128ScriptInterpreter::GetOpaqueTypeFromSBExecutionContext(
129 const lldb::SBExecutionContext &exe_ctx) const {
130 return exe_ctx.m_exe_ctx_sp;
131}
132
133lldb::ScriptLanguage
134ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
135 if (language.equals_insensitive(RHS: LanguageToString(language: eScriptLanguageNone)))
136 return eScriptLanguageNone;
137 if (language.equals_insensitive(RHS: LanguageToString(language: eScriptLanguagePython)))
138 return eScriptLanguagePython;
139 if (language.equals_insensitive(RHS: LanguageToString(language: eScriptLanguageLua)))
140 return eScriptLanguageLua;
141 return eScriptLanguageUnknown;
142}
143
144Status ScriptInterpreter::SetBreakpointCommandCallback(
145 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
146 const char *callback_text) {
147 Status error;
148 for (BreakpointOptions &bp_options : bp_options_vec) {
149 error = SetBreakpointCommandCallback(bp_options, callback_text,
150 /*is_callback=*/false);
151 if (!error.Success())
152 break;
153 }
154 return error;
155}
156
157Status ScriptInterpreter::SetBreakpointCommandCallbackFunction(
158 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
159 const char *function_name, StructuredData::ObjectSP extra_args_sp) {
160 Status error;
161 for (BreakpointOptions &bp_options : bp_options_vec) {
162 error = SetBreakpointCommandCallbackFunction(bp_options, function_name,
163 extra_args_sp);
164 if (!error.Success())
165 return error;
166 }
167 return error;
168}
169
170std::unique_ptr<ScriptInterpreterLocker>
171ScriptInterpreter::AcquireInterpreterLock() {
172 return std::make_unique<ScriptInterpreterLocker>();
173}
174
175static void ReadThreadBytesReceived(void *baton, const void *src,
176 size_t src_len) {
177 if (src && src_len) {
178 Stream *strm = (Stream *)baton;
179 strm->Write(src, src_len);
180 strm->Flush();
181 }
182}
183
184llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
185ScriptInterpreterIORedirect::Create(bool enable_io, Debugger &debugger,
186 CommandReturnObject *result) {
187 if (enable_io)
188 return std::unique_ptr<ScriptInterpreterIORedirect>(
189 new ScriptInterpreterIORedirect(debugger, result));
190
191 auto nullin = FileSystem::Instance().Open(file_spec: FileSpec(FileSystem::DEV_NULL),
192 options: File::eOpenOptionReadOnly);
193 if (!nullin)
194 return nullin.takeError();
195
196 auto nullout = FileSystem::Instance().Open(file_spec: FileSpec(FileSystem::DEV_NULL),
197 options: File::eOpenOptionWriteOnly);
198 if (!nullout)
199 return nullin.takeError();
200
201 return std::unique_ptr<ScriptInterpreterIORedirect>(
202 new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout)));
203}
204
205ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
206 std::unique_ptr<File> input, std::unique_ptr<File> output)
207 : m_input_file_sp(std::move(input)),
208 m_output_file_sp(std::make_shared<LockableStreamFile>(args: std::move(output),
209 args&: m_output_mutex)),
210 m_error_file_sp(m_output_file_sp),
211 m_communication("lldb.ScriptInterpreterIORedirect.comm"),
212 m_disconnect(false) {}
213
214ScriptInterpreterIORedirect::ScriptInterpreterIORedirect(
215 Debugger &debugger, CommandReturnObject *result)
216 : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
217 m_disconnect(false) {
218
219 if (result) {
220 m_input_file_sp = debugger.GetInputFileSP();
221
222 Pipe pipe;
223 Status pipe_result = pipe.CreateNew(child_process_inherit: false);
224#if defined(_WIN32)
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);
229#else
230 std::unique_ptr<ConnectionFileDescriptor> conn_up =
231 std::make_unique<ConnectionFileDescriptor>(
232 args: pipe.ReleaseReadFileDescriptor(), args: true);
233#endif
234
235 if (conn_up->IsConnected()) {
236 m_communication.SetConnection(std::move(conn_up));
237 m_communication.SetReadThreadBytesReceivedCallback(
238 callback: ReadThreadBytesReceived, callback_baton: &result->GetOutputStream());
239 m_communication.StartReadThread();
240 m_disconnect = true;
241
242 FILE *outfile_handle = fdopen(fd: pipe.ReleaseWriteFileDescriptor(), modes: "w");
243 m_output_file_sp = std::make_shared<LockableStreamFile>(
244 args: std::make_shared<StreamFile>(args&: outfile_handle, args: NativeFile::Owned),
245 args&: m_output_mutex);
246 m_error_file_sp = m_output_file_sp;
247 if (outfile_handle)
248 ::setbuf(stream: outfile_handle, buf: nullptr);
249
250 result->SetImmediateOutputFile(debugger.GetOutputFileSP());
251 result->SetImmediateErrorFile(debugger.GetErrorFileSP());
252 }
253 }
254
255 if (!m_input_file_sp || !m_output_file_sp || !m_error_file_sp)
256 debugger.AdoptTopIOHandlerFilesIfInvalid(in&: m_input_file_sp, out&: m_output_file_sp,
257 err&: m_error_file_sp);
258}
259
260void ScriptInterpreterIORedirect::Flush() {
261 if (m_output_file_sp)
262 m_output_file_sp->Lock().Flush();
263 if (m_error_file_sp)
264 m_error_file_sp->Lock().Flush();
265}
266
267ScriptInterpreterIORedirect::~ScriptInterpreterIORedirect() {
268 if (!m_disconnect)
269 return;
270
271 assert(m_output_file_sp);
272 assert(m_error_file_sp);
273 assert(m_output_file_sp == m_error_file_sp);
274
275 // Close the write end of the pipe since we are done with our one line
276 // script. This should cause the read thread that output_comm is using to
277 // exit.
278 m_output_file_sp->GetUnlockedFile().Close();
279 // The close above should cause this thread to exit when it gets to the end
280 // of file, so let it get all its data.
281 m_communication.JoinReadThread();
282 // Now we can close the read end of the pipe.
283 m_communication.Disconnect();
284}
285

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of lldb/source/Interpreter/ScriptInterpreter.cpp