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