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#include "llvm/ADT/StringSwitch.h"
20#if defined(_WIN32)
22#endif
23#include <cstdio>
24#include <cstdlib>
25#include <memory>
26#include <optional>
27#include <string>
28
29using namespace lldb;
30using namespace lldb_private;
31
33 lldb::ScriptLanguage script_lang)
34 : m_debugger(debugger), m_script_lang(script_lang) {}
35
37 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
38 CommandReturnObject &result) {
39 result.AppendError(
40 "This script interpreter does not support breakpoint callbacks.");
41}
42
44 WatchpointOptions *bp_options, CommandReturnObject &result) {
45 result.AppendError(
46 "This script interpreter does not support watchpoint callbacks.");
47}
48
52
54 const std::string &name, std::vector<ExtensionTemplateRequest> &extensions,
55 bool generate_non_abstract_methods, std::string output_file) {
56 return llvm::make_error<UnimplementedError>();
57}
58
60 const char *filename, const LoadScriptOptions &options,
62 FileSpec extra_search_dir, lldb::TargetSP loaded_into_target_sp) {
64 "This script interpreter does not support importing modules.");
65 return false;
66}
67
69 switch (language) {
71 return "None";
73 return "Python";
75 return "Lua";
77 return "Unknown";
78 }
79 llvm_unreachable("Unhandled ScriptInterpreter!");
80}
81
83ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) {
84 if (language.equals_insensitive(LanguageToString(eScriptLanguageNone)))
86 if (language.equals_insensitive(LanguageToString(eScriptLanguagePython)))
88 if (language.equals_insensitive(LanguageToString(eScriptLanguageLua)))
89 return eScriptLanguageLua;
91}
92
93llvm::StringLiteral
95 switch (extension) {
97 return "Invalid";
99 return "OperatingSystem";
101 return "ScriptedPlatform";
103 return "ScriptedProcess";
105 return "ScriptedBreakpointResolver";
107 return "ScriptedThreadPlan";
109 return "ScriptedFrameProvider";
111 return "ScriptedHook";
113 return "ScriptedThread";
115 return "ScriptedFrame";
117 return "ScriptedStackFrameRecognizer";
119 return "ScriptedCommand";
121 return "ParsedCommand";
123 return "ScriptedStringSummary";
125 return "ScriptedSyntheticChildren";
126 }
127 llvm_unreachable("unhandled ScriptedExtension");
128}
129
132 return llvm::StringSwitch<lldb::ScriptedExtension>(string)
133 .CaseLower("OperatingSystem", eScriptedExtensionOperatingSystem)
134 .CaseLower("ScriptedPlatform", eScriptedExtensionScriptedPlatform)
135 .CaseLower("ScriptedProcess", eScriptedExtensionScriptedProcess)
136 .CaseLower("ScriptedBreakpointResolver",
138 .CaseLower("ScriptedThreadPlan", eScriptedExtensionScriptedThreadPlan)
139 .CaseLower("ScriptedFrameProvider",
141 .CaseLower("ScriptedHook", eScriptedExtensionScriptedHook)
142 .CaseLower("ScriptedThread", eScriptedExtensionScriptedThread)
143 .CaseLower("ScriptedFrame", eScriptedExtensionScriptedFrame)
144 .CaseLower("ScriptedStackFrameRecognizer",
146 .CaseLower("ScriptedCommand", eScriptedExtensionScriptedCommand)
147 .CaseLower("ParsedCommand", eScriptedExtensionParsedCommand)
148 .CaseLower("ScriptedStringSummary",
150 .CaseLower("ScriptedSyntheticChildren",
153}
154
156 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
157 const char *callback_text) {
158 for (BreakpointOptions &bp_options : bp_options_vec)
159 if (llvm::Error error = SetBreakpointCommandCallback(
160 bp_options, callback_text, /*is_callback=*/false))
161 return error;
162 return llvm::Error::success();
163}
164
166 std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
167 const char *function_name, StructuredData::ObjectSP extra_args_sp) {
168 for (BreakpointOptions &bp_options : bp_options_vec)
170 bp_options, function_name, extra_args_sp))
171 return error;
172 return llvm::Error::success();
173}
174
175std::unique_ptr<ScriptInterpreterLocker>
177 return std::make_unique<ScriptInterpreterLocker>();
178}
179
182 std::string sanitized_name(name);
183 std::string conflicting_keyword;
184
185 // FIXME: for Python, don't allow certain characters in imported module
186 // filenames. Theoretically, different scripting languages may have
187 // different sets of forbidden tokens in filenames, and that should
188 // be dealt with by each ScriptInterpreter. For now, just replace dots
189 // with underscores. In order to support anything other than Python
190 // this will need to be reworked.
191 llvm::replace(sanitized_name, '.', '_');
192 llvm::replace(sanitized_name, ' ', '_');
193 llvm::replace(sanitized_name, '-', '_');
194 llvm::replace(sanitized_name, '+', 'x');
195
196 if (IsReservedWord(sanitized_name.c_str())) {
197 conflicting_keyword = sanitized_name;
198 sanitized_name.insert(sanitized_name.begin(), '_');
199 }
200
202 name.str(), std::move(sanitized_name), std::move(conflicting_keyword));
203}
204
205static void ReadThreadBytesReceived(void *baton, const void *src,
206 size_t src_len) {
207 if (src && src_len) {
208 Stream *strm = (Stream *)baton;
209 strm->Write(src, src_len);
210 strm->Flush();
211 }
212}
213
214llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
216 CommandReturnObject *result) {
217 if (enable_io)
218 return std::unique_ptr<ScriptInterpreterIORedirect>(
219 new ScriptInterpreterIORedirect(debugger, result));
220
223 if (!nullin)
224 return nullin.takeError();
225
228 if (!nullout)
229 return nullout.takeError();
230
231 return std::unique_ptr<ScriptInterpreterIORedirect>(
232 new ScriptInterpreterIORedirect(std::move(*nullin), std::move(*nullout)));
233}
234
236 std::unique_ptr<File> input, std::unique_ptr<File> output)
237 : m_input_file_sp(std::move(input)),
238 m_output_file_sp(std::make_shared<LockableStreamFile>(std::move(output),
241 m_communication("lldb.ScriptInterpreterIORedirect.comm"),
242 m_disconnect(false) {}
243
245 Debugger &debugger, CommandReturnObject *result)
246 : m_communication("lldb.ScriptInterpreterIORedirect.comm"),
247 m_disconnect(false) {
248
249 if (result) {
250 m_input_file_sp = debugger.GetInputFileSP();
251
252 Pipe pipe;
253 Status pipe_result = pipe.CreateNew();
254#if defined(_WIN32)
255 lldb::file_t read_file = pipe.GetReadNativeHandle();
257 std::unique_ptr<ConnectionGenericFile> conn_up =
258 std::make_unique<ConnectionGenericFile>(read_file, true);
259#else
260 std::unique_ptr<ConnectionFileDescriptor> conn_up =
261 std::make_unique<ConnectionFileDescriptor>(
262 pipe.ReleaseReadFileDescriptor(), true);
263#endif
264
265 if (conn_up->IsConnected()) {
266 m_communication.SetConnection(std::move(conn_up));
267 m_communication.SetReadThreadBytesReceivedCallback(
269 m_communication.StartReadThread();
270 m_disconnect = true;
271
272 FILE *outfile_handle = fdopen(pipe.ReleaseWriteFileDescriptor(), "w");
273 m_output_file_sp = std::make_shared<LockableStreamFile>(
274 std::make_shared<StreamFile>(outfile_handle, NativeFile::Owned),
277 if (outfile_handle)
278 ::setbuf(outfile_handle, nullptr);
279
280 result->SetImmediateOutputFile(debugger.GetOutputFileSP());
281 result->SetImmediateErrorFile(debugger.GetErrorFileSP());
282 }
283 }
284
288}
289
292 m_output_file_sp->Lock().Flush();
293 if (m_error_file_sp)
294 m_error_file_sp->Lock().Flush();
295}
296
298 if (!m_disconnect)
299 return;
300
301 assert(m_output_file_sp);
302 assert(m_error_file_sp);
304
305 // Close the write end of the pipe since we are done with our one line
306 // script. This should cause the read thread that output_comm is using to
307 // exit.
308 m_output_file_sp->GetUnlockedFile().Close();
309 // The close above should cause this thread to exit when it gets to the end
310 // of file, so let it get all its data.
311 m_communication.JoinReadThread();
312 // Now we can close the read end of the pipe.
313 m_communication.Disconnect();
314}
static llvm::raw_ostream & error(Stream &strm)
static void ReadThreadBytesReceived(void *baton, const void *src, size_t src_len)
"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:106
lldb::FileSP GetInputFileSP()
Definition Debugger.h:165
lldb::FileSP GetErrorFileSP()
Definition Debugger.h:172
lldb::FileSP GetOutputFileSP()
Definition Debugger.h:168
void AdoptTopIOHandlerFilesIfInvalid(lldb::FileSP &in, lldb::LockableStreamFileSP &out, lldb::LockableStreamFileSP &err)
A file utility class.
Definition FileSpec.h:56
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)
virtual llvm::Expected< FileSpec > GenerateExtensionTemplate(const std::string &name, std::vector< ExtensionTemplateRequest > &extensions, bool generate_non_abstract_methods, std::string output_file)
static llvm::StringLiteral ExtensionToString(lldb::ScriptedExtension extension)
static lldb::ScriptedExtension StringToExtension(llvm::StringRef string)
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)
virtual std::unique_ptr< ScriptInterpreterLocker > AcquireInterpreterLock()
virtual StructuredData::DictionarySP GetInterpreterInfo()
llvm::Error SetBreakpointCommandCallbackFunction(std::vector< std::reference_wrapper< BreakpointOptions > > &bp_options_vec, const char *function_name, StructuredData::ObjectSP extra_args_sp)
llvm::Error SetBreakpointCommandCallback(std::vector< std::reference_wrapper< BreakpointOptions > > &bp_options_vec, const char *callback_text)
Set the specified text as the callback for the breakpoint.
virtual bool IsReservedWord(const char *word)
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
"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::Target > TargetSP