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 
29 namespace lldb_private {
30 
31 class ScriptInterpreterLocker {
32 public:
33   ScriptInterpreterLocker() = default;
34 
35   virtual ~ScriptInterpreterLocker() = default;
36 
37 private:
38   ScriptInterpreterLocker(const ScriptInterpreterLocker &) = delete;
39   const ScriptInterpreterLocker &
40   operator=(const ScriptInterpreterLocker &) = delete;
41 };
42 
43 class ExecuteScriptOptions {
44 public:
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 
71 private:
72   bool m_enable_io = true;
73   bool m_set_lldb_globals = true;
74   bool m_maskout_errors = true;
75 };
76 
77 class LoadScriptOptions {
78 public:
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 
94 private:
95   bool m_init_session = false;
96   bool m_silent = false;
97 };
98 
99 class ScriptInterpreterIORedirect {
100 public:
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 
116 private:
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 
128 class ScriptInterpreter : public PluginInterface {
129 public:
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 
589 protected:
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