LLDB mainline
ScriptInterpreter.cpp
Go to the documentation of this file.
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
10#include "lldb/Core/Debugger.h"
12#include "lldb/Host/Pipe.h"
15#include "lldb/Utility/Status.h"
16#include "lldb/Utility/Stream.h"
19#if defined(_WIN32)
21#endif
22#include <cstdio>
23#include <cstdlib>
24#include <memory>
25#include <optional>
26#include <string>
27
28using namespace lldb;
29using namespace lldb_private;
30
32 lldb::ScriptLanguage script_lang)
33 : m_debugger(debugger), m_script_lang(script_lang) {}
34
36 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
37 CommandReturnObject &result) {
38 result.AppendError(
39 "This script interpreter does not support breakpoint callbacks.");
40}
41
43 WatchpointOptions *bp_options, CommandReturnObject &result) {
44 result.AppendError(
45 "This script interpreter does not support watchpoint callbacks.");
46}
47
51
53 const char *filename, const LoadScriptOptions &options,
55 FileSpec extra_search_dir, lldb::TargetSP loaded_into_target_sp) {
57 "This script interpreter does not support importing modules.");
58 return false;
59}
60
62 switch (language) {
64 return "None";
66 return "Python";
68 return "Lua";
70 return "Unknown";
71 }
72 llvm_unreachable("Unhandled ScriptInterpreter!");
73}
74
79
81 const lldb::SBBreakpoint &breakpoint) const {
82 return breakpoint.m_opaque_wp.lock();
83}
84
87 const lldb::SBBreakpointLocation &break_loc) const {
88 return break_loc.m_opaque_wp.lock();
89}
90
95
97 const lldb::SBLaunchInfo &launch_info) const {
98 return std::make_shared<ProcessLaunchInfo>(
99 *reinterpret_cast<ProcessLaunchInfo *>(launch_info.m_opaque_sp.get()));
100}
101
102Status
104 if (error.m_opaque_up)
105 return error.m_opaque_up->Clone();
106
107 return Status();
108}
109
111 const lldb::SBThread &thread) const {
112 if (thread.m_opaque_sp)
113 return thread.m_opaque_sp->GetThreadSP();
114 return nullptr;
115}
116
119 if (frame.m_opaque_sp)
120 return frame.m_opaque_sp->GetFrameSP();
121 return nullptr;
122}
123
124Event *
126 return event.m_opaque_ptr;
127}
128
130 const lldb::SBStream &stream) const {
131 if (stream.m_opaque_up) {
132 lldb::StreamSP s = std::make_shared<lldb_private::StreamString>();
133 *s << reinterpret_cast<StreamString *>(stream.m_opaque_up.get())->m_packet;
134 return s;
135 }
136
137 return nullptr;
138}
139
141 const lldb::SBSymbolContext &sb_sym_ctx) const {
142 if (sb_sym_ctx.m_opaque_up)
143 return *sb_sym_ctx.m_opaque_up;
144 return {};
145}
146
147std::optional<lldb_private::MemoryRegionInfo>
149 const lldb::SBMemoryRegionInfo &mem_region) const {
150 if (!mem_region.m_opaque_up)
151 return std::nullopt;
152 return *mem_region.m_opaque_up.get();
153}
154
160
165
170
173 if (!value.m_opaque_sp)
174 return lldb::ValueObjectSP();
175
177 return locker.GetLockedSP(*value.m_opaque_sp);
178}
179
181ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
182 if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))
183 return eScriptLanguageNone;
184 if (language.equals_insensitive(LanguageToString(eScriptLanguagePython)))
186 if (language.equals_insensitive(LanguageToString(eScriptLanguageLua)))
187 return eScriptLanguageLua;
189}
190
192 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
193 const char *callback_text) {
195 for (BreakpointOptions &bp_options : bp_options_vec) {
196 error = SetBreakpointCommandCallback(bp_options, callback_text,
197 /*is_callback=*/false);
198 if (!error.Success())
199 break;
200 }
201 return error;
202}
203
205 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
206 const char *function_name, StructuredData::ObjectSP extra_args_sp) {
208 for (BreakpointOptions &bp_options : bp_options_vec) {
209 error = SetBreakpointCommandCallbackFunction(bp_options, function_name,
210 extra_args_sp);
211 if (!error.Success())
212 return error;
213 }
214 return error;
215}
216
217std::unique_ptr<ScriptInterpreterLocker>
219 return std::make_unique<ScriptInterpreterLocker>();
220}
221
224 std::string sanitized_name(name);
225 std::string conflicting_keyword;
226
227 // FIXME: for Python, don't allow certain characters in imported module
228 // filenames. Theoretically, different scripting languages may have
229 // different sets of forbidden tokens in filenames, and that should
230 // be dealt with by each ScriptInterpreter. For now, just replace dots
231 // with underscores. In order to support anything other than Python
232 // this will need to be reworked.
233 llvm::replace(sanitized_name, '.', '_');
234 llvm::replace(sanitized_name, ' ', '_');
235 llvm::replace(sanitized_name, '-', '_');
236 llvm::replace(sanitized_name, '+', 'x');
237
238 if (IsReservedWord(sanitized_name.c_str())) {
239 conflicting_keyword = sanitized_name;
240 sanitized_name.insert(sanitized_name.begin(), '_');
241 }
242
244 name.str(), std::move(sanitized_name), std::move(conflicting_keyword));
245}
246
247static void ReadThreadBytesReceived(void *baton, const void *src,
248 size_t src_len) {
249 if (src && src_len) {
250 Stream *strm = (Stream *)baton;
251 strm->Write(src, src_len);
252 strm->Flush();
253 }
254}
255
256llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
258 CommandReturnObject *result) {
259 if (enable_io)
260 return std::unique_ptr<ScriptInterpreterIORedirect>(
261 new ScriptInterpreterIORedirect(debugger, result));
262
265 if (!nullin)
266 return nullin.takeError();
267
270 if (!nullout)
271 return nullout.takeError();
272
273 return std::unique_ptr<ScriptInterpreterIORedirect>(
274 new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout)));
275}
276
278 std::unique_ptr<File> input, std::unique_ptr<File> output)
279 : m_input_file_sp(std::move(input)),
280 m_output_file_sp(std::make_shared<LockableStreamFile>(std::move(output),
283 m_communication("lldb.ScriptInterpreterIORedirect.comm"),
284 m_disconnect(false) {}
285
287 Debugger &debugger, CommandReturnObject *result)
288 : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
289 m_disconnect(false) {
290
291 if (result) {
292 m_input_file_sp = debugger.GetInputFileSP();
293
294 Pipe pipe;
295 Status pipe_result = pipe.CreateNew();
296#if defined(_WIN32)
297 lldb::file_t read_file = pipe.GetReadNativeHandle();
299 std::unique_ptr<ConnectionGenericFile> conn_up =
300 std::make_unique<ConnectionGenericFile>(read_file, true);
301#else
302 std::unique_ptr<ConnectionFileDescriptor> conn_up =
303 std::make_unique<ConnectionFileDescriptor>(
304 pipe.ReleaseReadFileDescriptor(), true);
305#endif
306
307 if (conn_up->IsConnected()) {
308 m_communication.SetConnection(std::move(conn_up));
309 m_communication.SetReadThreadBytesReceivedCallback(
311 m_communication.StartReadThread();
312 m_disconnect = true;
313
314 FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w");
315 m_output_file_sp = std::make_shared<LockableStreamFile>(
316 std::make_shared<StreamFile>(outfile_handle, NativeFile::Owned),
319 if (outfile_handle)
320 ::setbuf(outfile_handle, nullptr);
321
322 result->SetImmediateOutputFile(debugger.GetOutputFileSP());
323 result->SetImmediateErrorFile(debugger.GetErrorFileSP());
324 }
325 }
326
330}
331
334 m_output_file_sp->Lock().Flush();
335 if (m_error_file_sp)
336 m_error_file_sp->Lock().Flush();
337}
338
340 if (!m_disconnect)
341 return;
342
343 assert(m_output_file_sp);
344 assert(m_error_file_sp);
346
347 // Close the write end of the pipe since we are done with our one line
348 // script. This should cause the read thread that output_comm is using to
349 // exit.
350 m_output_file_sp->GetUnlockedFile().Close();
351 // The close above should cause this thread to exit when it gets to the end
352 // of file, so let it get all its data.
353 m_communication.JoinReadThread();
354 // Now we can close the read end of the pipe.
355 m_communication.Disconnect();
356}
static llvm::raw_ostream & error(Stream &strm)
static void ReadThreadBytesReceived(void *baton, const void *src, size_t src_len)
ProcessAttachInfoSP m_opaque_sp
lldb::BreakpointLocationWP m_opaque_wp
lldb::BreakpointWP m_opaque_wp
lldb::DataExtractorSP m_opaque_sp
Definition SBData.h:159
lldb::ExecutionContextRefSP m_exe_ctx_sp
Represents a list of SBFrame objects.
Definition SBFrameList.h:31
lldb::StackFrameListSP m_opaque_sp
Definition SBFrameList.h:91
lldb::ExecutionContextRefSP m_opaque_sp
Definition SBFrame.h:248
std::shared_ptr< lldb_private::SBLaunchInfoImpl > m_opaque_sp
lldb::MemoryRegionInfoUP m_opaque_up
std::unique_ptr< lldb_private::Stream > m_opaque_up
Definition SBStream.h:122
std::unique_ptr< lldb_private::SymbolContext > m_opaque_up
lldb::TargetSP m_opaque_sp
Definition SBTarget.h:1074
ValueImplSP m_opaque_sp
Definition SBValue.h:513
"lldb/Breakpoint/BreakpointOptions.h" Class that manages the options on a breakpoint or breakpoint lo...
void SetImmediateErrorFile(lldb::FileSP file_sp)
void AppendError(llvm::StringRef in_string)
void SetImmediateOutputFile(lldb::FileSP file_sp)
A class to manage flag bits.
Definition Debugger.h:100
lldb::FileSP GetInputFileSP()
Definition Debugger.h:155
lldb::FileSP GetErrorFileSP()
Definition Debugger.h:162
lldb::FileSP GetOutputFileSP()
Definition Debugger.h:158
void AdoptTopIOHandlerFilesIfInvalid(lldb::FileSP &in, lldb::LockableStreamFileSP &out, lldb::LockableStreamFileSP &err)
A file utility class.
Definition FileSpec.h:57
static const char * DEV_NULL
Definition FileSystem.h:32
int Open(const char *path, int flags, int mode=0600)
Wraps open in a platform-independent way.
static FileSystem & Instance()
@ eOpenOptionReadOnly
Definition File.h:51
@ eOpenOptionWriteOnly
Definition File.h:52
Status CreateNew() override
Definition PipePosix.cpp:82
int ReleaseReadFileDescriptor() override
int ReleaseWriteFileDescriptor() override
void Flush()
Flush our output and error file handles.
ScriptInterpreterIORedirect(std::unique_ptr< File > input, std::unique_ptr< File > output)
static llvm::Expected< std::unique_ptr< ScriptInterpreterIORedirect > > Create(bool enable_io, Debugger &debugger, CommandReturnObject *result)
Create an IO redirect.
Holds an lldb_private::Module name and a "sanitized" version of it for the purposes of loading a scri...
static lldb::ScriptLanguage StringToLanguage(const llvm::StringRef &string)
virtual void CollectDataForBreakpointCommandCallback(std::vector< std::reference_wrapper< BreakpointOptions > > &options, CommandReturnObject &result)
lldb::ProcessAttachInfoSP GetOpaqueTypeFromSBAttachInfo(const lldb::SBAttachInfo &attach_info) const
lldb::StreamSP GetOpaqueTypeFromSBStream(const lldb::SBStream &stream) const
lldb::ExecutionContextRefSP GetOpaqueTypeFromSBExecutionContext(const lldb::SBExecutionContext &exe_ctx) const
SymbolContext GetOpaqueTypeFromSBSymbolContext(const lldb::SBSymbolContext &sym_ctx) const
lldb::ThreadSP GetOpaqueTypeFromSBThread(const lldb::SBThread &exe_ctx) const
std::optional< MemoryRegionInfo > GetOpaqueTypeFromSBMemoryRegionInfo(const lldb::SBMemoryRegionInfo &mem_region) const
lldb::ValueObjectSP GetOpaqueTypeFromSBValue(const lldb::SBValue &value) const
Event * GetOpaqueTypeFromSBEvent(const lldb::SBEvent &event) const
Status SetBreakpointCommandCallback(std::vector< std::reference_wrapper< BreakpointOptions > > &bp_options_vec, const char *callback_text)
Set the specified text as the callback for the breakpoint.
lldb::ProcessLaunchInfoSP GetOpaqueTypeFromSBLaunchInfo(const lldb::SBLaunchInfo &launch_info) const
virtual bool LoadScriptingModule(const char *filename, const LoadScriptOptions &options, lldb_private::Status &error, StructuredData::ObjectSP *module_sp=nullptr, FileSpec extra_search_dir={}, lldb::TargetSP loaded_into_target_sp={})
static std::string LanguageToString(lldb::ScriptLanguage language)
Status GetStatusFromSBError(const lldb::SBError &error) const
virtual std::unique_ptr< ScriptInterpreterLocker > AcquireInterpreterLock()
virtual StructuredData::DictionarySP GetInterpreterInfo()
lldb::BreakpointLocationSP GetOpaqueTypeFromSBBreakpointLocation(const lldb::SBBreakpointLocation &break_loc) const
lldb::TargetSP GetOpaqueTypeFromSBTarget(const lldb::SBTarget &target) const
Status SetBreakpointCommandCallbackFunction(std::vector< std::reference_wrapper< BreakpointOptions > > &bp_options_vec, const char *function_name, StructuredData::ObjectSP extra_args_sp)
lldb::BreakpointSP GetOpaqueTypeFromSBBreakpoint(const lldb::SBBreakpoint &breakpoint) const
lldb::StackFrameListSP GetOpaqueTypeFromSBFrameList(const lldb::SBFrameList &exe_ctx) const
lldb::StackFrameSP GetOpaqueTypeFromSBFrame(const lldb::SBFrame &frame) const
virtual bool IsReservedWord(const char *word)
lldb::DataExtractorSP GetDataExtractorFromSBData(const lldb::SBData &data) const
ScriptInterpreter(Debugger &debugger, lldb::ScriptLanguage script_lang)
virtual void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options, CommandReturnObject &result)
virtual SanitizedScriptingModuleName GetSanitizedScriptingModuleName(llvm::StringRef name)
An error handling class.
Definition Status.h:118
static Status FromErrorString(const char *str)
Definition Status.h:141
A stream class that can stream formatted output to a file.
Definition Stream.h:28
size_t Write(const void *src, size_t src_len)
Output character bytes to the stream.
Definition Stream.h:111
virtual void Flush()=0
Flush the stream.
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Object > ObjectSP
Defines a symbol context baton that can be handed other debug core functions.
lldb::ValueObjectSP GetLockedSP(ValueImpl &in_value)
"lldb/Breakpoint/WatchpointOptions.h" Class that manages the options on a watchpoint.
A class that represents a running process on the host machine.
PipePosix Pipe
Definition Pipe.h:20
int file_t
Definition lldb-types.h:59
ScriptLanguage
Script interpreter types.
@ eScriptLanguageUnknown
@ eScriptLanguageNone
@ eScriptLanguagePython
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::BreakpointLocation > BreakpointLocationSP
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::ProcessAttachInfo > ProcessAttachInfoSP
std::shared_ptr< lldb_private::Stream > StreamSP
std::shared_ptr< lldb_private::Breakpoint > BreakpointSP
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::DataExtractor > DataExtractorSP
std::shared_ptr< lldb_private::ProcessLaunchInfo > ProcessLaunchInfoSP
std::shared_ptr< lldb_private::StackFrameList > StackFrameListSP
std::shared_ptr< lldb_private::ExecutionContextRef > ExecutionContextRefSP