diff options
Diffstat (limited to 'tools/lldb-mi/Driver.cpp')
-rw-r--r-- | tools/lldb-mi/Driver.cpp | 1276 |
1 files changed, 0 insertions, 1276 deletions
diff --git a/tools/lldb-mi/Driver.cpp b/tools/lldb-mi/Driver.cpp deleted file mode 100644 index 2a90763..0000000 --- a/tools/lldb-mi/Driver.cpp +++ /dev/null @@ -1,1276 +0,0 @@ -//===-- Driver.cpp ----------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// In-house headers: -#include "MICmnConfig.h" - -#if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER - -#ifndef _MSC_VER -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> -#include <fcntl.h> -#include <string> -#endif // _MSC_VER - -#include "Platform.h" // CODETAG_IOR_SIGNALS -#include "Driver.h" - -#ifdef _MSC_VER -#include <lldb\Host\windows\getopt\GetOptInc.h> -#endif // _MSC_VER -#include "lldb/API/SBBreakpoint.h" -#include "lldb/API/SBCommandInterpreter.h" -#include "lldb/API/SBCommandReturnObject.h" -#include "lldb/API/SBCommunication.h" -#include "lldb/API/SBEvent.h" -#include "lldb/API/SBHostOS.h" -#include "lldb/API/SBListener.h" -#include "lldb/API/SBStream.h" -#include "lldb/API/SBTarget.h" -#include "lldb/API/SBThread.h" -#include "lldb/API/SBProcess.h" - -using namespace lldb; - -static void reset_stdin_termios(); -static bool g_old_stdin_termios_is_valid = false; -static struct termios g_old_stdin_termios; - -static char *g_debugger_name = (char *)""; -Driver *g_driver = NULL; - -// In the Driver::MainLoop, we change the terminal settings. This function is -// added as an atexit handler to make sure we clean them up. -static void -reset_stdin_termios() -{ - if (g_old_stdin_termios_is_valid) - { - g_old_stdin_termios_is_valid = false; - ::tcsetattr(STDIN_FILENO, TCSANOW, &g_old_stdin_termios); - } -} - -typedef struct -{ - uint32_t usage_mask; // Used to mark options that can be used together. If (1 << n & usage_mask) != 0 - // then this option belongs to option set n. - bool required; // This option is required (in the current usage level) - const char *long_option; // Full name for this option. - int short_option; // Single character for this option. - int option_has_arg; // no_argument, required_argument or optional_argument - uint32_t completion_type; // Cookie the option class can use to do define the argument completion. - lldb::CommandArgumentType argument_type; // Type of argument this option takes - const char *usage_text; // Full text explaining what this options does and what (if any) argument to - // pass it. -} OptionDefinition; - -#define LLDB_3_TO_5 LLDB_OPT_SET_3 | LLDB_OPT_SET_4 | LLDB_OPT_SET_5 -#define LLDB_4_TO_5 LLDB_OPT_SET_4 | LLDB_OPT_SET_5 - -static OptionDefinition g_options[] = { - {LLDB_OPT_SET_1, true, "help", 'h', no_argument, 0, eArgTypeNone, "Prints out the usage information for the LLDB debugger."}, - {LLDB_OPT_SET_2, true, "version", 'v', no_argument, 0, eArgTypeNone, "Prints out the current version number of the LLDB debugger."}, - {LLDB_OPT_SET_3, true, "arch", 'a', required_argument, 0, eArgTypeArchitecture, - "Tells the debugger to use the specified architecture when starting and running the program. <architecture> must " - "be one of the architectures for which the program was compiled."}, - {LLDB_OPT_SET_3, true, "file", 'f', required_argument, 0, eArgTypeFilename, - "Tells the debugger to use the file <filename> as the program to be debugged."}, - {LLDB_OPT_SET_3, false, "core", 'c', required_argument, 0, eArgTypeFilename, - "Tells the debugger to use the fullpath to <path> as the core file."}, - {LLDB_OPT_SET_5, true, "attach-pid", 'p', required_argument, 0, eArgTypePid, - "Tells the debugger to attach to a process with the given pid."}, - {LLDB_OPT_SET_4, true, "attach-name", 'n', required_argument, 0, eArgTypeProcessName, - "Tells the debugger to attach to a process with the given name."}, - {LLDB_OPT_SET_4, true, "wait-for", 'w', no_argument, 0, eArgTypeNone, - "Tells the debugger to wait for a process with the given pid or name to launch before attaching."}, - {LLDB_3_TO_5, false, "source", 's', required_argument, 0, eArgTypeFilename, "Tells the debugger to read in and execute the lldb " - "commands in the given file, after any file provided on " - "the command line has been loaded."}, - {LLDB_3_TO_5, false, "one-line", 'o', required_argument, 0, eArgTypeNone, - "Tells the debugger to execute this one-line lldb command after any file provided on the command line has been loaded."}, - {LLDB_3_TO_5, false, "source-before-file", 'S', required_argument, 0, eArgTypeFilename, - "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, "source-quietly", 'Q', no_argument, 0, eArgTypeNone, - "Tells the debugger suppress output from commands provided in the -s, -S, -O and -o commands."}, - {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, "Do not automatically parse any '.lldbinit' files."}, - {LLDB_3_TO_5, false, "no-use-colors", 'X', no_argument, 0, eArgTypeNone, "Do not use colors."}, - {LLDB_OPT_SET_6, true, "python-path", 'P', no_argument, 0, eArgTypeNone, - "Prints out the path to the lldb.py file for this version of lldb."}, - {LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0, eArgTypeScriptLang, - "Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default. " - "Valid scripting languages that can be specified include Python, Perl, Ruby and Tcl. Currently only the Python " - "extensions have been implemented."}, - {LLDB_3_TO_5, false, "debug", 'd', no_argument, 0, eArgTypeNone, - "Tells the debugger to print out extra information for debugging itself."}, - {0, false, NULL, 0, 0, 0, eArgTypeNone, NULL}}; - -static const uint32_t last_option_set_with_args = 2; - -Driver::Driver() - : SBBroadcaster("Driver") - , m_debugger(SBDebugger::Create(false)) - , m_option_data() -{ - // We want to be able to handle CTRL+D in the terminal to have it terminate - // certain input - m_debugger.SetCloseInputOnEOF(false); - g_debugger_name = (char *)m_debugger.GetInstanceName(); - if (g_debugger_name == NULL) - g_debugger_name = (char *)""; - g_driver = this; -} - -Driver::~Driver() -{ - g_driver = NULL; - g_debugger_name = NULL; -} - -// This function takes INDENT, which tells how many spaces to output at the front -// of each line; TEXT, which is the text that is to be output. It outputs the -// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the -// front of each line. It breaks lines on spaces, tabs or newlines, shortening -// the line if necessary to not break in the middle of a word. It assumes that -// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters. - -void -OutputFormattedUsageText(FILE *out, int indent, const char *text, int output_max_columns) -{ - int len = strlen(text); - std::string text_string(text); - - // Force indentation to be reasonable. - if (indent >= output_max_columns) - indent = 0; - - // Will it all fit on one line? - - if (len + indent < output_max_columns) - // Output as a single line - fprintf(out, "%*s%s\n", indent, "", text); - else - { - // We need to break it up into multiple lines. - int text_width = output_max_columns - indent - 1; - int start = 0; - int end = start; - int final_end = len; - int sub_len; - - while (end < final_end) - { - // Dont start the 'text' on a space, since we're already outputting the indentation. - while ((start < final_end) && (text[start] == ' ')) - start++; - - end = start + text_width; - if (end > final_end) - end = final_end; - else - { - // If we're not at the end of the text, make sure we break the line on white space. - while (end > start && text[end] != ' ' && text[end] != '\t' && text[end] != '\n') - end--; - } - sub_len = end - start; - std::string substring = text_string.substr(start, sub_len); - fprintf(out, "%*s%s\n", indent, "", substring.c_str()); - start = end + 1; - } - } -} - -void -ShowUsage(FILE *out, OptionDefinition *option_table, Driver::OptionData data) -{ - uint32_t screen_width = 80; - uint32_t indent_level = 0; - const char *name = "lldb"; - - fprintf(out, "\nUsage:\n\n"); - - indent_level += 2; - - // First, show each usage level set of options, e.g. <cmd> [options-for-level-0] - // <cmd> [options-for-level-1] - // etc. - - uint32_t num_options; - uint32_t num_option_sets = 0; - - for (num_options = 0; option_table[num_options].long_option != NULL; ++num_options) - { - uint32_t this_usage_mask = option_table[num_options].usage_mask; - if (this_usage_mask == LLDB_OPT_SET_ALL) - { - if (num_option_sets == 0) - num_option_sets = 1; - } - else - { - for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) - { - if (this_usage_mask & 1 << j) - { - if (num_option_sets <= j) - num_option_sets = j + 1; - } - } - } - } - - for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++) - { - uint32_t opt_set_mask; - - opt_set_mask = 1 << opt_set; - - if (opt_set > 0) - fprintf(out, "\n"); - fprintf(out, "%*s%s", indent_level, "", name); - bool is_help_line = false; - - for (uint32_t i = 0; i < num_options; ++i) - { - if (option_table[i].usage_mask & opt_set_mask) - { - CommandArgumentType arg_type = option_table[i].argument_type; - const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString(arg_type); - // This is a bit of a hack, but there's no way to say certain options don't have arguments yet... - // so we do it by hand here. - if (option_table[i].short_option == 'h') - is_help_line = true; - - if (option_table[i].required) - { - if (option_table[i].option_has_arg == required_argument) - fprintf(out, " -%c <%s>", option_table[i].short_option, arg_name); - else if (option_table[i].option_has_arg == optional_argument) - fprintf(out, " -%c [<%s>]", option_table[i].short_option, arg_name); - else - fprintf(out, " -%c", option_table[i].short_option); - } - else - { - if (option_table[i].option_has_arg == required_argument) - fprintf(out, " [-%c <%s>]", option_table[i].short_option, arg_name); - else if (option_table[i].option_has_arg == optional_argument) - fprintf(out, " [-%c [<%s>]]", option_table[i].short_option, arg_name); - else - fprintf(out, " [-%c]", option_table[i].short_option); - } - } - } - if (!is_help_line && (opt_set <= last_option_set_with_args)) - fprintf(out, " [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]"); - } - - fprintf(out, "\n\n"); - - // Now print out all the detailed information about the various options: long form, short form and help text: - // -- long_name <argument> - // - short <argument> - // help text - - // This variable is used to keep track of which options' info we've printed out, because some options can be in - // more than one usage level, but we only want to print the long form of its information once. - - Driver::OptionData::OptionSet options_seen; - Driver::OptionData::OptionSet::iterator pos; - - indent_level += 5; - - for (uint32_t i = 0; i < num_options; ++i) - { - // Only print this option if we haven't already seen it. - pos = options_seen.find(option_table[i].short_option); - if (pos == options_seen.end()) - { - CommandArgumentType arg_type = option_table[i].argument_type; - const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString(arg_type); - - options_seen.insert(option_table[i].short_option); - fprintf(out, "%*s-%c ", indent_level, "", option_table[i].short_option); - if (arg_type != eArgTypeNone) - fprintf(out, "<%s>", arg_name); - fprintf(out, "\n"); - fprintf(out, "%*s--%s ", indent_level, "", option_table[i].long_option); - if (arg_type != eArgTypeNone) - fprintf(out, "<%s>", arg_name); - fprintf(out, "\n"); - indent_level += 5; - OutputFormattedUsageText(out, indent_level, option_table[i].usage_text, screen_width); - indent_level -= 5; - fprintf(out, "\n"); - } - } - - indent_level -= 5; - - fprintf(out, "\n%*sNotes:\n", indent_level, ""); - indent_level += 5; - - fprintf(out, "\n%*sMultiple \"-s\" and \"-o\" options can be provided. They will be processed from left to right in order, " - "\n%*swith the source files and commands interleaved. The same is true of the \"-S\" and \"-O\" options." - "\n%*sThe before file and after file sets can intermixed freely, the command parser will sort them out." - "\n%*sThe order of the file specifiers (\"-c\", \"-f\", etc.) is not significant in this regard.\n\n", - indent_level, "", indent_level, "", indent_level, "", indent_level, ""); - - fprintf(out, "\n%*sIf you don't provide -f then the first argument will be the file to be debugged" - "\n%*swhich means that '%s -- <filename> [<ARG1> [<ARG2>]]' also works." - "\n%*sBut remember to end the options with \"--\" if any of your arguments have a \"-\" in them.\n\n", - indent_level, "", indent_level, "", name, indent_level, ""); -} - -void -BuildGetOptTable(OptionDefinition *expanded_option_table, std::vector<struct option> &getopt_table, uint32_t num_options) -{ - if (num_options == 0) - return; - - uint32_t i; - uint32_t j; - std::bitset<256> option_seen; - - getopt_table.resize(num_options + 1); - - for (i = 0, j = 0; i < num_options; ++i) - { - char short_opt = expanded_option_table[i].short_option; - - if (option_seen.test(short_opt) == false) - { - getopt_table[j].name = expanded_option_table[i].long_option; - getopt_table[j].has_arg = expanded_option_table[i].option_has_arg; - getopt_table[j].flag = NULL; - getopt_table[j].val = expanded_option_table[i].short_option; - option_seen.set(short_opt); - ++j; - } - } - - getopt_table[j].name = NULL; - getopt_table[j].has_arg = 0; - getopt_table[j].flag = NULL; - getopt_table[j].val = 0; -} - -Driver::OptionData::OptionData() - : m_args() - , m_script_lang(lldb::eScriptLanguageDefault) - , m_core_file() - , m_crash_log() - , m_initial_commands() - , m_after_file_commands() - , m_debug_mode(false) - , m_source_quietly(false) - , m_print_version(false) - , m_print_python_path(false) - , m_print_help(false) - , m_wait_for(false) - , m_process_name() - , m_process_pid(LLDB_INVALID_PROCESS_ID) - , m_use_external_editor(false) - , m_seen_options() -{ -} - -Driver::OptionData::~OptionData() -{ -} - -void -Driver::OptionData::Clear() -{ - m_args.clear(); - m_script_lang = lldb::eScriptLanguageDefault; - m_initial_commands.clear(); - m_after_file_commands.clear(); - m_debug_mode = false; - m_source_quietly = false; - m_print_help = false; - m_print_version = false; - m_print_python_path = false; - m_use_external_editor = false; - m_wait_for = false; - m_process_name.erase(); - m_process_pid = LLDB_INVALID_PROCESS_ID; -} - -void -Driver::OptionData::AddInitialCommand(const char *command, bool before_file, bool is_file, SBError &error) -{ - std::vector<std::pair<bool, std::string>> *command_set; - if (before_file) - command_set = &(m_initial_commands); - else - command_set = &(m_after_file_commands); - - if (is_file) - { - SBFileSpec file(command); - if (file.Exists()) - command_set->push_back(std::pair<bool, std::string>(true, optarg)); - 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)); - } - 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)); -} - -void -Driver::ResetOptionValues() -{ - m_option_data.Clear(); -} - -const char * -Driver::GetFilename() const -{ - if (m_option_data.m_args.empty()) - return NULL; - return m_option_data.m_args.front().c_str(); -} - -const char * -Driver::GetCrashLogFilename() const -{ - if (m_option_data.m_crash_log.empty()) - return NULL; - return m_option_data.m_crash_log.c_str(); -} - -lldb::ScriptLanguage -Driver::GetScriptLanguage() const -{ - return m_option_data.m_script_lang; -} - -void -Driver::ExecuteInitialCommands(bool before_file) -{ - size_t num_commands; - std::vector<std::pair<bool, std::string>> *command_set; - if (before_file) - command_set = &(m_option_data.m_initial_commands); - else - command_set = &(m_option_data.m_after_file_commands); - - num_commands = command_set->size(); - SBCommandReturnObject result; - bool old_async = GetDebugger().GetAsync(); - GetDebugger().SetAsync(false); - for (size_t idx = 0; idx < num_commands; idx++) - { - bool is_file = (*command_set)[idx].first; - const char *command = (*command_set)[idx].second.c_str(); - char command_string[PATH_MAX * 2]; - const bool dump_stream_only_if_no_immediate = true; - const char *executed_command = command; - if (is_file) - { - ::snprintf(command_string, sizeof(command_string), "command source -s %i '%s'", m_option_data.m_source_quietly, command); - executed_command = command_string; - } - - m_debugger.GetCommandInterpreter().HandleCommand(executed_command, result, false); - if (!m_option_data.m_source_quietly || result.Succeeded() == false) - { - const size_t output_size = result.GetOutputSize(); - if (output_size > 0) - { - const char *cstr = result.GetOutput(dump_stream_only_if_no_immediate); - if (cstr) - printf("%s", cstr); - } - const size_t error_size = result.GetErrorSize(); - if (error_size > 0) - { - const char *cstr = result.GetError(dump_stream_only_if_no_immediate); - if (cstr) - printf("%s", cstr); - } - } - - if (result.Succeeded() == false) - { - const char *type = before_file ? "before file" : "after_file"; - if (is_file) - ::fprintf(stderr, "Aborting %s command execution, command file: '%s' failed.\n", type, command); - else - ::fprintf(stderr, "Aborting %s command execution, command: '%s' failed.\n", type, command); - break; - } - result.Clear(); - } - GetDebugger().SetAsync(old_async); -} - -bool -Driver::GetDebugMode() const -{ - return m_option_data.m_debug_mode; -} - -// Check the arguments that were passed to this program to make sure they are valid and to get their -// argument values (if any). Return a boolean value indicating whether or not to start up the full -// debugger (i.e. the Command Interpreter) or not. Return FALSE if the arguments were invalid OR -// if the user only wanted help or version information. - -SBError -Driver::ParseArgs(int argc, const char *argv[], FILE *out_fh, bool &exiting) -{ - ResetOptionValues(); - - SBCommandReturnObject result; - - SBError error; - std::string option_string; - struct option *long_options = NULL; - std::vector<struct option> long_options_vector; - uint32_t num_options; - - for (num_options = 0; g_options[num_options].long_option != NULL; ++num_options) - /* Do Nothing. */; - - if (num_options == 0) - { - if (argc > 1) - error.SetErrorStringWithFormat("invalid number of options"); - return error; - } - - BuildGetOptTable(g_options, long_options_vector, num_options); - - if (long_options_vector.empty()) - long_options = NULL; - else - long_options = &long_options_vector.front(); - - if (long_options == NULL) - { - error.SetErrorStringWithFormat("invalid long options"); - return error; - } - - // Build the option_string argument for call to getopt_long_only. - - for (int i = 0; long_options[i].name != NULL; ++i) - { - if (long_options[i].flag == NULL) - { - option_string.push_back((char)long_options[i].val); - switch (long_options[i].has_arg) - { - default: - case no_argument: - break; - case required_argument: - option_string.push_back(':'); - break; - case optional_argument: - option_string.append("::"); - break; - } - } - } - - // This is kind of a pain, but since we make the debugger in the Driver's constructor, we can't - // know at that point whether we should read in init files yet. So we don't read them in in the - // Driver constructor, then set the flags back to "read them in" here, and then if we see the - // "-n" flag, we'll turn it off again. Finally we have to read them in by hand later in the - // main loop. - - m_debugger.SkipLLDBInitFiles(false); - m_debugger.SkipAppInitFiles(false); - -// Prepare for & make calls to getopt_long_only. -#if __GLIBC__ - optind = 0; -#else - optreset = 1; - optind = 1; -#endif - int val; - while (1) - { - int long_options_index = -1; - val = ::getopt_long_only(argc, const_cast<char **>(argv), option_string.c_str(), long_options, &long_options_index); - - if (val == -1) - break; - else if (val == '?') - { - m_option_data.m_print_help = true; - error.SetErrorStringWithFormat("unknown or ambiguous option"); - break; - } - else if (val == 0) - continue; - else - { - m_option_data.m_seen_options.insert((char)val); - if (long_options_index == -1) - { - for (int i = 0; long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val; ++i) - { - if (long_options[i].val == val) - { - long_options_index = i; - break; - } - } - } - - if (long_options_index >= 0) - { - const int short_option = g_options[long_options_index].short_option; - - switch (short_option) - { - case 'h': - m_option_data.m_print_help = true; - break; - - case 'v': - m_option_data.m_print_version = true; - break; - - case 'P': - m_option_data.m_print_python_path = true; - break; - - case 'c': - { - SBFileSpec file(optarg); - if (file.Exists()) - { - m_option_data.m_core_file = optarg; - } - else - error.SetErrorStringWithFormat("file specified in --core (-c) option doesn't exist: '%s'", optarg); - } - break; - - case 'e': - m_option_data.m_use_external_editor = true; - break; - - case 'x': - m_debugger.SkipLLDBInitFiles(true); - m_debugger.SkipAppInitFiles(true); - break; - - case 'X': - m_debugger.SetUseColor(false); - break; - - case 'f': - { - SBFileSpec file(optarg); - if (file.Exists()) - { - m_option_data.m_args.push_back(optarg); - } - else if (file.ResolveExecutableLocation()) - { - char path[PATH_MAX]; - file.GetPath(path, sizeof(path)); - m_option_data.m_args.push_back(path); - } - else - error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", optarg); - } - break; - - case 'a': - if (!m_debugger.SetDefaultArchitecture(optarg)) - error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", optarg); - break; - - case 'l': - m_option_data.m_script_lang = m_debugger.GetScriptingLanguage(optarg); - break; - - case 'd': - m_option_data.m_debug_mode = true; - break; - - case 'Q': - m_option_data.m_source_quietly = true; - break; - - case 'n': - m_option_data.m_process_name = optarg; - break; - - case 'w': - m_option_data.m_wait_for = true; - break; - - case 'p': - { - char *remainder; - m_option_data.m_process_pid = strtol(optarg, &remainder, 0); - if (remainder == optarg || *remainder != '\0') - error.SetErrorStringWithFormat("Could not convert process PID: \"%s\" into a pid.", optarg); - } - break; - case 's': - m_option_data.AddInitialCommand(optarg, false, true, error); - break; - case 'o': - m_option_data.AddInitialCommand(optarg, false, false, error); - break; - case 'S': - m_option_data.AddInitialCommand(optarg, true, true, error); - break; - case 'O': - m_option_data.AddInitialCommand(optarg, true, false, error); - break; - default: - m_option_data.m_print_help = true; - error.SetErrorStringWithFormat("unrecognized option %c", short_option); - break; - } - } - else - { - error.SetErrorStringWithFormat("invalid option with value %i", val); - } - if (error.Fail()) - { - return error; - } - } - } - - if (error.Fail() || m_option_data.m_print_help) - { - ShowUsage(out_fh, g_options, m_option_data); - exiting = true; - } - else if (m_option_data.m_print_version) - { - ::fprintf(out_fh, "%s\n", m_debugger.GetVersionString()); - exiting = true; - } - else if (m_option_data.m_print_python_path) - { - SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath(); - if (python_file_spec.IsValid()) - { - char python_path[PATH_MAX]; - size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX); - if (num_chars < PATH_MAX) - { - ::fprintf(out_fh, "%s\n", python_path); - } - else - ::fprintf(out_fh, "<PATH TOO LONG>\n"); - } - else - ::fprintf(out_fh, "<COULD NOT FIND PATH>\n"); - exiting = true; - } - else if (m_option_data.m_process_name.empty() && m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID) - { - // Any arguments that are left over after option parsing are for - // the program. If a file was specified with -f then the filename - // is already in the m_option_data.m_args array, and any remaining args - // are arguments for the inferior program. If no file was specified with - // -f, then what is left is the program name followed by any arguments. - - // Skip any options we consumed with getopt_long_only - argc -= optind; - argv += optind; - - if (argc > 0) - { - for (int arg_idx = 0; arg_idx < argc; ++arg_idx) - { - const char *arg = argv[arg_idx]; - if (arg) - m_option_data.m_args.push_back(arg); - } - } - } - else - { - // Skip any options we consumed with getopt_long_only - argc -= optind; - // argv += optind; // Commented out to keep static analyzer happy - - if (argc > 0) - ::fprintf(out_fh, "Warning: program arguments are ignored when attaching.\n"); - } - - return error; -} - -void -Driver::MainLoop() -{ - if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) - { - g_old_stdin_termios_is_valid = true; - atexit(reset_stdin_termios); - } - - ::setbuf(stdin, NULL); - ::setbuf(stdout, NULL); - - m_debugger.SetErrorFileHandle(stderr, false); - m_debugger.SetOutputFileHandle(stdout, false); - m_debugger.SetInputFileHandle(stdin, true); - - m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); - - struct winsize window_size; - if (isatty(STDIN_FILENO) && ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) - { - if (window_size.ws_col > 0) - m_debugger.SetTerminalWidth(window_size.ws_col); - } - - SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); - - // Before we handle any options from the command line, we parse the - // .lldbinit file in the user's home directory. - SBCommandReturnObject result; - sb_interpreter.SourceInitFileInHomeDirectory(result); - if (GetDebugMode()) - { - result.PutError(m_debugger.GetErrorFileHandle()); - result.PutOutput(m_debugger.GetOutputFileHandle()); - } - - // Now we handle options we got from the command line - // First source in the commands specified to be run before the file arguments are processed. - ExecuteInitialCommands(true); - - // Was there a core file specified? - std::string core_file_spec(""); - if (!m_option_data.m_core_file.empty()) - core_file_spec.append("--core ").append(m_option_data.m_core_file); - - char command_string[PATH_MAX * 2]; - const size_t num_args = m_option_data.m_args.size(); - if (num_args > 0) - { - char arch_name[64]; - if (m_debugger.GetDefaultArchitecture(arch_name, sizeof(arch_name))) - ::snprintf(command_string, sizeof(command_string), "target create --arch=%s %s \"%s\"", arch_name, core_file_spec.c_str(), - m_option_data.m_args[0].c_str()); - else - ::snprintf(command_string, sizeof(command_string), "target create %s \"%s\"", core_file_spec.c_str(), - m_option_data.m_args[0].c_str()); - - m_debugger.HandleCommand(command_string); - - if (num_args > 1) - { - m_debugger.HandleCommand("settings clear target.run-args"); - char arg_cstr[1024]; - for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) - { - ::snprintf(arg_cstr, sizeof(arg_cstr), "settings append target.run-args \"%s\"", m_option_data.m_args[arg_idx].c_str()); - m_debugger.HandleCommand(arg_cstr); - } - } - } - else if (!core_file_spec.empty()) - { - ::snprintf(command_string, sizeof(command_string), "target create %s", core_file_spec.c_str()); - m_debugger.HandleCommand(command_string); - ; - } - else if (!m_option_data.m_process_name.empty()) - { - ::snprintf(command_string, sizeof(command_string), "process attach --name '%s'%s", m_option_data.m_process_name.c_str(), - m_option_data.m_wait_for ? " --waitfor" : ""); - m_debugger.HandleCommand(command_string); - } - else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) - { - ::snprintf(command_string, sizeof(command_string), "process attach --pid %" PRIu64, m_option_data.m_process_pid); - m_debugger.HandleCommand(command_string); - } - - ExecuteInitialCommands(false); - - // 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()); - result.PutOutput(m_debugger.GetOutputFileHandle()); - } - - bool handle_events = true; - bool spawn_thread = false; - m_debugger.RunCommandInterpreter(handle_events, spawn_thread); - - reset_stdin_termios(); - fclose(stdin); - - SBDebugger::Destroy(m_debugger); -} - -void -Driver::ResizeWindow(unsigned short col) -{ - GetDebugger().SetTerminalWidth(col); -} - -//++ ------------------------------------------------------------------------------------ -// Details: Setup *this driver so it works as pass through (child) driver for the MI -// driver. Called by the parent (MI driver) driver. -// This driver has setup code in two places. The original in MainLoop() and -// in int main() (when MICONFIG_COMPILE_MIDRIVER_VERSION == 0) so that code can -// remain as much near to the original code as possible. If MI driver is the main -// driver (when MICONFIG_COMPILE_MIDRIVER_VERSION == 1) then this function is -// used to set up the Driver to work with the MI driver. -// Type: Method. -// Args: vwErrMsg - (W) On failure current error discription. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -Driver::MISetup(CMIUtilString &vwErrMsg) -{ - bool bOk = MIstatus::success; - - // Is *this driver a pass through driver to the MI driver - CMIDriverBase *pParent = GetDriversParent(); - if (pParent == nullptr) - { - // No it is not. - // If MI is the main driver (which passes through to *this driver) then - // *this driver needs to be initialized after MI is initialize to have a valid - // pointer to the parent driver. *this is the parent's pass thru driver. - assert(pParent == nullptr); - return MIstatus::success; // Allow success for if Driver is the main driver - } - - // MI driver may have streams it wants *this driver to use - still to be sorted - m_debugger.SetErrorFileHandle(pParent->GetStderr(), false); // MI may redirect to its own stream - m_debugger.SetOutputFileHandle(pParent->GetStdout(), false); // MI likely to NULL this - m_debugger.SetInputFileHandle(pParent->GetStdin(), false); // MI could use this to feed input - - // ToDo: Do I need this? - m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); - - // ToDo: Do I need this? - struct winsize window_size; - if (isatty(STDIN_FILENO) && ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) - { - if (window_size.ws_col > 0) - m_debugger.SetTerminalWidth(window_size.ws_col); - } - - return bOk; -} - -//++ ------------------------------------------------------------------------------------ -// Details: Initialize setup *this driver ready for use. -// Type: Overridden. -// Args: None. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -Driver::DoInitialize(void) -{ - // Do nothing - return MIstatus::success; -} - -//++ ------------------------------------------------------------------------------------ -// Details: Unbind detach or release resources used by *this driver. -// Type: Overridden. -// Args: None. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -Driver::DoShutdown(void) -{ - SBDebugger::Destroy(m_debugger); - - // Is *this driver a pass through driver to the MI driver - CMIDriverBase *pParent = GetDriversParent(); - if (pParent == nullptr) - { - // See DoInitialize(). - assert(pParent == nullptr); - return MIstatus::success; - } - - // Put stuff here when *this driver is a pass thru driver to the MI driver - - return MIstatus::success; -} - -//++ ------------------------------------------------------------------------------------ -// Details: Retrieve the name for *this driver. -// Type: Overridden. -// Args: None. -// Return: CMIUtilString & - Driver name. -// Throws: None. -//-- -const CMIUtilString & -Driver::GetName(void) const -{ - static CMIUtilString name("LLDB driver"); - return name; -} - -//++ ------------------------------------------------------------------------------------ -// Details: Retrieve *this driver's last error condition. -// Type: Overridden. -// Args: None. -// Return: CMIUtilString - Text description. -// Throws: None. -//-- -CMIUtilString -Driver::GetError(void) const -{ - // Do nothing - to implement - return CMIUtilString(); -} - -//++ ------------------------------------------------------------------------------------ -// Details: Call this function puts *this driver to work. -// Type: Overridden. -// Args: None. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -Driver::DoMainLoop(void) -{ - MainLoop(); - - return MIstatus::success; -} - -//++ ------------------------------------------------------------------------------------ -// Details: Call *this driver to resize the console window. -// Type: Overridden. -// Args: vTermWidth - (R) New window column size. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -void -Driver::DoResizeWindow(const uint32_t vTermWidth) -{ - ResizeWindow((unsigned short)vTermWidth); -} - -//++ ------------------------------------------------------------------------------------ -// Details: Call *this driver to return it's debugger. -// Type: Overridden. -// Args: None. -// Return: lldb::SBDebugger & - LLDB debugger object reference. -// Throws: None. -//-- -lldb::SBDebugger & -Driver::GetTheDebugger(void) -{ - return GetDebugger(); -} - -//++ ------------------------------------------------------------------------------------ -// Details: Proxy function to allow the driver implementation to validate executable -// command line arguments. -// Type: Overrideable. -// Args: argc - (R) An integer that contains the count of arguments that follow in -// argv. The argc parameter is always greater than or equal to 1. -// argv - (R) An array of null-terminated strings representing command-line -// arguments entered by the user of the program. By convention, -// argv[0] is the command with which the program is invoked. -// vpStdOut - (R) Pointer to a standard output stream. -// vwbExiting - (W) True = *this want to exit, Reasons: help, invalid arg(s), -// version information only. -// False = Continue to work, start debugger i.e. Command -// interpreter. -// Return: lldb::SBError - LLDB current error status. -// Throws: None. -//-- -lldb::SBError -Driver::DoParseArgs(const int argc, const char *argv[], FILE *vpStdOut, bool &vwbExiting) -{ - return ParseArgs(argc, argv, vpStdOut, vwbExiting); -} - -//++ ------------------------------------------------------------------------------------ -// Details: A client can ask if *this driver is GDB/MI compatible. -// Type: Overridden. -// Args: None. -// Return: True - GBD/MI compatible LLDB front end. -// False - Not GBD/MI compatible LLDB front end. -// Throws: None. -//-- -bool -Driver::GetDriverIsGDBMICompatibleDriver(void) const -{ - return false; -} - -//++ ------------------------------------------------------------------------------------ -// Details: This function allows *this driver to call on another driver to perform work -// should this driver not be able to handle the client data input. -// SetDriverToFallThruTo() specifies the fall through to driver. -// Check the error message if the function returns a failure. -// Type: Overridden. -// Args: vCmd - (R) Command instruction to interpret. -// vwErrMsg - (W) Error description on command failing. -// Return: MIstatus::success - Command succeeded. -// MIstatus::failure - Command failed. -// Throws: None. -//-- -bool -Driver::DoFallThruToAnotherDriver(const CMIUtilString &vCmd, CMIUtilString &vwErrMsg) -{ - bool bOk = MIstatus::success; - vwErrMsg.empty(); - - // ToDo: Implement do work on other driver after this driver said "Give up you try" - // This may nto be required if the feature to 'fall through' is not required - SBCommandReturnObject returnObj = lldb::SBCommandReturnObject(); - SBCommandInterpreter cmdIntrp = m_debugger.GetCommandInterpreter(); - const lldb::ReturnStatus cmdResult = cmdIntrp.HandleCommand(vCmd.c_str(), returnObj); - MIunused(cmdResult); - if (returnObj.Succeeded() == false) - { - bOk = MIstatus::failure; - vwErrMsg = returnObj.GetError(); - } - - return bOk; -} - -//++ ------------------------------------------------------------------------------------ -// Details: This function allows *this driver to call functionality on the parent driver -// ask for information for example. -// Type: Overridden. -// Args: vrOtherDriver - (R) Reference to another driver object. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -Driver::SetDriverParent(const CMIDriverBase &vrOtherDriver) -{ - m_pDriverParent = const_cast<CMIDriverBase *>(&vrOtherDriver); - - return MIstatus::success; -} - -//++ ------------------------------------------------------------------------------------ -// Details: Set a unique ID for *this driver. It cannot be empty. -// Type: Overridden. -// Args: vId - (R) Text description. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. -// Throws: None. -//-- -bool -Driver::SetId(const CMIUtilString &vId) -{ - if (vId.empty()) - { - // Invalid to have it empty - return MIstatus::failure; - } - - m_strDriverId = vId; - return MIstatus::success; -} - -//++ ------------------------------------------------------------------------------------ -// Details: Get the unique ID for *this driver. -// Type: Overridden. -// Args: None. -// Return: CMIUtilString & - Text description. -// Throws: None. -//-- -const CMIUtilString & -Driver::GetId(void) const -{ - return m_strDriverId; -} - -//++ ------------------------------------------------------------------------------------ -// Details: Create *this driver. Function contains functionality that needs to be called -// prior to constructing the *this driver. -// Type: Static method. -// Args: None. -// Return: Driver * - Ptr to the LLDB driver object. -// Throws: None. -//-- -Driver * -Driver::CreateSelf(void) -{ - lldb::SBDebugger::Initialize(); - - Driver *pDriver = new Driver; - return pDriver; -} - -//++ ------------------------------------------------------------------------------------ -// Details: Retrieve the name for *this driver. -// Type: Overridden. -// Args: None. -// Return: CMIUtilString - Driver name. -// Throws: None. -//-- -const CMIUtilString & -Driver::GetDriverName(void) const -{ - return GetName(); -} - -//++ ------------------------------------------------------------------------------------ -// Details: Get the unique ID for *this driver. -// Type: Overridden. -// Args: None. -// Return: CMIUtilString & - Text description. -// Throws: None. -//-- -const CMIUtilString & -Driver::GetDriverId(void) const -{ - return GetId(); -} - -#endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER |