1 //===-- REPL.cpp ------------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "lldb/Core/Debugger.h"
15 #include "lldb/Core/PluginManager.h"
16 #include "lldb/Core/StreamFile.h"
17 #include "lldb/Expression/ExpressionVariable.h"
18 #include "lldb/Expression/REPL.h"
19 #include "lldb/Expression/UserExpression.h"
20 #include "lldb/Host/HostInfo.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/CommandReturnObject.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Utility/AnsiTerminal.h"
26 
27 using namespace lldb_private;
28 
29 REPL::REPL(LLVMCastKind kind, Target &target) :
30     m_target(target),
31     m_kind(kind)
32 {
33     // Make sure all option values have sane defaults
34     Debugger &debugger = m_target.GetDebugger();
35     CommandInterpreter &ci = debugger.GetCommandInterpreter();
36     m_format_options.OptionParsingStarting(ci);
37     m_varobj_options.OptionParsingStarting(ci);
38     m_command_options.OptionParsingStarting(ci);
39 
40     // Default certain settings for REPL regardless of the global settings.
41     m_command_options.unwind_on_error = false;
42     m_command_options.ignore_breakpoints = false;
43     m_command_options.debug = false;
44 }
45 
46 REPL::~REPL() = default;
47 
48 lldb::REPLSP
49 REPL::Create(Error &err, lldb::LanguageType language, Debugger *debugger, Target *target, const char *repl_options)
50 {
51     uint32_t idx = 0;
52     lldb::REPLSP ret;
53 
54     while (REPLCreateInstance create_instance = PluginManager::GetREPLCreateCallbackAtIndex(idx++))
55     {
56         ret = (*create_instance)(err, language, debugger, target, repl_options);
57         if (ret)
58         {
59             break;
60         }
61     }
62 
63     return ret;
64 }
65 
66 std::string
67 REPL::GetSourcePath()
68 {
69     ConstString file_basename = GetSourceFileBasename();
70 
71     FileSpec tmpdir_file_spec;
72     if (HostInfo::GetLLDBPath (lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec))
73     {
74         tmpdir_file_spec.GetFilename().SetCString(file_basename.AsCString());
75         m_repl_source_path = tmpdir_file_spec.GetPath();
76     }
77     else
78     {
79         tmpdir_file_spec = FileSpec("/tmp", false);
80         tmpdir_file_spec.AppendPathComponent(file_basename.AsCString());
81     }
82 
83     return tmpdir_file_spec.GetPath();
84 }
85 
86 lldb::IOHandlerSP
87 REPL::GetIOHandler()
88 {
89     if (!m_io_handler_sp)
90     {
91         Debugger &debugger = m_target.GetDebugger();
92         m_io_handler_sp.reset (new IOHandlerEditline (debugger,
93                                                       IOHandler::Type::REPL,
94                                                       "lldb-repl",     // Name of input reader for history
95                                                       "> ",             // prompt
96                                                       ". ",             // Continuation prompt
97                                                       true,             // Multi-line
98                                                       true,             // The REPL prompt is always colored
99                                                       1,                // Line number
100                                                       *this));
101 
102         // Don't exit if CTRL+C is pressed
103         static_cast<IOHandlerEditline *>(m_io_handler_sp.get())->SetInterruptExits(false);
104 
105         if (m_io_handler_sp->GetIsInteractive() && m_io_handler_sp->GetIsRealTerminal())
106         {
107             m_indent_str.assign (debugger.GetTabSize(), ' ');
108             m_enable_auto_indent = debugger.GetAutoIndent();
109         }
110         else
111         {
112             m_indent_str.clear();
113             m_enable_auto_indent = false;
114         }
115 
116     }
117     return m_io_handler_sp;
118 }
119 
120 void
121 REPL::IOHandlerActivated (IOHandler &io_handler)
122 {
123     lldb::ProcessSP process_sp = m_target.GetProcessSP();
124     if (process_sp && process_sp->IsAlive())
125         return;
126     lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
127     error_sp->Printf("REPL requires a running target process.\n");
128     io_handler.SetIsDone(true);
129 }
130 
131 bool
132 REPL::IOHandlerInterrupt (IOHandler &io_handler)
133 {
134     return false;
135 }
136 
137 void
138 REPL::IOHandlerInputInterrupted (IOHandler &io_handler,
139                                  std::string &line)
140 {
141 }
142 
143 const char *
144 REPL::IOHandlerGetFixIndentationCharacters()
145 {
146     return (m_enable_auto_indent ? GetAutoIndentCharacters() : nullptr);
147 }
148 
149 ConstString
150 REPL::IOHandlerGetControlSequence (char ch)
151 {
152     if (ch == 'd')
153         return ConstString(":quit\n");
154     return ConstString();
155 }
156 
157 const char *
158 REPL::IOHandlerGetCommandPrefix ()
159 {
160     return ":";
161 }
162 
163 const char *
164 REPL::IOHandlerGetHelpPrologue ()
165 {
166     return "\nThe REPL (Read-Eval-Print-Loop) acts like an interpreter.  "
167     "Valid statements, expressions, and declarations are immediately compiled and executed.\n\n"
168     "The complete set of LLDB debugging commands are also available as described below.  Commands "
169     "must be prefixed with a colon at the REPL prompt (:quit for example.)  Typing just a colon "
170     "followed by return will switch to the LLDB prompt.\n\n";
171 }
172 
173 bool
174 REPL::IOHandlerIsInputComplete (IOHandler &io_handler,
175                                 StringList &lines)
176 {
177     // Check for meta command
178     const size_t num_lines = lines.GetSize();
179     if (num_lines == 1)
180     {
181         const char *first_line = lines.GetStringAtIndex(0);
182         if (first_line[0] == ':')
183             return true; // Meta command is a single line where that starts with ':'
184     }
185 
186     // Check if REPL input is done
187     std::string source_string (lines.CopyList());
188     return SourceIsComplete(source_string);
189 }
190 
191 int
192 REPL::CalculateActualIndentation (const StringList &lines)
193 {
194     std::string last_line = lines[lines.GetSize() - 1];
195 
196     int actual_indent = 0;
197     for (char &ch : last_line)
198     {
199         if (ch != ' ') break;
200         ++actual_indent;
201     }
202 
203     return actual_indent;
204 }
205 
206 int
207 REPL::IOHandlerFixIndentation (IOHandler &io_handler,
208                                const StringList &lines,
209                                int cursor_position)
210 {
211     if (!m_enable_auto_indent) return 0;
212 
213     if (!lines.GetSize())
214     {
215         return 0;
216     }
217 
218     int tab_size = io_handler.GetDebugger().GetTabSize();
219 
220     lldb::offset_t desired_indent = GetDesiredIndentation(lines,
221                                                           cursor_position,
222                                                           tab_size);
223 
224     int actual_indent = REPL::CalculateActualIndentation(lines);
225 
226     if (desired_indent == LLDB_INVALID_OFFSET)
227         return 0;
228 
229     return (int)desired_indent - actual_indent;
230 }
231 
232 void
233 REPL::IOHandlerInputComplete (IOHandler &io_handler, std::string &code)
234 {
235     lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFile());
236     lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFile());
237     bool extra_line = false;
238     bool did_quit = false;
239 
240     if (code.empty())
241     {
242         m_code.AppendString("");
243         static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1);
244     }
245     else
246     {
247         Debugger &debugger = m_target.GetDebugger();
248         CommandInterpreter &ci = debugger.GetCommandInterpreter();
249         extra_line = ci.GetSpaceReplPrompts();
250 
251         ExecutionContext exe_ctx (m_target.GetProcessSP()->GetThreadList().GetSelectedThread()->GetSelectedFrame().get());
252 
253         lldb::ProcessSP process_sp(exe_ctx.GetProcessSP());
254 
255         if (code[0] == ':')
256         {
257             // Meta command
258             // Strip the ':'
259             code.erase(0, 1);
260             if (Args::StripSpaces (code))
261             {
262                 // "lldb" was followed by arguments, so just execute the command dump the results
263 
264                 // Turn off prompt on quit in case the user types ":quit"
265                 const bool saved_prompt_on_quit = ci.GetPromptOnQuit();
266                 if (saved_prompt_on_quit)
267                     ci.SetPromptOnQuit(false);
268 
269                 // Execute the command
270                 CommandReturnObject result;
271                 result.SetImmediateOutputStream(output_sp);
272                 result.SetImmediateErrorStream(error_sp);
273                 ci.HandleCommand(code.c_str(), eLazyBoolNo, result);
274 
275                 if (saved_prompt_on_quit)
276                     ci.SetPromptOnQuit(true);
277 
278                 if (result.GetStatus() == lldb::eReturnStatusQuit)
279                 {
280                     did_quit = true;
281                     io_handler.SetIsDone(true);
282                     if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter))
283                     {
284                         // We typed "quit" or an alias to quit so we need to check if the
285                         // command interpreter is above us and tell it that it is done as well
286                         // so we don't drop back into the command interpreter if we have already
287                         // quit
288                         lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler());
289                         if (io_handler_sp)
290                             io_handler_sp->SetIsDone(true);
291                     }
292                 }
293             }
294             else
295             {
296                 // ":" was followed by no arguments, so push the LLDB command prompt
297                 if (debugger.CheckTopIOHandlerTypes(IOHandler::Type::REPL, IOHandler::Type::CommandInterpreter))
298                 {
299                     // If the user wants to get back to the command interpreter and the
300                     // command interpreter is what launched the REPL, then just let the
301                     // REPL exit and fall back to the command interpreter.
302                     io_handler.SetIsDone(true);
303                 }
304                 else
305                 {
306                     // The REPL wasn't launched the by the command interpreter, it is the
307                     // base IOHandler, so we need to get the command interpreter and
308                     lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler());
309                     if (io_handler_sp)
310                     {
311                         io_handler_sp->SetIsDone(false);
312                         debugger.PushIOHandler(ci.GetIOHandler());
313                     }
314                 }
315             }
316         }
317         else
318         {
319             // Unwind any expression we might have been running in case our REPL
320             // expression crashed and the user was looking around
321             if (m_dedicated_repl_mode)
322             {
323                 Thread *thread = exe_ctx.GetThreadPtr();
324                 if (thread && thread->UnwindInnermostExpression().Success())
325                 {
326                     thread->SetSelectedFrameByIndex(0, false);
327                     exe_ctx.SetFrameSP(thread->GetSelectedFrame());
328                 }
329             }
330 
331             const bool colorize_err = error_sp->GetFile().GetIsTerminalWithColors();
332 
333             EvaluateExpressionOptions expr_options;
334             expr_options.SetCoerceToId(m_varobj_options.use_objc);
335             expr_options.SetUnwindOnError(m_command_options.unwind_on_error);
336             expr_options.SetIgnoreBreakpoints (m_command_options.ignore_breakpoints);
337             expr_options.SetKeepInMemory(true);
338             expr_options.SetUseDynamic(m_varobj_options.use_dynamic);
339             expr_options.SetTryAllThreads(m_command_options.try_all_threads);
340             expr_options.SetGenerateDebugInfo(true);
341             expr_options.SetREPLEnabled (true);
342             expr_options.SetColorizeErrors(colorize_err);
343             expr_options.SetPoundLine(m_repl_source_path.c_str(), m_code.GetSize() + 1);
344             if (m_command_options.timeout > 0)
345                 expr_options.SetTimeoutUsec(m_command_options.timeout);
346             else
347                 expr_options.SetTimeoutUsec(0);
348 
349             expr_options.SetLanguage(GetLanguage());
350 
351             PersistentExpressionState *persistent_state = m_target.GetPersistentExpressionStateForLanguage(GetLanguage());
352 
353             const size_t var_count_before = persistent_state->GetSize();
354 
355             const char *expr_prefix = nullptr;
356             lldb::ValueObjectSP result_valobj_sp;
357             Error error;
358             lldb::ModuleSP jit_module_sp;
359             lldb::ExpressionResults execution_results = UserExpression::Evaluate (exe_ctx,
360                                                                                   expr_options,
361                                                                                   code.c_str(),
362                                                                                   expr_prefix,
363                                                                                   result_valobj_sp,
364                                                                                   error,
365                                                                                   0, // Line offset
366                                                                                   nullptr, // Fixed Expression
367                                                                                   &jit_module_sp);
368 
369             //CommandInterpreter &ci = debugger.GetCommandInterpreter();
370 
371             if (process_sp && process_sp->IsAlive())
372             {
373                 bool add_to_code = true;
374                 bool handled = false;
375                 if (result_valobj_sp)
376                 {
377                     lldb::Format format = m_format_options.GetFormat();
378 
379                     if (result_valobj_sp->GetError().Success())
380                     {
381                         handled |= PrintOneVariable(debugger, output_sp, result_valobj_sp);
382                     }
383                     else if (result_valobj_sp->GetError().GetError() == UserExpression::kNoResult)
384                     {
385                         if (format != lldb::eFormatVoid && debugger.GetNotifyVoid())
386                         {
387                             error_sp->PutCString("(void)\n");
388                             handled = true;
389                         }
390                     }
391                 }
392 
393                 if (debugger.GetPrintDecls())
394                 {
395                     for (size_t vi = var_count_before, ve = persistent_state->GetSize();
396                          vi != ve;
397                          ++vi)
398                     {
399                         lldb::ExpressionVariableSP persistent_var_sp = persistent_state->GetVariableAtIndex(vi);
400                         lldb::ValueObjectSP valobj_sp = persistent_var_sp->GetValueObject();
401 
402                         PrintOneVariable(debugger, output_sp, valobj_sp, persistent_var_sp.get());
403                     }
404                 }
405 
406                 if (!handled)
407                 {
408                     bool useColors = error_sp->GetFile().GetIsTerminalWithColors();
409                     switch (execution_results)
410                     {
411                         case lldb::eExpressionSetupError:
412                         case lldb::eExpressionParseError:
413                             add_to_code = false;
414                             LLVM_FALLTHROUGH;
415                         case lldb::eExpressionDiscarded:
416                             error_sp->Printf("%s\n", error.AsCString());
417                             break;
418 
419                         case lldb::eExpressionCompleted:
420                             break;
421                         case lldb::eExpressionInterrupted:
422                             if (useColors) {
423                                 error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
424                                 error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
425                             }
426                             error_sp->Printf("Execution interrupted. ");
427                             if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
428                             error_sp->Printf("Enter code to recover and continue.\nEnter LLDB commands to investigate (type :help for assistance.)\n");
429                             break;
430 
431                         case lldb::eExpressionHitBreakpoint:
432                             // Breakpoint was hit, drop into LLDB command interpreter
433                             if (useColors) {
434                                 error_sp->Printf(ANSI_ESCAPE1(ANSI_FG_COLOR_RED));
435                                 error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_BOLD));
436                             }
437                             output_sp->Printf("Execution stopped at breakpoint.  ");
438                             if (useColors) error_sp->Printf(ANSI_ESCAPE1(ANSI_CTRL_NORMAL));
439                             output_sp->Printf("Enter LLDB commands to investigate (type help for assistance.)\n");
440                         {
441                             lldb::IOHandlerSP io_handler_sp (ci.GetIOHandler());
442                             if (io_handler_sp)
443                             {
444                                 io_handler_sp->SetIsDone(false);
445                                 debugger.PushIOHandler(ci.GetIOHandler());
446                             }
447                         }
448                             break;
449 
450                         case lldb::eExpressionTimedOut:
451                             error_sp->Printf("error: timeout\n");
452                             if (error.AsCString())
453                                 error_sp->Printf("error: %s\n", error.AsCString());
454                             break;
455                         case lldb::eExpressionResultUnavailable:
456                             // Shoulnd't happen???
457                             error_sp->Printf("error: could not fetch result -- %s\n", error.AsCString());
458                             break;
459                         case lldb::eExpressionStoppedForDebug:
460                             // Shoulnd't happen???
461                             error_sp->Printf("error: stopped for debug -- %s\n", error.AsCString());
462                             break;
463                     }
464                 }
465 
466                 if (add_to_code)
467                 {
468                     const uint32_t new_default_line = m_code.GetSize() + 1;
469 
470                     m_code.SplitIntoLines(code);
471 
472                     // Update our code on disk
473                     if (!m_repl_source_path.empty())
474                     {
475                         lldb_private::File file (m_repl_source_path.c_str(),
476                                                  File::eOpenOptionWrite | File::eOpenOptionTruncate | File::eOpenOptionCanCreate,
477                                                  lldb::eFilePermissionsFileDefault);
478                         std::string code (m_code.CopyList());
479                         code.append(1, '\n');
480                         size_t bytes_written = code.size();
481                         file.Write(code.c_str(), bytes_written);
482                         file.Close();
483 
484                         // Now set the default file and line to the REPL source file
485                         m_target.GetSourceManager().SetDefaultFileAndLine(FileSpec(m_repl_source_path.c_str(), false), new_default_line);
486                     }
487                     static_cast<IOHandlerEditline &>(io_handler).SetBaseLineNumber(m_code.GetSize()+1);
488                 }
489                 if (extra_line)
490                 {
491                     fprintf(output_sp->GetFile().GetStream(), "\n");
492                 }
493             }
494         }
495 
496         // Don't complain about the REPL process going away if we are in the process of quitting.
497         if (!did_quit && (!process_sp || !process_sp->IsAlive()))
498         {
499             error_sp->Printf("error: REPL process is no longer alive, exiting REPL\n");
500             io_handler.SetIsDone(true);
501         }
502     }
503 }
504 
505 int
506 REPL::IOHandlerComplete (IOHandler &io_handler,
507                          const char *current_line,
508                          const char *cursor,
509                          const char *last_char,
510                          int skip_first_n_matches,
511                          int max_matches,
512                          StringList &matches)
513 {
514     matches.Clear();
515 
516     llvm::StringRef line (current_line, cursor - current_line);
517 
518     // Complete an LLDB command if the first character is a colon...
519     if (!line.empty() && line[0] == ':')
520     {
521         Debugger &debugger = m_target.GetDebugger();
522 
523         // auto complete LLDB commands
524         const char *lldb_current_line = line.substr(1).data();
525         return debugger.GetCommandInterpreter().HandleCompletion (lldb_current_line,
526                                                                   cursor,
527                                                                   last_char,
528                                                                   skip_first_n_matches,
529                                                                   max_matches,
530                                                                   matches);
531     }
532 
533     // Strip spaces from the line and see if we had only spaces
534     line = line.ltrim();
535     if (line.empty())
536     {
537         // Only spaces on this line, so just indent
538         matches.AppendString(m_indent_str);
539         return 1;
540     }
541 
542     std::string current_code;
543     current_code.append(m_code.CopyList());
544 
545     IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler);
546     const StringList *current_lines = editline.GetCurrentLines();
547     if (current_lines)
548     {
549         const uint32_t current_line_idx = editline.GetCurrentLineIndex();
550 
551         if (current_line_idx < current_lines->GetSize())
552         {
553             for (uint32_t i=0; i<current_line_idx; ++i)
554             {
555                 const char *line_cstr = current_lines->GetStringAtIndex(i);
556                 if (line_cstr)
557                 {
558                     current_code.append("\n");
559                     current_code.append (line_cstr);
560                 }
561             }
562         }
563     }
564 
565     if (cursor > current_line)
566     {
567         current_code.append("\n");
568         current_code.append(current_line, cursor - current_line);
569     }
570 
571     return CompleteCode(current_code, matches);
572 }
573 
574 bool
575 QuitCommandOverrideCallback(void *baton, const char **argv)
576 {
577     Target *target = (Target *)baton;
578     lldb::ProcessSP process_sp (target->GetProcessSP());
579     if (process_sp)
580     {
581         process_sp->Destroy(false);
582         process_sp->GetTarget().GetDebugger().ClearIOHandlers();
583     }
584     return false;
585 }
586 
587 Error
588 REPL::RunLoop ()
589 {
590     Error error;
591 
592     error = DoInitialization();
593     m_repl_source_path = GetSourcePath();
594 
595     if (!error.Success())
596         return error;
597 
598     Debugger &debugger = m_target.GetDebugger();
599 
600     lldb::IOHandlerSP io_handler_sp (GetIOHandler());
601 
602     FileSpec save_default_file;
603     uint32_t save_default_line = 0;
604 
605     if (!m_repl_source_path.empty())
606     {
607         // Save the current default file and line
608         m_target.GetSourceManager().GetDefaultFileAndLine(save_default_file, save_default_line);
609     }
610 
611     debugger.PushIOHandler(io_handler_sp);
612 
613     // Check if we are in dedicated REPL mode where LLDB was start with the "--repl" option
614     // from the command line. Currently we know this by checking if the debugger already
615     // has a IOHandler thread.
616     if (!debugger.HasIOHandlerThread())
617     {
618         // The debugger doesn't have an existing IOHandler thread, so this must be
619         // dedicated REPL mode...
620         m_dedicated_repl_mode = true;
621         debugger.StartIOHandlerThread();
622         std::string command_name_str ("quit");
623         CommandObject *cmd_obj = debugger.GetCommandInterpreter().GetCommandObjectForCommand(command_name_str);
624         if (cmd_obj)
625         {
626             assert(command_name_str.empty());
627             cmd_obj->SetOverrideCallback (QuitCommandOverrideCallback, &m_target);
628         }
629     }
630 
631     // Wait for the REPL command interpreter to get popped
632     io_handler_sp->WaitForPop();
633 
634     if (m_dedicated_repl_mode)
635     {
636         // If we were in dedicated REPL mode we would have started the
637         // IOHandler thread, and we should kill our process
638         lldb::ProcessSP process_sp = m_target.GetProcessSP();
639         if (process_sp && process_sp->IsAlive())
640             process_sp->Destroy(false);
641 
642         // Wait for the IO handler thread to exit (TODO: don't do this if the IO handler thread already exists...)
643         debugger.JoinIOHandlerThread();
644     }
645 
646     // Restore the default file and line
647     if (save_default_file && save_default_line != 0)
648         m_target.GetSourceManager().SetDefaultFileAndLine(save_default_file, save_default_line);
649     return error;
650 }
651