1//===-- ScriptInterpreter.h -------------------------------------*- C++ -*-===//
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#ifndef LLDB_INTERPRETER_SCRIPTINTERPRETER_H
10#define LLDB_INTERPRETER_SCRIPTINTERPRETER_H
11
12#include "lldb/API/SBData.h"
13#include "lldb/API/SBError.h"
14#include "lldb/API/SBMemoryRegionInfo.h"
15#include "lldb/Breakpoint/BreakpointOptions.h"
16#include "lldb/Core/PluginInterface.h"
17#include "lldb/Core/SearchFilter.h"
18#include "lldb/Core/StreamFile.h"
19#include "lldb/Core/ThreadedCommunication.h"
20#include "lldb/Host/PseudoTerminal.h"
21#include "lldb/Interpreter/ScriptedPlatformInterface.h"
22#include "lldb/Interpreter/ScriptedProcessInterface.h"
23#include "lldb/Utility/Broadcaster.h"
24#include "lldb/Utility/Status.h"
25#include "lldb/Utility/StructuredData.h"
26#include "lldb/lldb-private.h"
27#include <optional>
28
29namespace lldb_private {
30
31class ScriptInterpreterLocker {
32public:
33  ScriptInterpreterLocker() = default;
34
35  virtual ~ScriptInterpreterLocker() = default;
36
37private:
38  ScriptInterpreterLocker(const ScriptInterpreterLocker &) = delete;
39  const ScriptInterpreterLocker &
40  operator=(const ScriptInterpreterLocker &) = delete;
41};
42
43class ExecuteScriptOptions {
44public:
45  ExecuteScriptOptions() = default;
46
47  bool GetEnableIO() const { return m_enable_io; }
48
49  bool GetSetLLDBGlobals() const { return m_set_lldb_globals; }
50
51  // If this is true then any exceptions raised by the script will be
52  // cleared with PyErr_Clear().   If false then they will be left for
53  // the caller to clean up
54  bool GetMaskoutErrors() const { return m_maskout_errors; }
55
56  ExecuteScriptOptions &SetEnableIO(bool enable) {
57    m_enable_io = enable;
58    return *this;
59  }
60
61  ExecuteScriptOptions &SetSetLLDBGlobals(bool set) {
62    m_set_lldb_globals = set;
63    return *this;
64  }
65
66  ExecuteScriptOptions &SetMaskoutErrors(bool maskout) {
67    m_maskout_errors = maskout;
68    return *this;
69  }
70
71private:
72  bool m_enable_io = true;
73  bool m_set_lldb_globals = true;
74  bool m_maskout_errors = true;
75};
76
77class LoadScriptOptions {
78public:
79  LoadScriptOptions() = default;
80
81  bool GetInitSession() const { return m_init_session; }
82  bool GetSilent() const { return m_silent; }
83
84  LoadScriptOptions &SetInitSession(bool b) {
85    m_init_session = b;
86    return *this;
87  }
88
89  LoadScriptOptions &SetSilent(bool b) {
90    m_silent = b;
91    return *this;
92  }
93
94private:
95  bool m_init_session = false;
96  bool m_silent = false;
97};
98
99class ScriptInterpreterIORedirect {
100public:
101  /// Create an IO redirect. If IO is enabled, this will redirects the output
102  /// to the command return object if set or to the debugger otherwise. If IO
103  /// is disabled, it will redirect all IO to /dev/null.
104  static llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
105  Create(bool enable_io, Debugger &debugger, CommandReturnObject *result);
106
107  ~ScriptInterpreterIORedirect();
108
109  lldb::FileSP GetInputFile() const { return m_input_file_sp; }
110  lldb::FileSP GetOutputFile() const { return m_output_file_sp->GetFileSP(); }
111  lldb::FileSP GetErrorFile() const { return m_error_file_sp->GetFileSP(); }
112
113  /// Flush our output and error file handles.
114  void Flush();
115
116private:
117  ScriptInterpreterIORedirect(std::unique_ptr<File> input,
118                              std::unique_ptr<File> output);
119  ScriptInterpreterIORedirect(Debugger &debugger, CommandReturnObject *result);
120
121  lldb::FileSP m_input_file_sp;
122  lldb::StreamFileSP m_output_file_sp;
123  lldb::StreamFileSP m_error_file_sp;
124  ThreadedCommunication m_communication;
125  bool m_disconnect;
126};
127
128class ScriptInterpreter : public PluginInterface {
129public:
130  enum ScriptReturnType {
131    eScriptReturnTypeCharPtr,
132    eScriptReturnTypeBool,
133    eScriptReturnTypeShortInt,
134    eScriptReturnTypeShortIntUnsigned,
135    eScriptReturnTypeInt,
136    eScriptReturnTypeIntUnsigned,
137    eScriptReturnTypeLongInt,
138    eScriptReturnTypeLongIntUnsigned,
139    eScriptReturnTypeLongLong,
140    eScriptReturnTypeLongLongUnsigned,
141    eScriptReturnTypeFloat,
142    eScriptReturnTypeDouble,
143    eScriptReturnTypeChar,
144    eScriptReturnTypeCharStrOrNone,
145    eScriptReturnTypeOpaqueObject
146  };
147
148  ScriptInterpreter(
149      Debugger &debugger, lldb::ScriptLanguage script_lang,
150      lldb::ScriptedProcessInterfaceUP scripted_process_interface_up =
151          std::make_unique<ScriptedProcessInterface>(),
152      lldb::ScriptedPlatformInterfaceUP scripted_platform_interface_up =
153          std::make_unique<ScriptedPlatformInterface>());
154
155  virtual StructuredData::DictionarySP GetInterpreterInfo();
156
157  ~ScriptInterpreter() override = default;
158
159  virtual bool Interrupt() { return false; }
160
161  virtual bool ExecuteOneLine(
162      llvm::StringRef command, CommandReturnObject *result,
163      const ExecuteScriptOptions &options = ExecuteScriptOptions()) = 0;
164
165  virtual void ExecuteInterpreterLoop() = 0;
166
167  virtual bool ExecuteOneLineWithReturn(
168      llvm::StringRef in_string, ScriptReturnType return_type, void *ret_value,
169      const ExecuteScriptOptions &options = ExecuteScriptOptions()) {
170    return true;
171  }
172
173  virtual Status ExecuteMultipleLines(
174      const char *in_string,
175      const ExecuteScriptOptions &options = ExecuteScriptOptions()) {
176    Status error;
177    error.SetErrorString("not implemented");
178    return error;
179  }
180
181  virtual Status
182  ExportFunctionDefinitionToInterpreter(StringList &function_def) {
183    Status error;
184    error.SetErrorString("not implemented");
185    return error;
186  }
187
188  virtual Status GenerateBreakpointCommandCallbackData(
189      StringList &input,
190      std::string &output,
191      bool has_extra_args) {
192    Status error;
193    error.SetErrorString("not implemented");
194    return error;
195  }
196
197  virtual bool GenerateWatchpointCommandCallbackData(StringList &input,
198                                                     std::string &output) {
199    return false;
200  }
201
202  virtual bool GenerateTypeScriptFunction(const char *oneliner,
203                                          std::string &output,
204                                          const void *name_token = nullptr) {
205    return false;
206  }
207
208  virtual bool GenerateTypeScriptFunction(StringList &input,
209                                          std::string &output,
210                                          const void *name_token = nullptr) {
211    return false;
212  }
213
214  virtual bool GenerateScriptAliasFunction(StringList &input,
215                                           std::string &output) {
216    return false;
217  }
218
219  virtual bool GenerateTypeSynthClass(StringList &input, std::string &output,
220                                      const void *name_token = nullptr) {
221    return false;
222  }
223
224  virtual bool GenerateTypeSynthClass(const char *oneliner, std::string &output,
225                                      const void *name_token = nullptr) {
226    return false;
227  }
228
229  virtual StructuredData::ObjectSP
230  CreateSyntheticScriptedProvider(const char *class_name,
231                                  lldb::ValueObjectSP valobj) {
232    return StructuredData::ObjectSP();
233  }
234
235  virtual StructuredData::GenericSP
236  CreateScriptCommandObject(const char *class_name) {
237    return StructuredData::GenericSP();
238  }
239
240  virtual StructuredData::GenericSP
241  CreateFrameRecognizer(const char *class_name) {
242    return StructuredData::GenericSP();
243  }
244
245  virtual lldb::ValueObjectListSP GetRecognizedArguments(
246      const StructuredData::ObjectSP &implementor,
247      lldb::StackFrameSP frame_sp) {
248    return lldb::ValueObjectListSP();
249  }
250
251  virtual StructuredData::GenericSP
252  OSPlugin_CreatePluginObject(const char *class_name,
253                              lldb::ProcessSP process_sp) {
254    return StructuredData::GenericSP();
255  }
256
257  virtual StructuredData::DictionarySP
258  OSPlugin_RegisterInfo(StructuredData::ObjectSP os_plugin_object_sp) {
259    return StructuredData::DictionarySP();
260  }
261
262  virtual StructuredData::ArraySP
263  OSPlugin_ThreadsInfo(StructuredData::ObjectSP os_plugin_object_sp) {
264    return StructuredData::ArraySP();
265  }
266
267  virtual StructuredData::StringSP
268  OSPlugin_RegisterContextData(StructuredData::ObjectSP os_plugin_object_sp,
269                               lldb::tid_t thread_id) {
270    return StructuredData::StringSP();
271  }
272
273  virtual StructuredData::DictionarySP
274  OSPlugin_CreateThread(StructuredData::ObjectSP os_plugin_object_sp,
275                        lldb::tid_t tid, lldb::addr_t context) {
276    return StructuredData::DictionarySP();
277  }
278
279  virtual StructuredData::ObjectSP
280  CreateScriptedThreadPlan(const char *class_name,
281                           const StructuredDataImpl &args_data,
282                           std::string &error_str,
283                           lldb::ThreadPlanSP thread_plan_sp) {
284    return StructuredData::ObjectSP();
285  }
286
287  virtual bool
288  ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp,
289                                 Event *event, bool &script_error) {
290    script_error = true;
291    return true;
292  }
293
294  virtual bool
295  ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp,
296                               Event *event, bool &script_error) {
297    script_error = true;
298    return true;
299  }
300
301  virtual bool
302  ScriptedThreadPlanIsStale(StructuredData::ObjectSP implementor_sp,
303                            bool &script_error) {
304    script_error = true;
305    return true;
306  }
307
308  virtual lldb::StateType
309  ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp,
310                                bool &script_error) {
311    script_error = true;
312    return lldb::eStateStepping;
313  }
314
315  virtual StructuredData::GenericSP
316  CreateScriptedBreakpointResolver(const char *class_name,
317                                   const StructuredDataImpl &args_data,
318                                   lldb::BreakpointSP &bkpt_sp) {
319    return StructuredData::GenericSP();
320  }
321
322  virtual bool
323  ScriptedBreakpointResolverSearchCallback(StructuredData::GenericSP implementor_sp,
324                                           SymbolContext *sym_ctx)
325  {
326    return false;
327  }
328
329  virtual lldb::SearchDepth
330  ScriptedBreakpointResolverSearchDepth(StructuredData::GenericSP implementor_sp)
331  {
332    return lldb::eSearchDepthModule;
333  }
334
335  virtual StructuredData::GenericSP
336  CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name,
337                         const StructuredDataImpl &args_data, Status &error) {
338    error.SetErrorString("Creating scripted stop-hooks with the current "
339                         "script interpreter is not supported.");
340    return StructuredData::GenericSP();
341  }
342
343  // This dispatches to the handle_stop method of the stop-hook class.  It
344  // returns a "should_stop" bool.
345  virtual bool
346  ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp,
347                             ExecutionContext &exc_ctx,
348                             lldb::StreamSP stream_sp) {
349    return true;
350  }
351
352  virtual StructuredData::ObjectSP
353  LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) {
354    return StructuredData::ObjectSP();
355  }
356
357  virtual StructuredData::DictionarySP
358  GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target,
359                     const char *setting_name, lldb_private::Status &error) {
360    return StructuredData::DictionarySP();
361  }
362
363  virtual Status GenerateFunction(const char *signature,
364                                  const StringList &input) {
365    Status error;
366    error.SetErrorString("unimplemented");
367    return error;
368  }
369
370  virtual void CollectDataForBreakpointCommandCallback(
371      std::vector<std::reference_wrapper<BreakpointOptions>> &options,
372      CommandReturnObject &result);
373
374  virtual void
375  CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
376                                          CommandReturnObject &result);
377
378  /// Set the specified text as the callback for the breakpoint.
379  Status SetBreakpointCommandCallback(
380      std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
381      const char *callback_text);
382
383  virtual Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,
384                                              const char *callback_text) {
385    Status error;
386    error.SetErrorString("unimplemented");
387    return error;
388  }
389
390  /// This one is for deserialization:
391  virtual Status SetBreakpointCommandCallback(
392      BreakpointOptions &bp_options,
393      std::unique_ptr<BreakpointOptions::CommandData> &data_up) {
394    Status error;
395    error.SetErrorString("unimplemented");
396    return error;
397  }
398
399  Status SetBreakpointCommandCallbackFunction(
400      std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
401      const char *function_name, StructuredData::ObjectSP extra_args_sp);
402
403  /// Set a script function as the callback for the breakpoint.
404  virtual Status
405  SetBreakpointCommandCallbackFunction(BreakpointOptions &bp_options,
406                                       const char *function_name,
407                                       StructuredData::ObjectSP extra_args_sp) {
408    Status error;
409    error.SetErrorString("unimplemented");
410    return error;
411  }
412
413  /// Set a one-liner as the callback for the watchpoint.
414  virtual void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
415                                            const char *oneliner) {}
416
417  virtual bool GetScriptedSummary(const char *function_name,
418                                  lldb::ValueObjectSP valobj,
419                                  StructuredData::ObjectSP &callee_wrapper_sp,
420                                  const TypeSummaryOptions &options,
421                                  std::string &retval) {
422    return false;
423  }
424
425  // Calls the specified formatter matching Python function and returns its
426  // result (true if it's a match, false if we should keep looking for a
427  // matching formatter).
428  virtual bool FormatterCallbackFunction(const char *function_name,
429                                         lldb::TypeImplSP type_impl_sp) {
430    return true;
431  }
432
433  virtual void Clear() {
434    // Clean up any ref counts to SBObjects that might be in global variables
435  }
436
437  virtual size_t
438  CalculateNumChildren(const StructuredData::ObjectSP &implementor,
439                       uint32_t max) {
440    return 0;
441  }
442
443  virtual lldb::ValueObjectSP
444  GetChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) {
445    return lldb::ValueObjectSP();
446  }
447
448  virtual int
449  GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor,
450                          const char *child_name) {
451    return UINT32_MAX;
452  }
453
454  virtual bool
455  UpdateSynthProviderInstance(const StructuredData::ObjectSP &implementor) {
456    return false;
457  }
458
459  virtual bool MightHaveChildrenSynthProviderInstance(
460      const StructuredData::ObjectSP &implementor) {
461    return true;
462  }
463
464  virtual lldb::ValueObjectSP
465  GetSyntheticValue(const StructuredData::ObjectSP &implementor) {
466    return nullptr;
467  }
468
469  virtual ConstString
470  GetSyntheticTypeName(const StructuredData::ObjectSP &implementor) {
471    return ConstString();
472  }
473
474  virtual bool
475  RunScriptBasedCommand(const char *impl_function, llvm::StringRef args,
476                        ScriptedCommandSynchronicity synchronicity,
477                        lldb_private::CommandReturnObject &cmd_retobj,
478                        Status &error,
479                        const lldb_private::ExecutionContext &exe_ctx) {
480    return false;
481  }
482
483  virtual bool RunScriptBasedCommand(
484      StructuredData::GenericSP impl_obj_sp, llvm::StringRef args,
485      ScriptedCommandSynchronicity synchronicity,
486      lldb_private::CommandReturnObject &cmd_retobj, Status &error,
487      const lldb_private::ExecutionContext &exe_ctx) {
488    return false;
489  }
490
491  virtual bool RunScriptFormatKeyword(const char *impl_function,
492                                      Process *process, std::string &output,
493                                      Status &error) {
494    error.SetErrorString("unimplemented");
495    return false;
496  }
497
498  virtual bool RunScriptFormatKeyword(const char *impl_function, Thread *thread,
499                                      std::string &output, Status &error) {
500    error.SetErrorString("unimplemented");
501    return false;
502  }
503
504  virtual bool RunScriptFormatKeyword(const char *impl_function, Target *target,
505                                      std::string &output, Status &error) {
506    error.SetErrorString("unimplemented");
507    return false;
508  }
509
510  virtual bool RunScriptFormatKeyword(const char *impl_function,
511                                      StackFrame *frame, std::string &output,
512                                      Status &error) {
513    error.SetErrorString("unimplemented");
514    return false;
515  }
516
517  virtual bool RunScriptFormatKeyword(const char *impl_function,
518                                      ValueObject *value, std::string &output,
519                                      Status &error) {
520    error.SetErrorString("unimplemented");
521    return false;
522  }
523
524  virtual bool GetDocumentationForItem(const char *item, std::string &dest) {
525    dest.clear();
526    return false;
527  }
528
529  virtual bool
530  GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
531                               std::string &dest) {
532    dest.clear();
533    return false;
534  }
535
536  virtual uint32_t
537  GetFlagsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
538    return 0;
539  }
540
541  virtual bool GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
542                                           std::string &dest) {
543    dest.clear();
544    return false;
545  }
546
547  virtual bool CheckObjectExists(const char *name) { return false; }
548
549  virtual bool
550  LoadScriptingModule(const char *filename, const LoadScriptOptions &options,
551                      lldb_private::Status &error,
552                      StructuredData::ObjectSP *module_sp = nullptr,
553                      FileSpec extra_search_dir = {});
554
555  virtual bool IsReservedWord(const char *word) { return false; }
556
557  virtual std::unique_ptr<ScriptInterpreterLocker> AcquireInterpreterLock();
558
559  const char *GetScriptInterpreterPtyName();
560
561  virtual llvm::Expected<unsigned>
562  GetMaxPositionalArgumentsForCallable(const llvm::StringRef &callable_name) {
563    return llvm::createStringError(
564    llvm::inconvertibleErrorCode(), "Unimplemented function");
565  }
566
567  static std::string LanguageToString(lldb::ScriptLanguage language);
568
569  static lldb::ScriptLanguage StringToLanguage(const llvm::StringRef &string);
570
571  lldb::ScriptLanguage GetLanguage() { return m_script_lang; }
572
573  ScriptedProcessInterface &GetScriptedProcessInterface() {
574    return *m_scripted_process_interface_up;
575  }
576
577  ScriptedPlatformInterface &GetScriptedPlatformInterface() {
578    return *m_scripted_platform_interface_up;
579  }
580
581  lldb::DataExtractorSP
582  GetDataExtractorFromSBData(const lldb::SBData &data) const;
583
584  Status GetStatusFromSBError(const lldb::SBError &error) const;
585
586  std::optional<MemoryRegionInfo> GetOpaqueTypeFromSBMemoryRegionInfo(
587      const lldb::SBMemoryRegionInfo &mem_region) const;
588
589protected:
590  Debugger &m_debugger;
591  lldb::ScriptLanguage m_script_lang;
592  lldb::ScriptedProcessInterfaceUP m_scripted_process_interface_up;
593  lldb::ScriptedPlatformInterfaceUP m_scripted_platform_interface_up;
594};
595
596} // namespace lldb_private
597
598#endif // LLDB_INTERPRETER_SCRIPTINTERPRETER_H
599