summaryrefslogtreecommitdiff
path: root/tools/driver/Driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/driver/Driver.cpp')
-rw-r--r--tools/driver/Driver.cpp309
1 files changed, 231 insertions, 78 deletions
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp
index 854310031c37..f02b081b8f0f 100644
--- a/tools/driver/Driver.cpp
+++ b/tools/driver/Driver.cpp
@@ -19,6 +19,8 @@
#if defined(_WIN32)
#include <io.h>
#include <fcntl.h>
+#elif defined(__ANDROID_NDK__)
+#include <errno.h>
#else
#include <unistd.h>
#endif
@@ -39,6 +41,10 @@
#include "lldb/API/SBThread.h"
#include "lldb/API/SBProcess.h"
+#if !defined(__APPLE__)
+#include "llvm/Support/DataTypes.h"
+#endif
+
using namespace lldb;
static void reset_stdin_termios ();
@@ -104,8 +110,15 @@ static OptionDefinition g_options[] =
"Tells the debugger to read in and execute the lldb commands in the given file, before any file provided on the command line has been loaded." },
{ LLDB_3_TO_5, false, "one-line-before-file" , 'O', required_argument, 0, eArgTypeNone,
"Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." },
+ { LLDB_3_TO_5, false, "one-line-on-crash" , 'k', required_argument, 0, eArgTypeNone,
+ "When in batch mode, tells the debugger to execute this one-line lldb command if the target crashes." },
+ { LLDB_3_TO_5, false, "source-on-crash" , 'K', required_argument, 0, eArgTypeFilename,
+ "When in batch mode, tells the debugger to source this file of lldb commands if the target crashes." },
{ LLDB_3_TO_5, false, "source-quietly" , 'Q', no_argument , 0, eArgTypeNone,
- "Tells the debugger suppress output from commands provided in the -s, -S, -O and -o commands." },
+ "Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." },
+ { LLDB_3_TO_5, false, "batch" , 'b', no_argument , 0, eArgTypeNone,
+ "Tells the debugger to running the commands from -s, -S, -o & -O, and then quit. However if any run command stopped due to a signal or crash, "
+ "the debugger will return to the interactive prompt at the place of the crash." },
{ LLDB_3_TO_5, false, "editor" , 'e', no_argument , 0, eArgTypeNone,
"Tells the debugger to open source files using the host's \"external editor\" mechanism." },
{ LLDB_3_TO_5, false, "no-lldbinit" , 'x', no_argument , 0, eArgTypeNone,
@@ -393,6 +406,7 @@ Driver::OptionData::OptionData () :
m_crash_log (),
m_initial_commands (),
m_after_file_commands (),
+ m_after_crash_commands(),
m_debug_mode (false),
m_source_quietly(false),
m_print_version (false),
@@ -402,6 +416,7 @@ Driver::OptionData::OptionData () :
m_process_name(),
m_process_pid(LLDB_INVALID_PROCESS_ID),
m_use_external_editor(false),
+ m_batch(false),
m_seen_options()
{
}
@@ -417,6 +432,16 @@ Driver::OptionData::Clear ()
m_script_lang = lldb::eScriptLanguageDefault;
m_initial_commands.clear ();
m_after_file_commands.clear ();
+ // If there is a local .lldbinit, source that:
+ SBFileSpec local_lldbinit("./.lldbinit", true);
+ if (local_lldbinit.Exists())
+ {
+ char path[2048];
+ local_lldbinit.GetPath(path, 2047);
+ InitialCmdEntry entry(path, true, true);
+ m_after_file_commands.push_back (entry);
+ }
+
m_debug_mode = false;
m_source_quietly = false;
m_print_help = false;
@@ -425,35 +450,45 @@ Driver::OptionData::Clear ()
m_use_external_editor = false;
m_wait_for = false;
m_process_name.erase();
+ m_batch = false;
+ m_after_crash_commands.clear();
+
m_process_pid = LLDB_INVALID_PROCESS_ID;
}
void
-Driver::OptionData::AddInitialCommand (const char *command, bool before_file, bool is_file, SBError &error)
+Driver::OptionData::AddInitialCommand (const char *command, CommandPlacement placement, bool is_file, bool silent, SBError &error)
{
- std::vector<std::pair<bool, std::string> > *command_set;
- if (before_file)
+ std::vector<InitialCmdEntry> *command_set;
+ switch (placement)
+ {
+ case eCommandPlacementBeforeFile:
command_set = &(m_initial_commands);
- else
+ break;
+ case eCommandPlacementAfterFile:
command_set = &(m_after_file_commands);
+ break;
+ case eCommandPlacementAfterCrash:
+ command_set = &(m_after_crash_commands);
+ break;
+ }
if (is_file)
{
SBFileSpec file(command);
if (file.Exists())
- command_set->push_back (std::pair<bool, std::string> (true, optarg));
+ command_set->push_back (InitialCmdEntry(command, is_file, silent));
else if (file.ResolveExecutableLocation())
{
char final_path[PATH_MAX];
file.GetPath (final_path, sizeof(final_path));
- std::string path_str (final_path);
- command_set->push_back (std::pair<bool, std::string> (true, path_str));
+ command_set->push_back (InitialCmdEntry(final_path, is_file, silent));
}
else
error.SetErrorStringWithFormat("file specified in --source (-s) option doesn't exist: '%s'", optarg);
}
else
- command_set->push_back (std::pair<bool, std::string> (false, optarg));
+ command_set->push_back (InitialCmdEntry(command, is_file, silent));
}
void
@@ -485,16 +520,30 @@ Driver::GetScriptLanguage() const
}
void
-Driver::WriteInitialCommands (bool before_file, SBStream &strm)
+Driver::WriteCommandsForSourcing (CommandPlacement placement, SBStream &strm)
{
- std::vector<std::pair<bool, std::string> > &command_set = before_file ? m_option_data.m_initial_commands :
- m_option_data.m_after_file_commands;
+ std::vector<OptionData::InitialCmdEntry> *command_set;
+ switch (placement)
+ {
+ case eCommandPlacementBeforeFile:
+ command_set = &m_option_data.m_initial_commands;
+ break;
+ case eCommandPlacementAfterFile:
+ command_set = &m_option_data.m_after_file_commands;
+ break;
+ case eCommandPlacementAfterCrash:
+ command_set = &m_option_data.m_after_crash_commands;
+ break;
+ }
- for (const auto &command_pair : command_set)
+ for (const auto &command_entry : *command_set)
{
- const char *command = command_pair.second.c_str();
- if (command_pair.first)
- strm.Printf("command source -s %i '%s'\n", m_option_data.m_source_quietly, command);
+ const char *command = command_entry.contents.c_str();
+ if (command_entry.is_file)
+ {
+ bool source_quietly = m_option_data.m_source_quietly || command_entry.source_quietly;
+ strm.Printf("command source -s %i '%s'\n", source_quietly, command);
+ }
else
strm.Printf("%s\n", command);
}
@@ -637,6 +686,10 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting)
m_option_data.m_print_python_path = true;
break;
+ case 'b':
+ m_option_data.m_batch = true;
+ break;
+
case 'c':
{
SBFileSpec file(optarg);
@@ -697,6 +750,13 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting)
m_option_data.m_source_quietly = true;
break;
+ case 'K':
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, true, true, error);
+ break;
+ case 'k':
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterCrash, false, true, error);
+ break;
+
case 'n':
m_option_data.m_process_name = optarg;
break;
@@ -715,16 +775,16 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting)
}
break;
case 's':
- m_option_data.AddInitialCommand(optarg, false, true, error);
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, true, true, error);
break;
case 'o':
- m_option_data.AddInitialCommand(optarg, false, false, error);
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementAfterFile, false, true, error);
break;
case 'S':
- m_option_data.AddInitialCommand(optarg, true, true, error);
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile, true, true, error);
break;
case 'O':
- m_option_data.AddInitialCommand(optarg, true, false, error);
+ m_option_data.AddInitialCommand(optarg, eCommandPlacementBeforeFile, false, true, error);
break;
default:
m_option_data.m_print_help = true;
@@ -807,6 +867,95 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting)
return error;
}
+static ::FILE *
+PrepareCommandsForSourcing (const char *commands_data, size_t commands_size, int fds[2])
+{
+ enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
+
+ bool success = true;
+ ::FILE *commands_file = NULL;
+ fds[0] = -1;
+ fds[1] = -1;
+ int err = 0;
+#ifdef _WIN32
+ err = _pipe(fds, commands_size, O_BINARY);
+#else
+ err = pipe(fds);
+#endif
+ if (err == 0)
+ {
+ ssize_t nrwr = write(fds[WRITE], commands_data, commands_size);
+ if (nrwr < 0)
+ {
+ fprintf(stderr, "error: write(%i, %p, %zd) failed (errno = %i) "
+ "when trying to open LLDB commands pipe\n",
+ fds[WRITE], commands_data, commands_size, errno);
+ success = false;
+ }
+ else if (static_cast<size_t>(nrwr) == commands_size)
+ {
+ // Close the write end of the pipe so when we give the read end to
+ // the debugger/command interpreter it will exit when it consumes all
+ // of the data
+#ifdef _WIN32
+ _close(fds[WRITE]); fds[WRITE] = -1;
+#else
+ close(fds[WRITE]); fds[WRITE] = -1;
+#endif
+ // Now open the read file descriptor in a FILE * that we can give to
+ // the debugger as an input handle
+ commands_file = fdopen(fds[READ], "r");
+ if (commands_file)
+ {
+ fds[READ] = -1; // The FILE * 'commands_file' now owns the read descriptor
+ // Hand ownership if the FILE * over to the debugger for "commands_file".
+ }
+ else
+ {
+ fprintf(stderr,
+ "error: fdopen(%i, \"r\") failed (errno = %i) when "
+ "trying to open LLDB commands pipe\n",
+ fds[READ], errno);
+ success = false;
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "error: can't create pipe file descriptors for LLDB commands\n");
+ success = false;
+ }
+
+ return commands_file;
+}
+
+void
+CleanupAfterCommandSourcing (int fds[2])
+{
+ enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
+
+ // Close any pipes that we still have ownership of
+ if ( fds[WRITE] != -1)
+ {
+#ifdef _WIN32
+ _close(fds[WRITE]); fds[WRITE] = -1;
+#else
+ close(fds[WRITE]); fds[WRITE] = -1;
+#endif
+
+ }
+
+ if ( fds[READ] != -1)
+ {
+#ifdef _WIN32
+ _close(fds[READ]); fds[READ] = -1;
+#else
+ close(fds[READ]); fds[READ] = -1;
+#endif
+ }
+
+}
+
void
Driver::MainLoop ()
{
@@ -849,7 +998,7 @@ Driver::MainLoop ()
SBStream commands_stream;
// First source in the commands specified to be run before the file arguments are processed.
- WriteInitialCommands(true, commands_stream);
+ WriteCommandsForSourcing(eCommandPlacementBeforeFile, commands_stream);
const size_t num_args = m_option_data.m_args.size();
if (num_args > 0)
@@ -899,11 +1048,8 @@ Driver::MainLoop ()
commands_stream.Printf ("process attach --pid %" PRIu64 "\n", m_option_data.m_process_pid);
}
- WriteInitialCommands(false, commands_stream);
+ WriteCommandsForSourcing(eCommandPlacementAfterFile, commands_stream);
- // Now that all option parsing is done, we try and parse the .lldbinit
- // file in the current working directory
- sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
if (GetDebugMode())
{
result.PutError(m_debugger.GetErrorFileHandle());
@@ -917,72 +1063,69 @@ Driver::MainLoop ()
// so we can then run the command interpreter using the file contents.
const char *commands_data = commands_stream.GetData();
const size_t commands_size = commands_stream.GetSize();
+
+ // The command file might have requested that we quit, this variable will track that.
+ bool quit_requested = false;
+ bool stopped_for_crash = false;
if (commands_data && commands_size)
{
- enum PIPES { READ, WRITE }; // Constants 0 and 1 for READ and WRITE
-
+ int initial_commands_fds[2];
bool success = true;
- int fds[2] = { -1, -1 };
- int err = 0;
-#ifdef _WIN32
- err = _pipe(fds, commands_size, O_BINARY);
-#else
- err = pipe(fds);
-#endif
- if (err == 0)
+ FILE *commands_file = PrepareCommandsForSourcing (commands_data, commands_size, initial_commands_fds);
+ if (commands_file)
{
- if (write (fds[WRITE], commands_data, commands_size) == commands_size)
+ m_debugger.SetInputFileHandle (commands_file, true);
+
+ // Set the debugger into Sync mode when running the command file. Otherwise command files
+ // that run the target won't run in a sensible way.
+ bool old_async = m_debugger.GetAsync();
+ m_debugger.SetAsync(false);
+ int num_errors;
+
+ SBCommandInterpreterRunOptions options;
+ options.SetStopOnError (true);
+ if (m_option_data.m_batch)
+ options.SetStopOnCrash (true);
+
+ m_debugger.RunCommandInterpreter(handle_events,
+ spawn_thread,
+ options,
+ num_errors,
+ quit_requested,
+ stopped_for_crash);
+
+ if (m_option_data.m_batch && stopped_for_crash && !m_option_data.m_after_crash_commands.empty())
{
- // Close the write end of the pipe so when we give the read end to
- // the debugger/command interpreter it will exit when it consumes all
- // of the data
-#ifdef _WIN32
- _close(fds[WRITE]); fds[WRITE] = -1;
-#else
- close(fds[WRITE]); fds[WRITE] = -1;
-#endif
- // Now open the read file descriptor in a FILE * that we can give to
- // the debugger as an input handle
- FILE *commands_file = fdopen(fds[READ], "r");
+ int crash_command_fds[2];
+ SBStream crash_commands_stream;
+ WriteCommandsForSourcing (eCommandPlacementAfterCrash, crash_commands_stream);
+ const char *crash_commands_data = crash_commands_stream.GetData();
+ const size_t crash_commands_size = crash_commands_stream.GetSize();
+ commands_file = PrepareCommandsForSourcing (crash_commands_data, crash_commands_size, crash_command_fds);
if (commands_file)
{
- fds[READ] = -1; // The FILE * 'commands_file' now owns the read descriptor
- // Hand ownership if the FILE * over to the debugger for "commands_file".
+ bool local_quit_requested;
+ bool local_stopped_for_crash;
m_debugger.SetInputFileHandle (commands_file, true);
- m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
- }
- else
- {
- fprintf(stderr, "error: fdopen(%i, \"r\") failed (errno = %i) when trying to open LLDB commands pipe\n", fds[READ], errno);
- success = false;
+
+ m_debugger.RunCommandInterpreter(handle_events,
+ spawn_thread,
+ options,
+ num_errors,
+ local_quit_requested,
+ local_stopped_for_crash);
+ if (local_quit_requested)
+ quit_requested = true;
+
}
}
+ m_debugger.SetAsync(old_async);
}
else
- {
- fprintf(stderr, "error: can't create pipe file descriptors for LLDB commands\n");
success = false;
- }
// Close any pipes that we still have ownership of
- if ( fds[WRITE] != -1)
- {
-#ifdef _WIN32
- _close(fds[WRITE]); fds[WRITE] = -1;
-#else
- close(fds[WRITE]); fds[WRITE] = -1;
-#endif
-
- }
-
- if ( fds[READ] != -1)
- {
-#ifdef _WIN32
- _close(fds[READ]); fds[READ] = -1;
-#else
- close(fds[READ]); fds[READ] = -1;
-#endif
- }
+ CleanupAfterCommandSourcing(initial_commands_fds);
// Something went wrong with command pipe
if (!success)
@@ -995,8 +1138,18 @@ Driver::MainLoop ()
// Now set the input file handle to STDIN and run the command
// interpreter again in interactive mode and let the debugger
// take ownership of stdin
- m_debugger.SetInputFileHandle (stdin, true);
- m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
+
+ bool go_interactive = true;
+ if (quit_requested)
+ go_interactive = false;
+ else if (m_option_data.m_batch && !stopped_for_crash)
+ go_interactive = false;
+
+ if (go_interactive)
+ {
+ m_debugger.SetInputFileHandle (stdin, true);
+ m_debugger.RunCommandInterpreter(handle_events, spawn_thread);
+ }
reset_stdin_termios();
fclose (stdin);