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
11#include "lldb/Core/Debugger.h"
13#include "lldb/Host/Pipe.h"
16#include "lldb/Utility/Status.h"
17#include "lldb/Utility/Stream.h"
21#include "llvm/ADT/StringSwitch.h"
22#if defined(_WIN32)
24#endif
25#include <cstdio>
26#include <cstdlib>
27#include <memory>
28#include <optional>
29#include <string>
30
31using namespace lldb;
32using namespace lldb_private;
33
35 lldb::ScriptLanguage script_lang)
36 : m_debugger(debugger), m_script_lang(script_lang) {}
37
39 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
40 CommandReturnObject &result) {
41 result.AppendError(
42 "This script interpreter does not support breakpoint callbacks.");
43}
44
46 WatchpointOptions *bp_options, CommandReturnObject &result) {
47 result.AppendError(
48 "This script interpreter does not support watchpoint callbacks.");
49}
50
54
56 const std::string &name, std::vector<ExtensionTemplateRequest> &extensions,
57 bool generate_non_abstract_methods, std::string output_file) {
58 return llvm::make_error<UnimplementedError>();
59}
60
62 const char *filename, const LoadScriptOptions &options,
64 FileSpec extra_search_dir, lldb::TargetSP loaded_into_target_sp) {
66 "This script interpreter does not support importing modules.");
67 return false;
68}
69
71 switch (language) {
73 return "None";
75 return "Python";
77 return "Lua";
79 return "Unknown";
80 }
81 llvm_unreachable("Unhandled ScriptInterpreter!");
82}
83
88
90 const lldb::SBBreakpoint &breakpoint) const {
91 return breakpoint.m_opaque_wp.lock();
92}
93
96 const lldb::SBBreakpointLocation &break_loc) const {
97 return break_loc.m_opaque_wp.lock();
98}
99
104
109
114
116 const lldb::SBLaunchInfo &launch_info) const {
117 return std::make_shared<ProcessLaunchInfo>(
118 *reinterpret_cast<ProcessLaunchInfo *>(launch_info.m_opaque_sp.get()));
119}
120
121Status
123 if (error.m_opaque_up)
124 return error.m_opaque_up->Clone();
125
126 return Status();
127}
128
130 const lldb::SBThread &thread) const {
131 if (thread.m_opaque_sp)
132 return thread.m_opaque_sp->GetThreadSP();
133 return nullptr;
134}
135
138 if (frame.m_opaque_sp)
139 return frame.m_opaque_sp->GetFrameSP();
140 return nullptr;
141}
142
143Event *
145 return event.m_opaque_ptr;
146}
147
149 const lldb::SBStream &stream) const {
150 if (stream.m_opaque_up) {
151 lldb::StreamSP s = std::make_shared<lldb_private::StreamString>();
152 *s << reinterpret_cast<StreamString *>(stream.m_opaque_up.get())->m_packet;
153 return s;
154 }
155
156 return nullptr;
157}
158
160 const lldb::SBSymbolContext &sb_sym_ctx) const {
161 if (sb_sym_ctx.m_opaque_up)
162 return *sb_sym_ctx.m_opaque_up;
163 return {};
164}
165
166std::optional<lldb_private::MemoryRegionInfo>
168 const lldb::SBMemoryRegionInfo &mem_region) const {
169 if (!mem_region.m_opaque_up)
170 return std::nullopt;
171 return *mem_region.m_opaque_up.get();
172}
173
179
184
189
192 if (!value.m_opaque_sp)
193 return lldb::ValueObjectSP();
194
196 return locker.GetLockedSP(*value.m_opaque_sp);
197}
198
200ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
201 if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))
202 return eScriptLanguageNone;
203 if (language.equals_insensitive(LanguageToString(eScriptLanguagePython)))
205 if (language.equals_insensitive(LanguageToString(eScriptLanguageLua)))
206 return eScriptLanguageLua;
208}
209
210llvm::StringLiteral
212 switch (extension) {
214 return "Invalid";
216 return "OperatingSystem";
218 return "ScriptedPlatform";
220 return "ScriptedProcess";
222 return "ScriptedBreakpointResolver";
224 return "ScriptedThreadPlan";
226 return "ScriptedFrameProvider";
228 return "ScriptedHook";
230 return "ScriptedThread";
232 return "ScriptedFrame";
234 return "ScriptedStackFrameRecognizer";
236 return "ScriptedCommand";
238 return "ParsedCommand";
240 return "ScriptedStringSummary";
242 return "ScriptedSyntheticChildren";
243 }
244 llvm_unreachable("unhandled ScriptedExtension");
245}
246
249 return llvm::StringSwitch<lldb::ScriptedExtension>(string)
250 .CaseLower("OperatingSystem", eScriptedExtensionOperatingSystem)
251 .CaseLower("ScriptedPlatform", eScriptedExtensionScriptedPlatform)
252 .CaseLower("ScriptedProcess", eScriptedExtensionScriptedProcess)
253 .CaseLower("ScriptedBreakpointResolver",
255 .CaseLower("ScriptedThreadPlan", eScriptedExtensionScriptedThreadPlan)
256 .CaseLower("ScriptedFrameProvider",
258 .CaseLower("ScriptedHook", eScriptedExtensionScriptedHook)
259 .CaseLower("ScriptedThread", eScriptedExtensionScriptedThread)
260 .CaseLower("ScriptedFrame", eScriptedExtensionScriptedFrame)
261 .CaseLower("ScriptedStackFrameRecognizer",
263 .CaseLower("ScriptedCommand", eScriptedExtensionScriptedCommand)
264 .CaseLower("ParsedCommand", eScriptedExtensionParsedCommand)
265 .CaseLower("ScriptedStringSummary",
267 .CaseLower("ScriptedSyntheticChildren",
270}
271
273 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
274 const char *callback_text) {
276 for (BreakpointOptions &bp_options : bp_options_vec) {
277 error = SetBreakpointCommandCallback(bp_options, callback_text,
278 /*is_callback=*/false);
279 if (!error.Success())
280 break;
281 }
282 return error;
283}
284
286 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
287 const char *function_name, StructuredData::ObjectSP extra_args_sp) {
289 for (BreakpointOptions &bp_options : bp_options_vec) {
290 error = SetBreakpointCommandCallbackFunction(bp_options, function_name,
291 extra_args_sp);
292 if (!error.Success())
293 return error;
294 }
295 return error;
296}
297
298std::unique_ptr<ScriptInterpreterLocker>
300 return std::make_unique<ScriptInterpreterLocker>();
301}
302
305 std::string sanitized_name(name);
306 std::string conflicting_keyword;
307
308 // FIXME: for Python, don't allow certain characters in imported module
309 // filenames. Theoretically, different scripting languages may have
310 // different sets of forbidden tokens in filenames, and that should
311 // be dealt with by each ScriptInterpreter. For now, just replace dots
312 // with underscores. In order to support anything other than Python
313 // this will need to be reworked.
314 llvm::replace(sanitized_name, '.', '_');
315 llvm::replace(sanitized_name, ' ', '_');
316 llvm::replace(sanitized_name, '-', '_');
317 llvm::replace(sanitized_name, '+', 'x');
318
319 if (IsReservedWord(sanitized_name.c_str())) {
320 conflicting_keyword = sanitized_name;
321 sanitized_name.insert(sanitized_name.begin(), '_');
322 }
323
325 name.str(), std::move(sanitized_name), std::move(conflicting_keyword));
326}
327
328static void ReadThreadBytesReceived(void *baton, const void *src,
329 size_t src_len) {
330 if (src && src_len) {
331 Stream *strm = (Stream *)baton;
332 strm->Write(src, src_len);
333 strm->Flush();
334 }
335}
336
337llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
339 CommandReturnObject *result) {
340 if (enable_io)
341 return std::unique_ptr<ScriptInterpreterIORedirect>(
342 new ScriptInterpreterIORedirect(debugger, result));
343
346 if (!nullin)
347 return nullin.takeError();
348
351 if (!nullout)
352 return nullout.takeError();
353
354 return std::unique_ptr<ScriptInterpreterIORedirect>(
355 new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout)));
356}
357
359 std::unique_ptr<File> input, std::unique_ptr<File> output)
360 : m_input_file_sp(std::move(input)),
361 m_output_file_sp(std::make_shared<LockableStreamFile>(std::move(output),
364 m_communication("lldb.ScriptInterpreterIORedirect.comm"),
365 m_disconnect(false) {}
366
368 Debugger &debugger, CommandReturnObject *result)
369 : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
370 m_disconnect(false) {
371
372 if (result) {
373 m_input_file_sp = debugger.GetInputFileSP();
374
375 Pipe pipe;
376 Status pipe_result = pipe.CreateNew();
377#if defined(_WIN32)
378 lldb::file_t read_file = pipe.GetReadNativeHandle();
380 std::unique_ptr<ConnectionGenericFile> conn_up =
381 std::make_unique<ConnectionGenericFile>(read_file, true);
382#else
383 std::unique_ptr<ConnectionFileDescriptor> conn_up =
384 std::make_unique<ConnectionFileDescriptor>(
385 pipe.ReleaseReadFileDescriptor(), true);
386#endif
387
388 if (conn_up->IsConnected()) {
389 m_communication.SetConnection(std::move(conn_up));
390 m_communication.SetReadThreadBytesReceivedCallback(
392 m_communication.StartReadThread();
393 m_disconnect = true;
394
395 FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w");
396 m_output_file_sp = std::make_shared<LockableStreamFile>(
397 std::make_shared<StreamFile>(outfile_handle, NativeFile::Owned),
400 if (outfile_handle)
401 ::setbuf(outfile_handle, nullptr);
402
403 result->SetImmediateOutputFile(debugger.GetOutputFileSP());
404 result->SetImmediateErrorFile(debugger.GetErrorFileSP());
405 }
406 }
407
411}
412
415 m_output_file_sp->Lock().Flush();
416 if (m_error_file_sp)
417 m_error_file_sp->Lock().Flush();
418}
419
421 if (!m_disconnect)
422 return;
423
424 assert(m_output_file_sp);
425 assert(m_error_file_sp);
427
428 // Close the write end of the pipe since we are done with our one line
429 // script. This should cause the read thread that output_comm is using to
430 // exit.
431 m_output_file_sp->GetUnlockedFile().Close();
432 // The close above should cause this thread to exit when it gets to the end
433 // of file, so let it get all its data.
434 m_communication.JoinReadThread();
435 // Now we can close the read end of the pipe.
436 m_communication.Disconnect();
437}
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
std::unique_ptr< lldb_private::SBCommandReturnObjectImpl > m_opaque_up
lldb::DataExtractorSP m_opaque_sp
Definition SBData.h:159
lldb::DebuggerSP m_opaque_sp
Definition SBDebugger.h:708
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:1082
ValueImplSP m_opaque_sp
Definition SBValue.h:539
"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()
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
CommandReturnObject * GetOpaqueTypeFromSBCommandReturnObject(const lldb::SBCommandReturnObject &cmd_retobj) const
lldb::ExecutionContextRefSP GetOpaqueTypeFromSBExecutionContext(const lldb::SBExecutionContext &exe_ctx) const
SymbolContext GetOpaqueTypeFromSBSymbolContext(const lldb::SBSymbolContext &sym_ctx) const
virtual llvm::Expected< FileSpec > GenerateExtensionTemplate(const std::string &name, std::vector< ExtensionTemplateRequest > &extensions, bool generate_non_abstract_methods, std::string output_file)
lldb::ThreadSP GetOpaqueTypeFromSBThread(const lldb::SBThread &exe_ctx) const
static llvm::StringLiteral ExtensionToString(lldb::ScriptedExtension extension)
static lldb::ScriptedExtension StringToExtension(llvm::StringRef string)
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::DebuggerSP GetOpaqueTypeFromSBDebugger(const lldb::SBDebugger &debugger) 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
ScriptedExtension
Scripting extension types.
@ eScriptedExtensionOperatingSystem
@ eScriptedExtensionScriptedHook
@ eScriptedExtensionParsedCommand
@ eScriptedExtensionScriptedPlatform
@ eScriptedExtensionScriptedCommand
@ eScriptedExtensionScriptedProcess
@ eScriptedExtensionScriptedFrame
@ eScriptedExtensionScriptedBreakpointResolver
@ eScriptedExtensionScriptedThreadPlan
@ eScriptedExtensionScriptedStringSummary
@ eScriptedExtensionScriptedFrameProvider
@ eScriptedExtensionScriptedThread
@ eScriptedExtensionScriptedStackFrameRecognizer
@ eScriptedExtensionScriptedSyntheticChildren
@ eScriptedExtensionInvalid
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::Debugger > DebuggerSP
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