130fdc8d8SChris Lattner //===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner 
930fdc8d8SChris Lattner #include "Driver.h"
1030fdc8d8SChris Lattner 
11a382d474SEli Friedman #include "lldb/API/SBCommandInterpreter.h"
124b354039SJonas Devlieghere #include "lldb/API/SBCommandInterpreterRunOptions.h"
13a382d474SEli Friedman #include "lldb/API/SBCommandReturnObject.h"
14a382d474SEli Friedman #include "lldb/API/SBDebugger.h"
159eb13719SLawrence D'Anna #include "lldb/API/SBFile.h"
16a382d474SEli Friedman #include "lldb/API/SBHostOS.h"
173e7e915dSSean Callanan #include "lldb/API/SBLanguageRuntime.h"
18936c6242SJonas Devlieghere #include "lldb/API/SBReproducer.h"
1985e8b814SJim Ingham #include "lldb/API/SBStream.h"
20878ae018SJason Molenda #include "lldb/API/SBStringList.h"
21bbef51ebSLawrence D'Anna #include "lldb/API/SBStructuredData.h"
2200eae5eaSJonas Devlieghere 
232ad6e0a6SJonas Devlieghere #include "llvm/ADT/StringRef.h"
24b02baf0aSJonas Devlieghere #include "llvm/Support/Format.h"
254778f40fSMartin Storsjo #include "llvm/Support/InitLLVM.h"
2600eae5eaSJonas Devlieghere #include "llvm/Support/Path.h"
272ad6e0a6SJonas Devlieghere #include "llvm/Support/Signals.h"
28b02baf0aSJonas Devlieghere #include "llvm/Support/WithColor.h"
2900eae5eaSJonas Devlieghere #include "llvm/Support/raw_ostream.h"
3000eae5eaSJonas Devlieghere 
3100eae5eaSJonas Devlieghere #include <algorithm>
3200eae5eaSJonas Devlieghere #include <atomic>
3300eae5eaSJonas Devlieghere #include <bitset>
3472748488SJan Kratochvil #include <clocale>
3500eae5eaSJonas Devlieghere #include <csignal>
3600eae5eaSJonas Devlieghere #include <string>
37190fadcdSZachary Turner #include <thread>
385ce9dc61STatyana Krasnukha #include <utility>
3930fdc8d8SChris Lattner 
4076e47d48SRaphael Isemann #include <climits>
4176e47d48SRaphael Isemann #include <cstdio>
4276e47d48SRaphael Isemann #include <cstdlib>
4376e47d48SRaphael Isemann #include <cstring>
4400eae5eaSJonas Devlieghere #include <fcntl.h>
4500eae5eaSJonas Devlieghere 
46b82ad2a8STodd Fiala #if !defined(__APPLE__)
4740a069adSZachary Turner #include "llvm/Support/DataTypes.h"
48b82ad2a8STodd Fiala #endif
4940a069adSZachary Turner 
5030fdc8d8SChris Lattner using namespace lldb;
5100eae5eaSJonas Devlieghere using namespace llvm;
5200eae5eaSJonas Devlieghere 
5300eae5eaSJonas Devlieghere namespace {
5400eae5eaSJonas Devlieghere enum ID {
5500eae5eaSJonas Devlieghere   OPT_INVALID = 0, // This is not an option ID.
5600eae5eaSJonas Devlieghere #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
5700eae5eaSJonas Devlieghere                HELPTEXT, METAVAR, VALUES)                                      \
5800eae5eaSJonas Devlieghere   OPT_##ID,
5900eae5eaSJonas Devlieghere #include "Options.inc"
6000eae5eaSJonas Devlieghere #undef OPTION
6100eae5eaSJonas Devlieghere };
6200eae5eaSJonas Devlieghere 
6300eae5eaSJonas Devlieghere #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
6400eae5eaSJonas Devlieghere #include "Options.inc"
6500eae5eaSJonas Devlieghere #undef PREFIX
6600eae5eaSJonas Devlieghere 
67e6366a85SJonas Devlieghere const opt::OptTable::Info InfoTable[] = {
6800eae5eaSJonas Devlieghere #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM,  \
6900eae5eaSJonas Devlieghere                HELPTEXT, METAVAR, VALUES)                                      \
7000eae5eaSJonas Devlieghere   {                                                                            \
7100eae5eaSJonas Devlieghere       PREFIX,      NAME,      HELPTEXT,                                        \
7200eae5eaSJonas Devlieghere       METAVAR,     OPT_##ID,  opt::Option::KIND##Class,                        \
7300eae5eaSJonas Devlieghere       PARAM,       FLAGS,     OPT_##GROUP,                                     \
7400eae5eaSJonas Devlieghere       OPT_##ALIAS, ALIASARGS, VALUES},
7500eae5eaSJonas Devlieghere #include "Options.inc"
7600eae5eaSJonas Devlieghere #undef OPTION
7700eae5eaSJonas Devlieghere };
7800eae5eaSJonas Devlieghere 
7900eae5eaSJonas Devlieghere class LLDBOptTable : public opt::OptTable {
8000eae5eaSJonas Devlieghere public:
LLDBOptTable()8100eae5eaSJonas Devlieghere   LLDBOptTable() : OptTable(InfoTable) {}
8200eae5eaSJonas Devlieghere };
8300eae5eaSJonas Devlieghere } // namespace
8430fdc8d8SChris Lattner 
8530fdc8d8SChris Lattner static void reset_stdin_termios();
86f571b890SGreg Clayton static bool g_old_stdin_termios_is_valid = false;
8730fdc8d8SChris Lattner static struct termios g_old_stdin_termios;
8830fdc8d8SChris Lattner 
disable_color(const raw_ostream & OS)894429cf14SJonas Devlieghere static bool disable_color(const raw_ostream &OS) { return false; }
904429cf14SJonas Devlieghere 
91e6366a85SJonas Devlieghere static Driver *g_driver = nullptr;
92dd759857SCaroline Tice 
9330fdc8d8SChris Lattner // In the Driver::MainLoop, we change the terminal settings.  This function is
9430fdc8d8SChris Lattner // added as an atexit handler to make sure we clean them up.
reset_stdin_termios()95b9c1b51eSKate Stone static void reset_stdin_termios() {
96b9c1b51eSKate Stone   if (g_old_stdin_termios_is_valid) {
97f571b890SGreg Clayton     g_old_stdin_termios_is_valid = false;
9830fdc8d8SChris Lattner     ::tcsetattr(STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
9930fdc8d8SChris Lattner   }
100f571b890SGreg Clayton }
10130fdc8d8SChris Lattner 
Driver()102b9c1b51eSKate Stone Driver::Driver()
103e6366a85SJonas Devlieghere     : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)) {
104fc3f027dSGreg Clayton   // We want to be able to handle CTRL+D in the terminal to have it terminate
105fc3f027dSGreg Clayton   // certain input
106fc3f027dSGreg Clayton   m_debugger.SetCloseInputOnEOF(false);
107efed6131SCaroline Tice   g_driver = this;
10830fdc8d8SChris Lattner }
10930fdc8d8SChris Lattner 
~Driver()1106ac12b5bSJonas Devlieghere Driver::~Driver() {
1116ac12b5bSJonas Devlieghere   SBDebugger::Destroy(m_debugger);
1126ac12b5bSJonas Devlieghere   g_driver = nullptr;
1136ac12b5bSJonas Devlieghere }
11430fdc8d8SChris Lattner 
AddInitialCommand(std::string command,CommandPlacement placement,bool is_file,SBError & error)11500eae5eaSJonas Devlieghere void Driver::OptionData::AddInitialCommand(std::string command,
116b9c1b51eSKate Stone                                            CommandPlacement placement,
117b9c1b51eSKate Stone                                            bool is_file, SBError &error) {
1180f17c557SJim Ingham   std::vector<InitialCmdEntry> *command_set;
119b9c1b51eSKate Stone   switch (placement) {
1204add3b13SJim Ingham   case eCommandPlacementBeforeFile:
121ed3252fbSJim Ingham     command_set = &(m_initial_commands);
1224add3b13SJim Ingham     break;
1234add3b13SJim Ingham   case eCommandPlacementAfterFile:
124ed3252fbSJim Ingham     command_set = &(m_after_file_commands);
1254add3b13SJim Ingham     break;
1264add3b13SJim Ingham   case eCommandPlacementAfterCrash:
1274add3b13SJim Ingham     command_set = &(m_after_crash_commands);
1284add3b13SJim Ingham     break;
1294add3b13SJim Ingham   }
130ed3252fbSJim Ingham 
131b9c1b51eSKate Stone   if (is_file) {
13200eae5eaSJonas Devlieghere     SBFileSpec file(command.c_str());
133ed3252fbSJim Ingham     if (file.Exists())
1342edcad7bSJonas Devlieghere       command_set->push_back(InitialCmdEntry(command, is_file));
135b9c1b51eSKate Stone     else if (file.ResolveExecutableLocation()) {
136ed3252fbSJim Ingham       char final_path[PATH_MAX];
137ed3252fbSJim Ingham       file.GetPath(final_path, sizeof(final_path));
1382edcad7bSJonas Devlieghere       command_set->push_back(InitialCmdEntry(final_path, is_file));
139b9c1b51eSKate Stone     } else
140b9c1b51eSKate Stone       error.SetErrorStringWithFormat(
14100eae5eaSJonas Devlieghere           "file specified in --source (-s) option doesn't exist: '%s'",
14200eae5eaSJonas Devlieghere           command.c_str());
143b9c1b51eSKate Stone   } else
1442edcad7bSJonas Devlieghere     command_set->push_back(InitialCmdEntry(command, is_file));
145ed3252fbSJim Ingham }
146ed3252fbSJim Ingham 
WriteCommandsForSourcing(CommandPlacement placement,SBStream & strm)147b9c1b51eSKate Stone void Driver::WriteCommandsForSourcing(CommandPlacement placement,
148b9c1b51eSKate Stone                                       SBStream &strm) {
1490f17c557SJim Ingham   std::vector<OptionData::InitialCmdEntry> *command_set;
150b9c1b51eSKate Stone   switch (placement) {
1514add3b13SJim Ingham   case eCommandPlacementBeforeFile:
1524add3b13SJim Ingham     command_set = &m_option_data.m_initial_commands;
1534add3b13SJim Ingham     break;
1544add3b13SJim Ingham   case eCommandPlacementAfterFile:
1554add3b13SJim Ingham     command_set = &m_option_data.m_after_file_commands;
1564add3b13SJim Ingham     break;
1574add3b13SJim Ingham   case eCommandPlacementAfterCrash:
1584add3b13SJim Ingham     command_set = &m_option_data.m_after_crash_commands;
1594add3b13SJim Ingham     break;
1604add3b13SJim Ingham   }
16106357c93SGreg Clayton 
162b9c1b51eSKate Stone   for (const auto &command_entry : *command_set) {
1630f17c557SJim Ingham     const char *command = command_entry.contents.c_str();
164b9c1b51eSKate Stone     if (command_entry.is_file) {
165b9c1b51eSKate Stone       bool source_quietly =
166b9c1b51eSKate Stone           m_option_data.m_source_quietly || command_entry.source_quietly;
167e6366a85SJonas Devlieghere       strm.Printf("command source -s %i '%s'\n",
168e6366a85SJonas Devlieghere                   static_cast<int>(source_quietly), command);
169b9c1b51eSKate Stone     } else
17006357c93SGreg Clayton       strm.Printf("%s\n", command);
1716611103cSGreg Clayton   }
1726611103cSGreg Clayton }
1736611103cSGreg Clayton 
174b9c1b51eSKate Stone // Check the arguments that were passed to this program to make sure they are
17500eae5eaSJonas Devlieghere // valid and to get their argument values (if any).  Return a boolean value
17600eae5eaSJonas Devlieghere // indicating whether or not to start up the full debugger (i.e. the Command
17700eae5eaSJonas Devlieghere // Interpreter) or not.  Return FALSE if the arguments were invalid OR if the
17800eae5eaSJonas Devlieghere // user only wanted help or version information.
ProcessArgs(const opt::InputArgList & args,bool & exiting)179b02baf0aSJonas Devlieghere SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
18000eae5eaSJonas Devlieghere   SBError error;
1816611103cSGreg Clayton 
182b9c1b51eSKate Stone   // This is kind of a pain, but since we make the debugger in the Driver's
18300eae5eaSJonas Devlieghere   // constructor, we can't know at that point whether we should read in init
18400eae5eaSJonas Devlieghere   // files yet.  So we don't read them in in the Driver constructor, then set
18500eae5eaSJonas Devlieghere   // the flags back to "read them in" here, and then if we see the "-n" flag,
18600eae5eaSJonas Devlieghere   // we'll turn it off again.  Finally we have to read them in by hand later in
18700eae5eaSJonas Devlieghere   // the main loop.
18806942690SJim Ingham   m_debugger.SkipLLDBInitFiles(false);
18906942690SJim Ingham   m_debugger.SkipAppInitFiles(false);
19006942690SJim Ingham 
1914429cf14SJonas Devlieghere   if (args.hasArg(OPT_no_use_colors)) {
1924429cf14SJonas Devlieghere     m_debugger.SetUseColor(false);
1934429cf14SJonas Devlieghere     WithColor::setAutoDetectFunction(disable_color);
1944429cf14SJonas Devlieghere     m_option_data.m_debug_mode = true;
1954429cf14SJonas Devlieghere   }
1964429cf14SJonas Devlieghere 
19700eae5eaSJonas Devlieghere   if (args.hasArg(OPT_version)) {
19800eae5eaSJonas Devlieghere     m_option_data.m_print_version = true;
19930fdc8d8SChris Lattner   }
20030fdc8d8SChris Lattner 
20100eae5eaSJonas Devlieghere   if (args.hasArg(OPT_python_path)) {
202e2231ac7SJim Ingham     m_option_data.m_print_python_path = true;
20300eae5eaSJonas Devlieghere   }
204bbef51ebSLawrence D'Anna   if (args.hasArg(OPT_print_script_interpreter_info)) {
205bbef51ebSLawrence D'Anna     m_option_data.m_print_script_interpreter_info = true;
206bbef51ebSLawrence D'Anna   }
207e2231ac7SJim Ingham 
20800eae5eaSJonas Devlieghere   if (args.hasArg(OPT_batch)) {
209ffc9f1deSJim Ingham     m_option_data.m_batch = true;
21000eae5eaSJonas Devlieghere   }
211ffc9f1deSJim Ingham 
212cef2af0fSJonas Devlieghere   if (auto *arg = args.getLastArg(OPT_core)) {
213cef2af0fSJonas Devlieghere     auto arg_value = arg->getValue();
214cef2af0fSJonas Devlieghere     SBFileSpec file(arg_value);
215cef2af0fSJonas Devlieghere     if (!file.Exists()) {
216b9c1b51eSKate Stone       error.SetErrorStringWithFormat(
217cef2af0fSJonas Devlieghere           "file specified in --core (-c) option doesn't exist: '%s'",
218cef2af0fSJonas Devlieghere           arg_value);
21900eae5eaSJonas Devlieghere       return error;
22000eae5eaSJonas Devlieghere     }
221cef2af0fSJonas Devlieghere     m_option_data.m_core_file = arg_value;
22200eae5eaSJonas Devlieghere   }
2236eee5aa0SGreg Clayton 
22400eae5eaSJonas Devlieghere   if (args.hasArg(OPT_editor)) {
225e40e4218SJim Ingham     m_option_data.m_use_external_editor = true;
22600eae5eaSJonas Devlieghere   }
2276611103cSGreg Clayton 
22800eae5eaSJonas Devlieghere   if (args.hasArg(OPT_no_lldbinit)) {
2296eee5aa0SGreg Clayton     m_debugger.SkipLLDBInitFiles(true);
23006942690SJim Ingham     m_debugger.SkipAppInitFiles(true);
23100eae5eaSJonas Devlieghere   }
2326eee5aa0SGreg Clayton 
2337ffd9638SJonas Devlieghere   if (args.hasArg(OPT_local_lldbinit)) {
2347ffd9638SJonas Devlieghere     lldb::SBDebugger::SetInternalVariable("target.load-cwd-lldbinit", "true",
2357ffd9638SJonas Devlieghere                                           m_debugger.GetInstanceName());
2367ffd9638SJonas Devlieghere   }
2377ffd9638SJonas Devlieghere 
23800eae5eaSJonas Devlieghere   if (auto *arg = args.getLastArg(OPT_file)) {
239cef2af0fSJonas Devlieghere     auto arg_value = arg->getValue();
240cef2af0fSJonas Devlieghere     SBFileSpec file(arg_value);
241b9c1b51eSKate Stone     if (file.Exists()) {
242e6366a85SJonas Devlieghere       m_option_data.m_args.emplace_back(arg_value);
243b9c1b51eSKate Stone     } else if (file.ResolveExecutableLocation()) {
244428a9a58SCaroline Tice       char path[PATH_MAX];
24525f3a3cdSJohnny Chen       file.GetPath(path, sizeof(path));
246e6366a85SJonas Devlieghere       m_option_data.m_args.emplace_back(path);
24700eae5eaSJonas Devlieghere     } else {
248b9c1b51eSKate Stone       error.SetErrorStringWithFormat(
249cef2af0fSJonas Devlieghere           "file specified in --file (-f) option doesn't exist: '%s'",
250cef2af0fSJonas Devlieghere           arg_value);
25100eae5eaSJonas Devlieghere       return error;
25200eae5eaSJonas Devlieghere     }
25300eae5eaSJonas Devlieghere   }
2546611103cSGreg Clayton 
25500eae5eaSJonas Devlieghere   if (auto *arg = args.getLastArg(OPT_arch)) {
256cef2af0fSJonas Devlieghere     auto arg_value = arg->getValue();
257e6366a85SJonas Devlieghere     if (!lldb::SBDebugger::SetDefaultArchitecture(arg_value)) {
258b9c1b51eSKate Stone       error.SetErrorStringWithFormat(
259cef2af0fSJonas Devlieghere           "invalid architecture in the -a or --arch option: '%s'", arg_value);
26000eae5eaSJonas Devlieghere       return error;
26100eae5eaSJonas Devlieghere     }
26200eae5eaSJonas Devlieghere   }
2636611103cSGreg Clayton 
26400eae5eaSJonas Devlieghere   if (auto *arg = args.getLastArg(OPT_script_language)) {
265cef2af0fSJonas Devlieghere     auto arg_value = arg->getValue();
266de3d12f9SJonas Devlieghere     m_debugger.SetScriptLanguage(m_debugger.GetScriptingLanguage(arg_value));
26700eae5eaSJonas Devlieghere   }
2686611103cSGreg Clayton 
26900eae5eaSJonas Devlieghere   if (args.hasArg(OPT_source_quietly)) {
270ed3252fbSJim Ingham     m_option_data.m_source_quietly = true;
27100eae5eaSJonas Devlieghere   }
272ed3252fbSJim Ingham 
27300eae5eaSJonas Devlieghere   if (auto *arg = args.getLastArg(OPT_attach_name)) {
274cef2af0fSJonas Devlieghere     auto arg_value = arg->getValue();
275cef2af0fSJonas Devlieghere     m_option_data.m_process_name = arg_value;
27600eae5eaSJonas Devlieghere   }
277e64f0dc7SJim Ingham 
27800eae5eaSJonas Devlieghere   if (args.hasArg(OPT_wait_for)) {
279e64f0dc7SJim Ingham     m_option_data.m_wait_for = true;
28000eae5eaSJonas Devlieghere   }
281e64f0dc7SJim Ingham 
28200eae5eaSJonas Devlieghere   if (auto *arg = args.getLastArg(OPT_attach_pid)) {
283cef2af0fSJonas Devlieghere     auto arg_value = arg->getValue();
284e64f0dc7SJim Ingham     char *remainder;
285cef2af0fSJonas Devlieghere     m_option_data.m_process_pid = strtol(arg_value, &remainder, 0);
286cef2af0fSJonas Devlieghere     if (remainder == arg_value || *remainder != '\0') {
287b9c1b51eSKate Stone       error.SetErrorStringWithFormat(
288cef2af0fSJonas Devlieghere           "Could not convert process PID: \"%s\" into a pid.", arg_value);
28900eae5eaSJonas Devlieghere       return error;
29000eae5eaSJonas Devlieghere     }
29100eae5eaSJonas Devlieghere   }
2923e7e915dSSean Callanan 
29300eae5eaSJonas Devlieghere   if (auto *arg = args.getLastArg(OPT_repl_language)) {
294cef2af0fSJonas Devlieghere     auto arg_value = arg->getValue();
295b9c1b51eSKate Stone     m_option_data.m_repl_lang =
296cef2af0fSJonas Devlieghere         SBLanguageRuntime::GetLanguageTypeFromString(arg_value);
297b9c1b51eSKate Stone     if (m_option_data.m_repl_lang == eLanguageTypeUnknown) {
298b9c1b51eSKate Stone       error.SetErrorStringWithFormat("Unrecognized language name: \"%s\"",
299cef2af0fSJonas Devlieghere                                      arg_value);
30030fdc8d8SChris Lattner       return error;
30130fdc8d8SChris Lattner     }
30246a28a95SJonas Devlieghere     m_debugger.SetREPLLanguage(m_option_data.m_repl_lang);
30330fdc8d8SChris Lattner   }
30400eae5eaSJonas Devlieghere 
3057e896277SJonas Devlieghere   if (args.hasArg(OPT_repl)) {
30600eae5eaSJonas Devlieghere     m_option_data.m_repl = true;
3077e896277SJonas Devlieghere   }
3087e896277SJonas Devlieghere 
3097e896277SJonas Devlieghere   if (auto *arg = args.getLastArg(OPT_repl_)) {
3107e896277SJonas Devlieghere     m_option_data.m_repl = true;
3117e896277SJonas Devlieghere     if (auto arg_value = arg->getValue())
312cef2af0fSJonas Devlieghere       m_option_data.m_repl_options = arg_value;
3134ab31c98SCaroline Tice   }
31430fdc8d8SChris Lattner 
31500eae5eaSJonas Devlieghere   // We need to process the options below together as their relative order
31600eae5eaSJonas Devlieghere   // matters.
31700eae5eaSJonas Devlieghere   for (auto *arg : args.filtered(OPT_source_on_crash, OPT_one_line_on_crash,
31800eae5eaSJonas Devlieghere                                  OPT_source, OPT_source_before_file,
31900eae5eaSJonas Devlieghere                                  OPT_one_line, OPT_one_line_before_file)) {
320cef2af0fSJonas Devlieghere     auto arg_value = arg->getValue();
32100eae5eaSJonas Devlieghere     if (arg->getOption().matches(OPT_source_on_crash)) {
322cef2af0fSJonas Devlieghere       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
323cef2af0fSJonas Devlieghere                                       true, error);
32400eae5eaSJonas Devlieghere       if (error.Fail())
32500eae5eaSJonas Devlieghere         return error;
32600eae5eaSJonas Devlieghere     }
32700eae5eaSJonas Devlieghere 
32800eae5eaSJonas Devlieghere     if (arg->getOption().matches(OPT_one_line_on_crash)) {
329cef2af0fSJonas Devlieghere       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterCrash,
33000eae5eaSJonas Devlieghere                                       false, error);
33100eae5eaSJonas Devlieghere       if (error.Fail())
33200eae5eaSJonas Devlieghere         return error;
33300eae5eaSJonas Devlieghere     }
33400eae5eaSJonas Devlieghere 
33500eae5eaSJonas Devlieghere     if (arg->getOption().matches(OPT_source)) {
336cef2af0fSJonas Devlieghere       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
337cef2af0fSJonas Devlieghere                                       true, error);
33800eae5eaSJonas Devlieghere       if (error.Fail())
33900eae5eaSJonas Devlieghere         return error;
34000eae5eaSJonas Devlieghere     }
34100eae5eaSJonas Devlieghere 
34200eae5eaSJonas Devlieghere     if (arg->getOption().matches(OPT_source_before_file)) {
343cef2af0fSJonas Devlieghere       m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
344cef2af0fSJonas Devlieghere                                       true, error);
34500eae5eaSJonas Devlieghere       if (error.Fail())
34600eae5eaSJonas Devlieghere         return error;
34700eae5eaSJonas Devlieghere     }
34800eae5eaSJonas Devlieghere 
34900eae5eaSJonas Devlieghere     if (arg->getOption().matches(OPT_one_line)) {
350cef2af0fSJonas Devlieghere       m_option_data.AddInitialCommand(arg_value, eCommandPlacementAfterFile,
351cef2af0fSJonas Devlieghere                                       false, error);
35200eae5eaSJonas Devlieghere       if (error.Fail())
35300eae5eaSJonas Devlieghere         return error;
35400eae5eaSJonas Devlieghere     }
35500eae5eaSJonas Devlieghere 
35600eae5eaSJonas Devlieghere     if (arg->getOption().matches(OPT_one_line_before_file)) {
357cef2af0fSJonas Devlieghere       m_option_data.AddInitialCommand(arg_value, eCommandPlacementBeforeFile,
35800eae5eaSJonas Devlieghere                                       false, error);
35900eae5eaSJonas Devlieghere       if (error.Fail())
36000eae5eaSJonas Devlieghere         return error;
36100eae5eaSJonas Devlieghere     }
36200eae5eaSJonas Devlieghere   }
36300eae5eaSJonas Devlieghere 
36400eae5eaSJonas Devlieghere   if (m_option_data.m_process_name.empty() &&
36500eae5eaSJonas Devlieghere       m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) {
36600eae5eaSJonas Devlieghere 
36782093e8fSJonas Devlieghere     for (auto *arg : args.filtered(OPT_INPUT))
36800eae5eaSJonas Devlieghere       m_option_data.m_args.push_back(arg->getAsString((args)));
36900eae5eaSJonas Devlieghere 
37000eae5eaSJonas Devlieghere     // Any argument following -- is an argument for the inferior.
37100eae5eaSJonas Devlieghere     if (auto *arg = args.getLastArgNoClaim(OPT_REM)) {
37200eae5eaSJonas Devlieghere       for (auto value : arg->getValues())
373e6366a85SJonas Devlieghere         m_option_data.m_args.emplace_back(value);
37400eae5eaSJonas Devlieghere     }
375e6366a85SJonas Devlieghere   } else if (args.getLastArgNoClaim() != nullptr) {
376b02baf0aSJonas Devlieghere     WithColor::warning() << "program arguments are ignored when attaching.\n";
37700eae5eaSJonas Devlieghere   }
37800eae5eaSJonas Devlieghere 
37900eae5eaSJonas Devlieghere   if (m_option_data.m_print_version) {
380e6366a85SJonas Devlieghere     llvm::outs() << lldb::SBDebugger::GetVersionString() << '\n';
381429222c1SDeepak Panickal     exiting = true;
38200eae5eaSJonas Devlieghere     return error;
38300eae5eaSJonas Devlieghere   }
38400eae5eaSJonas Devlieghere 
38500eae5eaSJonas Devlieghere   if (m_option_data.m_print_python_path) {
386e2231ac7SJim Ingham     SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
387b9c1b51eSKate Stone     if (python_file_spec.IsValid()) {
388e2231ac7SJim Ingham       char python_path[PATH_MAX];
389e2231ac7SJim Ingham       size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
390b9c1b51eSKate Stone       if (num_chars < PATH_MAX) {
391b02baf0aSJonas Devlieghere         llvm::outs() << python_path << '\n';
392b9c1b51eSKate Stone       } else
393b02baf0aSJonas Devlieghere         llvm::outs() << "<PATH TOO LONG>\n";
394b9c1b51eSKate Stone     } else
395b02baf0aSJonas Devlieghere       llvm::outs() << "<COULD NOT FIND PATH>\n";
396429222c1SDeepak Panickal     exiting = true;
39700eae5eaSJonas Devlieghere     return error;
398e64f0dc7SJim Ingham   }
39930fdc8d8SChris Lattner 
400bbef51ebSLawrence D'Anna   if (m_option_data.m_print_script_interpreter_info) {
401bbef51ebSLawrence D'Anna     SBStructuredData info =
402bbef51ebSLawrence D'Anna         m_debugger.GetScriptInterpreterInfo(m_debugger.GetScriptLanguage());
403bbef51ebSLawrence D'Anna     if (!info) {
404bbef51ebSLawrence D'Anna       error.SetErrorString("no script interpreter.");
405bbef51ebSLawrence D'Anna     } else {
406bbef51ebSLawrence D'Anna       SBStream stream;
407bbef51ebSLawrence D'Anna       error = info.GetAsJSON(stream);
408bbef51ebSLawrence D'Anna       if (error.Success()) {
409bbef51ebSLawrence D'Anna         llvm::outs() << stream.GetData() << '\n';
410bbef51ebSLawrence D'Anna       }
411bbef51ebSLawrence D'Anna     }
412bbef51ebSLawrence D'Anna     exiting = true;
413bbef51ebSLawrence D'Anna     return error;
414bbef51ebSLawrence D'Anna   }
415bbef51ebSLawrence D'Anna 
4166611103cSGreg Clayton   return error;
41730fdc8d8SChris Lattner }
41830fdc8d8SChris Lattner 
EscapeString(std::string arg)419b9c1b51eSKate Stone std::string EscapeString(std::string arg) {
420aa1ae6f6SPavel Labath   std::string::size_type pos = 0;
421b9c1b51eSKate Stone   while ((pos = arg.find_first_of("\"\\", pos)) != std::string::npos) {
422aa1ae6f6SPavel Labath     arg.insert(pos, 1, '\\');
423aa1ae6f6SPavel Labath     pos += 2;
424aa1ae6f6SPavel Labath   }
425aa1ae6f6SPavel Labath   return '"' + arg + '"';
426aa1ae6f6SPavel Labath }
427aa1ae6f6SPavel Labath 
MainLoop()428c094d23fSRaphael Isemann int Driver::MainLoop() {
429b9c1b51eSKate Stone   if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) {
430f571b890SGreg Clayton     g_old_stdin_termios_is_valid = true;
43130fdc8d8SChris Lattner     atexit(reset_stdin_termios);
432f571b890SGreg Clayton   }
43330fdc8d8SChris Lattner 
434f6034c4fSAdrian McCarthy #ifndef _MSC_VER
435f6034c4fSAdrian McCarthy   // Disabling stdin buffering with MSVC's 2015 CRT exposes a bug in fgets
436f6034c4fSAdrian McCarthy   // which causes it to miss newlines depending on whether there have been an
437f6034c4fSAdrian McCarthy   // odd or even number of characters.  Bug has been reported to MS via Connect.
438e6366a85SJonas Devlieghere   ::setbuf(stdin, nullptr);
439f6034c4fSAdrian McCarthy #endif
440e6366a85SJonas Devlieghere   ::setbuf(stdout, nullptr);
44130fdc8d8SChris Lattner 
4426611103cSGreg Clayton   m_debugger.SetErrorFileHandle(stderr, false);
4436611103cSGreg Clayton   m_debugger.SetOutputFileHandle(stdout, false);
444de3d12f9SJonas Devlieghere   // Don't take ownership of STDIN yet...
445de3d12f9SJonas Devlieghere   m_debugger.SetInputFileHandle(stdin, false);
44630fdc8d8SChris Lattner 
447e40e4218SJim Ingham   m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
448e40e4218SJim Ingham 
44930fdc8d8SChris Lattner   struct winsize window_size;
450e6366a85SJonas Devlieghere   if ((isatty(STDIN_FILENO) != 0) &&
451b9c1b51eSKate Stone       ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
4523df9a8dfSCaroline Tice     if (window_size.ws_col > 0)
453a7015092SGreg Clayton       m_debugger.SetTerminalWidth(window_size.ws_col);
454f7c0fd8dSGreg Clayton   }
45530fdc8d8SChris Lattner 
45644d93782SGreg Clayton   SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
45730fdc8d8SChris Lattner 
4586c99a346SPavel Labath   // Process lldbinit files before handling any options from the command line.
45930fdc8d8SChris Lattner   SBCommandReturnObject result;
4606c99a346SPavel Labath   sb_interpreter.SourceInitFileInGlobalDirectory(result);
4616c99a346SPavel Labath   if (m_option_data.m_debug_mode) {
4626c99a346SPavel Labath     result.PutError(m_debugger.GetErrorFile());
4636c99a346SPavel Labath     result.PutOutput(m_debugger.GetOutputFile());
4646c99a346SPavel Labath   }
4656c99a346SPavel Labath 
466868b45b5SMed Ismail Bennani   sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl);
467de3d12f9SJonas Devlieghere   if (m_option_data.m_debug_mode) {
4689eb13719SLawrence D'Anna     result.PutError(m_debugger.GetErrorFile());
4699eb13719SLawrence D'Anna     result.PutOutput(m_debugger.GetOutputFile());
47030fdc8d8SChris Lattner   }
47130fdc8d8SChris Lattner 
4722edcad7bSJonas Devlieghere   // Source the local .lldbinit file if it exists and we're allowed to source.
4732edcad7bSJonas Devlieghere   // Here we want to always print the return object because it contains the
4742edcad7bSJonas Devlieghere   // warning and instructions to load local lldbinit files.
4752edcad7bSJonas Devlieghere   sb_interpreter.SourceInitFileInCurrentWorkingDirectory(result);
4769eb13719SLawrence D'Anna   result.PutError(m_debugger.GetErrorFile());
4779eb13719SLawrence D'Anna   result.PutOutput(m_debugger.GetOutputFile());
4782edcad7bSJonas Devlieghere 
479c094d23fSRaphael Isemann   // We allow the user to specify an exit code when calling quit which we will
480c094d23fSRaphael Isemann   // return when exiting.
481c094d23fSRaphael Isemann   m_debugger.GetCommandInterpreter().AllowExitCodeOnQuit(true);
482c094d23fSRaphael Isemann 
48330fdc8d8SChris Lattner   // Now we handle options we got from the command line
484f8314536SEd Maste   SBStream commands_stream;
48506357c93SGreg Clayton 
486b9c1b51eSKate Stone   // First source in the commands specified to be run before the file arguments
487b9c1b51eSKate Stone   // are processed.
4884add3b13SJim Ingham   WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
48930fdc8d8SChris Lattner 
490040f94ccSAdrian Prantl   // If we're not in --repl mode, add the commands to process the file
491040f94ccSAdrian Prantl   // arguments, and the commands specified to run afterwards.
492040f94ccSAdrian Prantl   if (!m_option_data.m_repl) {
4938d846daaSGreg Clayton     const size_t num_args = m_option_data.m_args.size();
494b9c1b51eSKate Stone     if (num_args > 0) {
4955b1fe95dSJim Ingham       char arch_name[64];
496de3d12f9SJonas Devlieghere       if (lldb::SBDebugger::GetDefaultArchitecture(arch_name,
497de3d12f9SJonas Devlieghere                                                    sizeof(arch_name)))
498b9c1b51eSKate Stone         commands_stream.Printf("target create --arch=%s %s", arch_name,
499b9c1b51eSKate Stone                                EscapeString(m_option_data.m_args[0]).c_str());
5005b1fe95dSJim Ingham       else
501b9c1b51eSKate Stone         commands_stream.Printf("target create %s",
502b9c1b51eSKate Stone                                EscapeString(m_option_data.m_args[0]).c_str());
5035b1fe95dSJim Ingham 
504b9c1b51eSKate Stone       if (!m_option_data.m_core_file.empty()) {
505b9c1b51eSKate Stone         commands_stream.Printf(" --core %s",
506b9c1b51eSKate Stone                                EscapeString(m_option_data.m_core_file).c_str());
50706357c93SGreg Clayton       }
50806357c93SGreg Clayton       commands_stream.Printf("\n");
5098d846daaSGreg Clayton 
510b9c1b51eSKate Stone       if (num_args > 1) {
51106357c93SGreg Clayton         commands_stream.Printf("settings set -- target.run-args ");
5128d846daaSGreg Clayton         for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
513b9c1b51eSKate Stone           commands_stream.Printf(
514b9c1b51eSKate Stone               " %s", EscapeString(m_option_data.m_args[arg_idx]).c_str());
51506357c93SGreg Clayton         commands_stream.Printf("\n");
5168d846daaSGreg Clayton       }
517b9c1b51eSKate Stone     } else if (!m_option_data.m_core_file.empty()) {
518b9c1b51eSKate Stone       commands_stream.Printf("target create --core %s\n",
519b9c1b51eSKate Stone                              EscapeString(m_option_data.m_core_file).c_str());
520b9c1b51eSKate Stone     } else if (!m_option_data.m_process_name.empty()) {
521de3d12f9SJonas Devlieghere       commands_stream.Printf(
522de3d12f9SJonas Devlieghere           "process attach --name %s",
523b9c1b51eSKate Stone           EscapeString(m_option_data.m_process_name).c_str());
52406357c93SGreg Clayton 
52506357c93SGreg Clayton       if (m_option_data.m_wait_for)
52606357c93SGreg Clayton         commands_stream.Printf(" --waitfor");
52706357c93SGreg Clayton 
52806357c93SGreg Clayton       commands_stream.Printf("\n");
52906357c93SGreg Clayton 
530b9c1b51eSKate Stone     } else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) {
531b9c1b51eSKate Stone       commands_stream.Printf("process attach --pid %" PRIu64 "\n",
532b9c1b51eSKate Stone                              m_option_data.m_process_pid);
5339c0b64c9SGreg Clayton     }
53430fdc8d8SChris Lattner 
5354add3b13SJim Ingham     WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
536040f94ccSAdrian Prantl   } else if (!m_option_data.m_after_file_commands.empty()) {
537040f94ccSAdrian Prantl     // We're in repl mode and after-file-load commands were specified.
538040f94ccSAdrian Prantl     WithColor::warning() << "commands specified to run after file load (via -o "
539040f94ccSAdrian Prantl                             "or -s) are ignored in REPL mode.\n";
540040f94ccSAdrian Prantl   }
54144d93782SGreg Clayton 
542de3d12f9SJonas Devlieghere   if (m_option_data.m_debug_mode) {
5439eb13719SLawrence D'Anna     result.PutError(m_debugger.GetErrorFile());
5449eb13719SLawrence D'Anna     result.PutOutput(m_debugger.GetOutputFile());
54530fdc8d8SChris Lattner   }
54630fdc8d8SChris Lattner 
547de3d12f9SJonas Devlieghere   const bool handle_events = true;
548de3d12f9SJonas Devlieghere   const bool spawn_thread = false;
54906357c93SGreg Clayton 
550b9c1b51eSKate Stone   // Check if we have any data in the commands stream, and if so, save it to a
551b9c1b51eSKate Stone   // temp file
55206357c93SGreg Clayton   // so we can then run the command interpreter using the file contents.
5534c67b119SJonas Devlieghere   bool go_interactive = true;
554f23b829aSLevon Ter-Grigoryan   if ((commands_stream.GetData() != nullptr) &&
555f23b829aSLevon Ter-Grigoryan       (commands_stream.GetSize() != 0u)) {
556f23b829aSLevon Ter-Grigoryan     SBError error = m_debugger.SetInputString(commands_stream.GetData());
557f23b829aSLevon Ter-Grigoryan     if (error.Fail()) {
558f23b829aSLevon Ter-Grigoryan       WithColor::error() << error.GetCString() << '\n';
5590ca90eb3SJonas Devlieghere       return 1;
5600d671dbcSJonas Devlieghere     }
5610d671dbcSJonas Devlieghere 
5624c67b119SJonas Devlieghere     // Set the debugger into Sync mode when running the command file. Otherwise
5634c67b119SJonas Devlieghere     // command files that run the target won't run in a sensible way.
56426c7bf93SJim Ingham     bool old_async = m_debugger.GetAsync();
56526c7bf93SJim Ingham     m_debugger.SetAsync(false);
56626c7bf93SJim Ingham 
56726c7bf93SJim Ingham     SBCommandInterpreterRunOptions options;
5684c67b119SJonas Devlieghere     options.SetAutoHandleEvents(true);
5694c67b119SJonas Devlieghere     options.SetSpawnThread(false);
57026c7bf93SJim Ingham     options.SetStopOnError(true);
5714c67b119SJonas Devlieghere     options.SetStopOnCrash(m_option_data.m_batch);
572e2a6c08bSLawrence D'Anna     options.SetEchoCommands(!m_option_data.m_source_quietly);
57326c7bf93SJim Ingham 
5744c67b119SJonas Devlieghere     SBCommandInterpreterRunResult results =
5754c67b119SJonas Devlieghere         m_debugger.RunCommandInterpreter(options);
5764c67b119SJonas Devlieghere     if (results.GetResult() == lldb::eCommandInterpreterResultQuitRequested)
5774c67b119SJonas Devlieghere       go_interactive = false;
5784c67b119SJonas Devlieghere     if (m_option_data.m_batch &&
5794c67b119SJonas Devlieghere         results.GetResult() != lldb::eCommandInterpreterResultInferiorCrash)
5804c67b119SJonas Devlieghere       go_interactive = false;
5814add3b13SJim Ingham 
58261d5b0e6SJonas Devlieghere     // When running in batch mode and stopped because of an error, exit with a
58361d5b0e6SJonas Devlieghere     // non-zero exit status.
58461d5b0e6SJonas Devlieghere     if (m_option_data.m_batch &&
58561d5b0e6SJonas Devlieghere         results.GetResult() == lldb::eCommandInterpreterResultCommandError)
5860ca90eb3SJonas Devlieghere       return 1;
58761d5b0e6SJonas Devlieghere 
5884c67b119SJonas Devlieghere     if (m_option_data.m_batch &&
5894c67b119SJonas Devlieghere         results.GetResult() == lldb::eCommandInterpreterResultInferiorCrash &&
590b9c1b51eSKate Stone         !m_option_data.m_after_crash_commands.empty()) {
5914add3b13SJim Ingham       SBStream crash_commands_stream;
592b9c1b51eSKate Stone       WriteCommandsForSourcing(eCommandPlacementAfterCrash,
593b9c1b51eSKate Stone                                crash_commands_stream);
594f23b829aSLevon Ter-Grigoryan       SBError error =
595f23b829aSLevon Ter-Grigoryan           m_debugger.SetInputString(crash_commands_stream.GetData());
596f23b829aSLevon Ter-Grigoryan       if (error.Success()) {
5974c67b119SJonas Devlieghere         SBCommandInterpreterRunResult local_results =
5984c67b119SJonas Devlieghere             m_debugger.RunCommandInterpreter(options);
5994c67b119SJonas Devlieghere         if (local_results.GetResult() ==
6004c67b119SJonas Devlieghere             lldb::eCommandInterpreterResultQuitRequested)
6014c67b119SJonas Devlieghere           go_interactive = false;
60261d5b0e6SJonas Devlieghere 
60361d5b0e6SJonas Devlieghere         // When running in batch mode and an error occurred while sourcing
60461d5b0e6SJonas Devlieghere         // the crash commands, exit with a non-zero exit status.
60561d5b0e6SJonas Devlieghere         if (m_option_data.m_batch &&
60661d5b0e6SJonas Devlieghere             local_results.GetResult() ==
60761d5b0e6SJonas Devlieghere                 lldb::eCommandInterpreterResultCommandError)
6080ca90eb3SJonas Devlieghere           return 1;
6094add3b13SJim Ingham       }
6104add3b13SJim Ingham     }
61126c7bf93SJim Ingham     m_debugger.SetAsync(old_async);
61249668765SGreg Clayton   }
61306357c93SGreg Clayton 
6144c67b119SJonas Devlieghere   // Now set the input file handle to STDIN and run the command interpreter
6154c67b119SJonas Devlieghere   // again in interactive mode or repl mode and let the debugger take ownership
6164c67b119SJonas Devlieghere   // of stdin.
617b9c1b51eSKate Stone   if (go_interactive) {
61806357c93SGreg Clayton     m_debugger.SetInputFileHandle(stdin, true);
619040f94ccSAdrian Prantl 
620040f94ccSAdrian Prantl     if (m_option_data.m_repl) {
621040f94ccSAdrian Prantl       const char *repl_options = nullptr;
622040f94ccSAdrian Prantl       if (!m_option_data.m_repl_options.empty())
623040f94ccSAdrian Prantl         repl_options = m_option_data.m_repl_options.c_str();
624de3d12f9SJonas Devlieghere       SBError error(
625de3d12f9SJonas Devlieghere           m_debugger.RunREPL(m_option_data.m_repl_lang, repl_options));
626040f94ccSAdrian Prantl       if (error.Fail()) {
627040f94ccSAdrian Prantl         const char *error_cstr = error.GetCString();
628040f94ccSAdrian Prantl         if ((error_cstr != nullptr) && (error_cstr[0] != 0))
629040f94ccSAdrian Prantl           WithColor::error() << error_cstr << '\n';
630040f94ccSAdrian Prantl         else
631040f94ccSAdrian Prantl           WithColor::error() << error.GetError() << '\n';
632040f94ccSAdrian Prantl       }
633040f94ccSAdrian Prantl     } else {
63444d93782SGreg Clayton       m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
63526c7bf93SJim Ingham     }
6363e7e915dSSean Callanan   }
637ed3252fbSJim Ingham 
63830fdc8d8SChris Lattner   reset_stdin_termios();
639f571b890SGreg Clayton   fclose(stdin);
64030fdc8d8SChris Lattner 
6416ac12b5bSJonas Devlieghere   return sb_interpreter.GetQuitStatus();
64230fdc8d8SChris Lattner }
64330fdc8d8SChris Lattner 
ResizeWindow(unsigned short col)644b9c1b51eSKate Stone void Driver::ResizeWindow(unsigned short col) {
645c46fe7c0SJim Ingham   GetDebugger().SetTerminalWidth(col);
646c46fe7c0SJim Ingham }
64730fdc8d8SChris Lattner 
sigwinch_handler(int signo)648b9c1b51eSKate Stone void sigwinch_handler(int signo) {
649dd759857SCaroline Tice   struct winsize window_size;
650e6366a85SJonas Devlieghere   if ((isatty(STDIN_FILENO) != 0) &&
651b9c1b51eSKate Stone       ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) {
652e6366a85SJonas Devlieghere     if ((window_size.ws_col > 0) && g_driver != nullptr) {
653c46fe7c0SJim Ingham       g_driver->ResizeWindow(window_size.ws_col);
654dd759857SCaroline Tice     }
655dd759857SCaroline Tice   }
656dd759857SCaroline Tice }
657dd759857SCaroline Tice 
sigint_handler(int signo)658b9c1b51eSKate Stone void sigint_handler(int signo) {
659320d6795SNathan Lanza #ifdef _WIN32 // Restore handler as it is not persistent on Windows
660320d6795SNathan Lanza   signal(SIGINT, sigint_handler);
661320d6795SNathan Lanza #endif
6626c84ffbfSAdrian McCarthy   static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
663e6366a85SJonas Devlieghere   if (g_driver != nullptr) {
6646c84ffbfSAdrian McCarthy     if (!g_interrupt_sent.test_and_set()) {
665efed6131SCaroline Tice       g_driver->GetDebugger().DispatchInputInterrupt();
6666c84ffbfSAdrian McCarthy       g_interrupt_sent.clear();
667efed6131SCaroline Tice       return;
668efed6131SCaroline Tice     }
669efed6131SCaroline Tice   }
670efed6131SCaroline Tice 
6716c84ffbfSAdrian McCarthy   _exit(signo);
672efed6131SCaroline Tice }
673efed6131SCaroline Tice 
6744bcadd66SPavel Labath #ifndef _WIN32
sigtstp_handler(int signo)6754bcadd66SPavel Labath static void sigtstp_handler(int signo) {
676e6366a85SJonas Devlieghere   if (g_driver != nullptr)
677c5917d9aSJim Ingham     g_driver->GetDebugger().SaveInputTerminalState();
678bb5c39d7SPavel Labath 
6794bcadd66SPavel Labath   // Unblock the signal and remove our handler.
6804bcadd66SPavel Labath   sigset_t set;
6814bcadd66SPavel Labath   sigemptyset(&set);
6824bcadd66SPavel Labath   sigaddset(&set, signo);
6834bcadd66SPavel Labath   pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
684c5917d9aSJim Ingham   signal(signo, SIG_DFL);
685c5917d9aSJim Ingham 
6864bcadd66SPavel Labath   // Now re-raise the signal. We will immediately suspend...
6874bcadd66SPavel Labath   raise(signo);
6884bcadd66SPavel Labath   // ... and resume after a SIGCONT.
6894bcadd66SPavel Labath 
6904bcadd66SPavel Labath   // Now undo the modifications.
6914bcadd66SPavel Labath   pthread_sigmask(SIG_BLOCK, &set, nullptr);
6924bcadd66SPavel Labath   signal(signo, sigtstp_handler);
6934bcadd66SPavel Labath 
694e6366a85SJonas Devlieghere   if (g_driver != nullptr)
695c5917d9aSJim Ingham     g_driver->GetDebugger().RestoreInputTerminalState();
696c5917d9aSJim Ingham }
6974bcadd66SPavel Labath #endif
698c5917d9aSJim Ingham 
printHelp(LLDBOptTable & table,llvm::StringRef tool_name)69900eae5eaSJonas Devlieghere static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {
700b0337458SJonas Devlieghere   std::string usage_str = tool_name.str() + " [options]";
701f1e2d585SFangrui Song   table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB", false);
70200eae5eaSJonas Devlieghere 
70300eae5eaSJonas Devlieghere   std::string examples = R"___(
70400eae5eaSJonas Devlieghere EXAMPLES:
70500eae5eaSJonas Devlieghere   The debugger can be started in several modes.
70600eae5eaSJonas Devlieghere 
70700eae5eaSJonas Devlieghere   Passing an executable as a positional argument prepares lldb to debug the
70882093e8fSJonas Devlieghere   given executable. To disambiguate between arguments passed to lldb and
70982093e8fSJonas Devlieghere   arguments passed to the debugged executable, arguments starting with a - must
71082093e8fSJonas Devlieghere   be passed after --.
71100eae5eaSJonas Devlieghere 
7123a62d4fdSBrad Smith     lldb --arch x86_64 /path/to/program program argument -- --arch armv7
71382093e8fSJonas Devlieghere 
71482093e8fSJonas Devlieghere   For convenience, passing the executable after -- is also supported.
71582093e8fSJonas Devlieghere 
7163a62d4fdSBrad Smith     lldb --arch x86_64 -- /path/to/program program argument --arch armv7
71700eae5eaSJonas Devlieghere 
71800eae5eaSJonas Devlieghere   Passing one of the attach options causes lldb to immediately attach to the
71900eae5eaSJonas Devlieghere   given process.
72000eae5eaSJonas Devlieghere 
72100eae5eaSJonas Devlieghere     lldb -p <pid>
72200eae5eaSJonas Devlieghere     lldb -n <process-name>
72300eae5eaSJonas Devlieghere 
72400eae5eaSJonas Devlieghere   Passing --repl starts lldb in REPL mode.
72500eae5eaSJonas Devlieghere 
72600eae5eaSJonas Devlieghere     lldb -r
72700eae5eaSJonas Devlieghere 
72800eae5eaSJonas Devlieghere   Passing --core causes lldb to debug the core file.
72900eae5eaSJonas Devlieghere 
73000eae5eaSJonas Devlieghere     lldb -c /path/to/core
73100eae5eaSJonas Devlieghere 
732040f94ccSAdrian Prantl   Command options can be combined with these modes and cause lldb to run the
73300eae5eaSJonas Devlieghere   specified commands before or after events, like loading the file or crashing,
73400eae5eaSJonas Devlieghere   in the order provided on the command line.
73500eae5eaSJonas Devlieghere 
73600eae5eaSJonas Devlieghere     lldb -O 'settings set stop-disassembly-count 20' -o 'run' -o 'bt'
73700eae5eaSJonas Devlieghere     lldb -S /source/before/file -s /source/after/file
73800eae5eaSJonas Devlieghere     lldb -K /source/before/crash -k /source/after/crash
739040f94ccSAdrian Prantl 
740040f94ccSAdrian Prantl   Note: In REPL mode no file is loaded, so commands specified to run after
7416c2e4e88SJonas Devlieghere   loading the file (via -o or -s) will be ignored.)___";
7426c2e4e88SJonas Devlieghere   llvm::outs() << examples << '\n';
74300eae5eaSJonas Devlieghere }
74400eae5eaSJonas Devlieghere 
InitializeReproducer(llvm::StringRef argv0,opt::InputArgList & input_args)745cdae6d77SFangrui Song static llvm::Optional<int> InitializeReproducer(llvm::StringRef argv0,
74610aa9e19SJonas Devlieghere                                                 opt::InputArgList &input_args) {
74713ecae2fSJonas Devlieghere   bool capture = input_args.hasArg(OPT_capture);
74884557c18SJonas Devlieghere   bool generate_on_exit = input_args.hasArg(OPT_generate_on_exit);
74913ecae2fSJonas Devlieghere   auto *capture_path = input_args.getLastArg(OPT_capture_path);
75013ecae2fSJonas Devlieghere 
75184557c18SJonas Devlieghere   if (generate_on_exit && !capture) {
752066e817bSJonas Devlieghere     WithColor::warning()
75384557c18SJonas Devlieghere         << "-reproducer-generate-on-exit specified without -capture\n";
754066e817bSJonas Devlieghere   }
755066e817bSJonas Devlieghere 
75613ecae2fSJonas Devlieghere   if (capture || capture_path) {
75713ecae2fSJonas Devlieghere     if (capture_path) {
75813ecae2fSJonas Devlieghere       if (!capture)
75913ecae2fSJonas Devlieghere         WithColor::warning() << "-capture-path specified without -capture\n";
76013ecae2fSJonas Devlieghere       if (const char *error = SBReproducer::Capture(capture_path->getValue())) {
76113ecae2fSJonas Devlieghere         WithColor::error() << "reproducer capture failed: " << error << '\n';
76213ecae2fSJonas Devlieghere         return 1;
76313ecae2fSJonas Devlieghere       }
76413ecae2fSJonas Devlieghere     } else {
76513ecae2fSJonas Devlieghere       const char *error = SBReproducer::Capture();
76613ecae2fSJonas Devlieghere       if (error) {
76713ecae2fSJonas Devlieghere         WithColor::error() << "reproducer capture failed: " << error << '\n';
76813ecae2fSJonas Devlieghere         return 1;
76913ecae2fSJonas Devlieghere       }
77013ecae2fSJonas Devlieghere     }
77184557c18SJonas Devlieghere     if (generate_on_exit)
772066e817bSJonas Devlieghere       SBReproducer::SetAutoGenerate(true);
77313ecae2fSJonas Devlieghere   }
77413ecae2fSJonas Devlieghere 
77513ecae2fSJonas Devlieghere   return llvm::None;
77613ecae2fSJonas Devlieghere }
77713ecae2fSJonas Devlieghere 
main(int argc,char const * argv[])778b117ec8bSJonas Devlieghere int main(int argc, char const *argv[]) {
77972748488SJan Kratochvil   // Editline uses for example iswprint which is dependent on LC_CTYPE.
78072748488SJan Kratochvil   std::setlocale(LC_ALL, "");
78172748488SJan Kratochvil   std::setlocale(LC_CTYPE, "");
78272748488SJan Kratochvil 
783fa6984a3SJonas Devlieghere   // Setup LLVM signal handlers and make sure we call llvm_shutdown() on
784fa6984a3SJonas Devlieghere   // destruction.
7854624e83cSVedant Kumar   llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false);
786190fadcdSZachary Turner 
78700eae5eaSJonas Devlieghere   // Parse arguments.
78800eae5eaSJonas Devlieghere   LLDBOptTable T;
78977d5a63cSLuboš Luňák   unsigned MissingArgIndex;
79077d5a63cSLuboš Luňák   unsigned MissingArgCount;
79100eae5eaSJonas Devlieghere   ArrayRef<const char *> arg_arr = makeArrayRef(argv + 1, argc - 1);
79277d5a63cSLuboš Luňák   opt::InputArgList input_args =
79377d5a63cSLuboš Luňák       T.ParseArgs(arg_arr, MissingArgIndex, MissingArgCount);
794ce19664dSJonas Devlieghere   llvm::StringRef argv0 = llvm::sys::path::filename(argv[0]);
79530fdc8d8SChris Lattner 
79600eae5eaSJonas Devlieghere   if (input_args.hasArg(OPT_help)) {
797ce19664dSJonas Devlieghere     printHelp(T, argv0);
79800eae5eaSJonas Devlieghere     return 0;
79900eae5eaSJonas Devlieghere   }
80000eae5eaSJonas Devlieghere 
80177d5a63cSLuboš Luňák   // Check for missing argument error.
80277d5a63cSLuboš Luňák   if (MissingArgCount) {
80377d5a63cSLuboš Luňák     WithColor::error() << "argument to '"
80477d5a63cSLuboš Luňák                        << input_args.getArgString(MissingArgIndex)
80577d5a63cSLuboš Luňák                        << "' is missing\n";
80677d5a63cSLuboš Luňák   }
8075b5b81bcSJonas Devlieghere   // Error out on unknown options.
8085b5b81bcSJonas Devlieghere   if (input_args.hasArg(OPT_UNKNOWN)) {
809b02baf0aSJonas Devlieghere     for (auto *arg : input_args.filtered(OPT_UNKNOWN)) {
8105b5b81bcSJonas Devlieghere       WithColor::error() << "unknown option: " << arg->getSpelling() << '\n';
8115b5b81bcSJonas Devlieghere     }
81277d5a63cSLuboš Luňák   }
81377d5a63cSLuboš Luňák   if (MissingArgCount || input_args.hasArg(OPT_UNKNOWN)) {
814ce19664dSJonas Devlieghere     llvm::errs() << "Use '" << argv0
815ce19664dSJonas Devlieghere                  << " --help' for a complete list of options.\n";
8165b5b81bcSJonas Devlieghere     return 1;
817b02baf0aSJonas Devlieghere   }
818b02baf0aSJonas Devlieghere 
81910aa9e19SJonas Devlieghere   if (auto exit_code = InitializeReproducer(argv[0], input_args)) {
82013ecae2fSJonas Devlieghere     return *exit_code;
82115eacd74SJonas Devlieghere   }
82215eacd74SJonas Devlieghere 
823936c6242SJonas Devlieghere   SBError error = SBDebugger::InitializeWithErrorHandling();
82415eacd74SJonas Devlieghere   if (error.Fail()) {
82515eacd74SJonas Devlieghere     WithColor::error() << "initialization failed: " << error.GetCString()
82615eacd74SJonas Devlieghere                        << '\n';
82715eacd74SJonas Devlieghere     return 1;
82815eacd74SJonas Devlieghere   }
8292ccf8cfcSGreg Clayton   SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
83030fdc8d8SChris Lattner 
83129365da0SZachary Turner   signal(SIGINT, sigint_handler);
832*bc13101cSMartin Storsjö #if !defined(_WIN32)
8333fcbed6bSGreg Clayton   signal(SIGPIPE, SIG_IGN);
834dd759857SCaroline Tice   signal(SIGWINCH, sigwinch_handler);
835c5917d9aSJim Ingham   signal(SIGTSTP, sigtstp_handler);
83629365da0SZachary Turner #endif
837dd759857SCaroline Tice 
838c094d23fSRaphael Isemann   int exit_code = 0;
8396611103cSGreg Clayton   // Create a scope for driver so that the driver object will destroy itself
8406611103cSGreg Clayton   // before SBDebugger::Terminate() is called.
8416611103cSGreg Clayton   {
84230fdc8d8SChris Lattner     Driver driver;
84330fdc8d8SChris Lattner 
844429222c1SDeepak Panickal     bool exiting = false;
845b02baf0aSJonas Devlieghere     SBError error(driver.ProcessArgs(input_args, exiting));
846b9c1b51eSKate Stone     if (error.Fail()) {
847c094d23fSRaphael Isemann       exit_code = 1;
848b02baf0aSJonas Devlieghere       if (const char *error_cstr = error.GetCString())
849b02baf0aSJonas Devlieghere         WithColor::error() << error_cstr << '\n';
850b9c1b51eSKate Stone     } else if (!exiting) {
851c094d23fSRaphael Isemann       exit_code = driver.MainLoop();
85230fdc8d8SChris Lattner     }
8536611103cSGreg Clayton   }
85430fdc8d8SChris Lattner 
85530fdc8d8SChris Lattner   SBDebugger::Terminate();
856c094d23fSRaphael Isemann   return exit_code;
85730fdc8d8SChris Lattner }
858