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