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