diff options
Diffstat (limited to 'lldb/source/Commands')
72 files changed, 14027 insertions, 0 deletions
diff --git a/lldb/source/Commands/CommandObjectAdd.cpp b/lldb/source/Commands/CommandObjectAdd.cpp new file mode 100644 index 00000000000..cd1d02d22ff --- /dev/null +++ b/lldb/source/Commands/CommandObjectAdd.cpp @@ -0,0 +1,51 @@ +//===-- CommandObjectAdd.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectAdd.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Core/Options.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectAdd +//------------------------------------------------------------------------- + +CommandObjectAdd::CommandObjectAdd () : + CommandObject ("add", + "Allows the user to add a new command/function pair to the debugger's dictionary.", + "add <new-command-name> <script-function-name>") +{ +} + +CommandObjectAdd::~CommandObjectAdd() +{ +} + + +bool +CommandObjectAdd::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + result.AppendMessage ("This function has not been implemented yet."); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); +} diff --git a/lldb/source/Commands/CommandObjectAdd.h b/lldb/source/Commands/CommandObjectAdd.h new file mode 100644 index 00000000000..9aa59b61a7a --- /dev/null +++ b/lldb/source/Commands/CommandObjectAdd.h @@ -0,0 +1,43 @@ +//===-- CommandObjectAdd.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectAdd_h_ +#define liblldb_CommandObjectAdd_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { +//------------------------------------------------------------------------- +// CommandObjectAdd +//------------------------------------------------------------------------- + +class CommandObjectAdd : public CommandObject +{ +public: + + CommandObjectAdd (); + + virtual + ~CommandObjectAdd (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectAdd_h_ diff --git a/lldb/source/Commands/CommandObjectAlias.cpp b/lldb/source/Commands/CommandObjectAlias.cpp new file mode 100644 index 00000000000..50c2ab92e9f --- /dev/null +++ b/lldb/source/Commands/CommandObjectAlias.cpp @@ -0,0 +1,225 @@ +//===-- CommandObjectAlias.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectAlias.h" + + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" +#include "lldb/Core/Args.h" +#include "lldb/Core/Options.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/CommandInterpreter.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectAlias +//------------------------------------------------------------------------- + +CommandObjectAlias::CommandObjectAlias () : + CommandObject ("alias", + "Allows users to define their own debugger command abbreviations.", + "alias <new_command> <old_command> [<options-for-aliased-command>]") +{ + SetHelpLong( +"'alias' allows the user to create a short-cut or abbreviation for long \n\ +commands, multi-word commands, and commands that take particular options. \n\ +Below are some simple examples of how one might use the 'alias' command: \n\ +\n 'alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\ + // command. \n\ + 'alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\ + // command. Since breakpoint commands are two-word \n\ + // commands, the user will still need to enter the \n\ + // second word after 'bp', e.g. 'bp enable' or \n\ + // 'bp delete'. \n\ + 'alias bpi breakpoint list' // Creates the abbreviation 'bpi' for the \n\ + // two-word command 'breakpoint list'. \n\ +\nAn alias can include some options for the command, with the values either \n\ +filled in at the time the alias is created, or specified as positional \n\ +arguments, to be filled in when the alias is invoked. The following example \n\ +shows how to create aliases with options: \n\ +\n\ + 'alias bfl breakpoint set -f %1 -l %2' \n\ +\nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\ +options already part of the alias. So if the user wants to set a breakpoint \n\ +by file and line without explicitly having to use the -f and -l options, the \n\ +user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\ +for the actual arguments that will be passed when the alias command is used. \n\ +The number in the placeholder refers to the position/order the actual value \n\ +occupies when the alias is used. So all the occurrences of '%1' in the alias \n\ +will be replaced with the first argument, all the occurrences of '%2' in the \n\ +alias will be replaced with the second argument, and so on. This also allows \n\ +actual arguments to be used multiple times within an alias (see 'process \n\ +launch' example below). So in the 'bfl' case, the actual file value will be \n\ +filled in with the first argument following 'bfl' and the actual line number \n\ +value will be filled in with the second argument. The user would use this \n\ +alias as follows: \n\ +\n (dbg) alias bfl breakpoint set -f %1 -l %2 \n\ + <... some time later ...> \n\ + (dbg) bfl my-file.c 137 \n\ +\nThis would be the same as if the user had entered \n\ +'breakpoint set -f my-file.c -l 137'. \n\ +\nAnother example: \n\ +\n (dbg) alias pltty process launch -s -o %1 -e %1 \n\ + (dbg) pltty /dev/tty0 \n\ + // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\ +\nIf the user always wanted to pass the same value to a particular option, the \n\ +alias could be defined with that value directly in the alias as a constant, \n\ +rather than using a positional placeholder: \n\ +\n alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\ + // 3 of whatever file is indicated. \n"); + +} + +CommandObjectAlias::~CommandObjectAlias () +{ +} + + +bool +CommandObjectAlias::Execute (Args& args, CommandContext *context, CommandInterpreter *interpreter, + CommandReturnObject &result) +{ + const int argc = args.GetArgumentCount(); + + if (argc < 2) + { + result.AppendError ("'alias' requires at least two arguments"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const std::string alias_command = args.GetArgumentAtIndex(0); + const std::string actual_command = args.GetArgumentAtIndex(1); + + args.Shift(); // Shift the alias command word off the argument vector. + args.Shift(); // Shift the old command word off the argument vector. + + // Verify that the command is alias'able, and get the appropriate command object. + + if (interpreter->CommandExists (alias_command.c_str())) + { + result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n", + alias_command.c_str()); + result.SetStatus (eReturnStatusFailed); + } + else + { + CommandObjectSP command_obj_sp(interpreter->GetCommandSP (actual_command.c_str())); + CommandObjectSP subcommand_obj_sp; + bool use_subcommand = false; + if (command_obj_sp.get()) + { + CommandObject *cmd_obj = command_obj_sp.get(); + CommandObject *sub_cmd_obj; + OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector); + OptionArgVector *option_arg_vector = option_arg_vector_sp.get(); + + if (cmd_obj->IsMultiwordObject()) + { + if (argc >= 3) + { + const std::string sub_command = args.GetArgumentAtIndex(0); + assert (sub_command.length() != 0); + subcommand_obj_sp = + (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str())); + if (subcommand_obj_sp.get()) + { + sub_cmd_obj = subcommand_obj_sp.get(); + use_subcommand = true; + args.Shift(); // Shift the sub_command word off the argument vector. + } + else + { + result.AppendErrorWithFormat ("Error occurred while attempting to look up command '%s %s'.\n", + alias_command.c_str(), sub_command.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + } + + // Verify & handle any options/arguments passed to the alias command + + if (args.GetArgumentCount () > 0) + { + if ((!use_subcommand && (cmd_obj->WantsRawCommandString())) + || (use_subcommand && (sub_cmd_obj->WantsRawCommandString()))) + { + result.AppendErrorWithFormat ("'%s' cannot be aliased with any options or arguments.\n", + (use_subcommand ? sub_cmd_obj->GetCommandName() + : cmd_obj->GetCommandName())); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // options or arguments have been passed to the alias command, and must be verified & processed here. + if ((!use_subcommand && (cmd_obj->GetOptions() != NULL)) + || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL))) + { + Options *options; + if (use_subcommand) + options = sub_cmd_obj->GetOptions(); + else + options = cmd_obj->GetOptions(); + options->ResetOptionValues (); + args.Unshift ("dummy_arg"); + args.ParseAliasOptions (*options, result, option_arg_vector); + args.Shift (); + if (result.Succeeded()) + options->VerifyPartialOptions (result); + if (!result.Succeeded()) + return false; + } + else + { + for (int i = 0; i < args.GetArgumentCount(); ++i) + option_arg_vector->push_back (OptionArgPair ("<argument>", + std::string (args.GetArgumentAtIndex (i)))); + } + } + + // Create the alias. + + if (interpreter->AliasExists (alias_command.c_str()) + || interpreter->UserCommandExists (alias_command.c_str())) + { + OptionArgVectorSP tmp_option_arg_sp (interpreter->GetAliasOptions (alias_command.c_str())); + if (tmp_option_arg_sp.get()) + { + if (option_arg_vector->size() == 0) + interpreter->RemoveAliasOptions (alias_command.c_str()); + } + result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n", alias_command.c_str()); + } + + if (use_subcommand) + interpreter->AddAlias (alias_command.c_str(), subcommand_obj_sp); + else + interpreter->AddAlias (alias_command.c_str(), command_obj_sp); + if (option_arg_vector->size() > 0) + interpreter->AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str()); + result.SetStatus (eReturnStatusFailed); + } + } + + return result.Succeeded(); +} + diff --git a/lldb/source/Commands/CommandObjectAlias.h b/lldb/source/Commands/CommandObjectAlias.h new file mode 100644 index 00000000000..859b7cea049 --- /dev/null +++ b/lldb/source/Commands/CommandObjectAlias.h @@ -0,0 +1,43 @@ +//===-- CommandObjectAlias.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectAlias_h_ +#define liblldb_CommandObjectAlias_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectAlias +//------------------------------------------------------------------------- + +class CommandObjectAlias : public CommandObject +{ +public: + + CommandObjectAlias (); + + virtual + ~CommandObjectAlias (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectAlias_h_ diff --git a/lldb/source/Commands/CommandObjectAppend.cpp b/lldb/source/Commands/CommandObjectAppend.cpp new file mode 100644 index 00000000000..613b85b4be9 --- /dev/null +++ b/lldb/source/Commands/CommandObjectAppend.cpp @@ -0,0 +1,95 @@ +//===-- CommandObjectAppend.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectAppend.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//----------------------------------------------------------------------------- +// CommandObjectAppend +//----------------------------------------------------------------------------- + +CommandObjectAppend::CommandObjectAppend () : + CommandObject ("append", + "Allows the user to append a value to a single debugger setting variable, for settings that are of list types. Type 'settings' to see a list of debugger setting variables", + "append <var-name> <value-string>") +{ +} + +CommandObjectAppend::~CommandObjectAppend () +{ +} + +bool +CommandObjectAppend::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + CommandInterpreter::VariableMap::iterator pos; + + const int argc = command.GetArgumentCount(); + if (argc < 2) + { + result.AppendError ("'append' requires at least two arguments"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const char *var_name = command.GetArgumentAtIndex(0); + command.Shift(); + + + if (var_name == NULL || var_name[0] == '\0') + { + result.AppendError ("'set' command requires a valid variable name. No value supplied"); + result.SetStatus (eReturnStatusFailed); + } + else + { + StateVariable *var = interpreter->GetStateVariable(var_name); + if (var == NULL) + { + result.AppendErrorWithFormat ("'%s' is not a settable internal variable.\n", var_name); + result.SetStatus (eReturnStatusFailed); + } + else + { + if (var->GetType() == StateVariable::eTypeString) + { + for (int i = 0; i < command.GetArgumentCount(); ++i) + var->AppendStringValue (command.GetArgumentAtIndex(i)); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else if (var->GetType() == StateVariable::eTypeStringArray) + { + var->GetArgs().AppendArguments (command); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendErrorWithFormat ("Values cannot be appended to variable '%s'. Try 'set' instead.\n", var_name); + result.SetStatus (eReturnStatusFailed); + } + } + } + return result.Succeeded(); +} + diff --git a/lldb/source/Commands/CommandObjectAppend.h b/lldb/source/Commands/CommandObjectAppend.h new file mode 100644 index 00000000000..436283730fb --- /dev/null +++ b/lldb/source/Commands/CommandObjectAppend.h @@ -0,0 +1,43 @@ +//===-- CommandObjectAppend.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectAppend_h_ +#define liblldb_CommandObjectAppend_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { +//----------------------------------------------------------------------------- +// CommandObjectAppend +//----------------------------------------------------------------------------- + +class CommandObjectAppend : public CommandObject +{ +public: + CommandObjectAppend (); + + virtual + ~CommandObjectAppend (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectAppend_h_ diff --git a/lldb/source/Commands/CommandObjectApropos.cpp b/lldb/source/Commands/CommandObjectApropos.cpp new file mode 100644 index 00000000000..0fcc093901f --- /dev/null +++ b/lldb/source/Commands/CommandObjectApropos.cpp @@ -0,0 +1,96 @@ +//===-- CommandObjectApropos.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectApropos.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Options.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectApropos +//------------------------------------------------------------------------- + +CommandObjectApropos::CommandObjectApropos () : + CommandObject ("apropos", + "Finds a list of debugger commands related to a particular word/subject.", + "apropos <search-word>") +{ +} + +CommandObjectApropos::~CommandObjectApropos() +{ +} + + +bool +CommandObjectApropos::Execute (Args &command, CommandContext *context, CommandInterpreter *interpreter, + CommandReturnObject &result) +{ + const int argc = command.GetArgumentCount (); + + if (argc == 1) + { + const char *search_word = command.GetArgumentAtIndex(0); + if ((search_word != NULL) + && (strlen (search_word) > 0)) + { + // The bulk of the work must be done inside the Command Interpreter, since the command dictionary + // is private. + StringList commands_found; + StringList commands_help; + interpreter->FindCommandsForApropos (search_word, commands_found, commands_help); + if (commands_found.GetSize() == 0) + { + result.AppendMessageWithFormat ("No commands found pertaining to '%s'.", search_word); + result.AppendMessage ("Try 'help' to see a complete list of debugger commands."); + } + else + { + result.AppendMessageWithFormat ("The following commands may relate to '%s':\n", search_word); + size_t max_len = 0; + + for (int i = 0; i < commands_found.GetSize(); ++i) + { + int len = strlen (commands_found.GetStringAtIndex (i)); + if (len > max_len) + max_len = len; + } + + for (int i = 0; i < commands_found.GetSize(); ++i) + interpreter->OutputFormattedHelpText (result.GetOutputStream(), commands_found.GetStringAtIndex(i), + "--", commands_help.GetStringAtIndex(i), max_len); + + } + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError ("'' is not a valid search word.\n"); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("'apropos' must be called with exactly one argument.\n"); + result.SetStatus (eReturnStatusFailed); + } + + return result.Succeeded(); +} diff --git a/lldb/source/Commands/CommandObjectApropos.h b/lldb/source/Commands/CommandObjectApropos.h new file mode 100644 index 00000000000..a079a3fc4ac --- /dev/null +++ b/lldb/source/Commands/CommandObjectApropos.h @@ -0,0 +1,45 @@ +//===-- CommandObjectApropos.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectApropos_h_ +#define liblldb_CommandObjectApropos_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectApropos +//------------------------------------------------------------------------- + +class CommandObjectApropos : public CommandObject +{ +public: + + CommandObjectApropos (); + + virtual + ~CommandObjectApropos (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectApropos_h_ diff --git a/lldb/source/Commands/CommandObjectArgs.cpp b/lldb/source/Commands/CommandObjectArgs.cpp new file mode 100644 index 00000000000..7f1fd3dda94 --- /dev/null +++ b/lldb/source/Commands/CommandObjectArgs.cpp @@ -0,0 +1,279 @@ +//===-- CommandObjectArgs.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectArgs.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Value.h" +#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangExpressionVariable.h" +#include "lldb/Expression/ClangFunction.h" +#include "lldb/Host/Host.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/StackFrame.h" + +using namespace lldb; +using namespace lldb_private; + +// This command is a toy. I'm just using it to have a way to construct the arguments to +// calling functions. +// + +CommandObjectArgs::CommandOptions::CommandOptions () : +Options() +{ + // Keep only one place to reset the values to their defaults + ResetOptionValues(); +} + + +CommandObjectArgs::CommandOptions::~CommandOptions () +{ +} + +Error +CommandObjectArgs::CommandOptions::SetOptionValue (int option_idx, const char *option_arg) +{ + Error error; + + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + default: + error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); + break; + } + + return error; +} + +void +CommandObjectArgs::CommandOptions::ResetOptionValues () +{ + Options::ResetOptionValues(); +} + +const lldb::OptionDefinition* +CommandObjectArgs::CommandOptions::GetDefinitions () +{ + return g_option_table; +} + +CommandObjectArgs::CommandObjectArgs () : + CommandObject ("args", + "When stopped at the start of a function, reads function arguments of type (u?)int(8|16|32|64)_t, (void|char)*", + "args") +{ +} + +CommandObjectArgs::~CommandObjectArgs () +{ +} + +Options * +CommandObjectArgs::GetOptions () +{ + return &m_options; +} + +bool +CommandObjectArgs::Execute(Args &command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) +{ + ConstString target_triple; + + Process *process = context->GetExecutionContext().process; + if (!process) + { + result.AppendError ("Args found no process."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const ABI *abi = process->GetABI (); + if (!abi) + { + result.AppendError ("The current process has no ABI."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + int num_args = command.GetArgumentCount (); + int arg_index; + + if (!num_args) + { + result.AppendError ("args requires at least one argument"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Thread *thread = context->GetExecutionContext ().thread; + + if (!thread) + { + result.AppendError ("args found no thread."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + lldb::StackFrameSP thread_cur_frame = thread->GetCurrentFrame (); + if (!thread_cur_frame) + { + result.AppendError ("The current thread has no current frame."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Module *thread_module = thread_cur_frame->GetPC ().GetModule (); + if (!thread_module) + { + result.AppendError ("The PC has no associated module."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + TypeList *thread_type_list = thread_module->GetTypeList (); + if (!thread_type_list) + { + result.AppendError ("The module has no type list."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + ClangASTContext &ast_context = thread_type_list->GetClangASTContext(); + + ValueList value_list; + + for (arg_index = 0; arg_index < num_args; ++arg_index) + { + const char *arg_type_cstr = command.GetArgumentAtIndex(arg_index); + Value value; + value.SetValueType(Value::eValueTypeScalar); + void *type; + + char *int_pos; + if ((int_pos = strstr (arg_type_cstr, "int"))) + { + Encoding encoding = eEncodingSint; + + int width = 0; + + if (int_pos > arg_type_cstr + 1) + { + result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); + result.SetStatus (eReturnStatusFailed); + return false; + } + if (int_pos == arg_type_cstr + 1 && arg_type_cstr[0] != 'u') + { + result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); + result.SetStatus (eReturnStatusFailed); + return false; + } + if (arg_type_cstr[0] == 'u') + { + encoding = eEncodingUint; + } + + char *width_pos = int_pos + 3; + + if (!strcmp (width_pos, "8_t")) + width = 8; + else if (!strcmp (width_pos, "16_t")) + width = 16; + else if (!strcmp (width_pos, "32_t")) + width = 32; + else if (!strcmp (width_pos, "64_t")) + width = 64; + else + { + result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); + result.SetStatus (eReturnStatusFailed); + return false; + } + + type = ast_context.GetBuiltinTypeForEncodingAndBitSize(encoding, width); + + if (!type) + { + result.AppendErrorWithFormat ("Couldn't get Clang type for format %s (%s integer, width %d).\n", + arg_type_cstr, + (encoding == eEncodingSint ? "signed" : "unsigned"), + width); + + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else if (strchr (arg_type_cstr, '*')) + { + if (!strcmp (arg_type_cstr, "void*")) + type = ast_context.CreatePointerType (ast_context.GetVoidBuiltInType ()); + else if (!strcmp (arg_type_cstr, "char*")) + type = ast_context.GetCStringType (false); + else + { + result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr); + result.SetStatus (eReturnStatusFailed); + return false; + } + + value.SetContext (Value::eContextTypeOpaqueClangQualType, type); + + value_list.PushValue(value); + } + + if (!abi->GetArgumentValues (*thread, value_list)) + { + result.AppendError ("Couldn't get argument values"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + result.GetOutputStream ().Printf("Arguments : \n"); + + for (arg_index = 0; arg_index < num_args; ++arg_index) + { + result.GetOutputStream ().Printf ("%d (%s): ", arg_index, command.GetArgumentAtIndex (arg_index)); + value_list.GetValueAtIndex (arg_index)->Dump (&result.GetOutputStream ()); + result.GetOutputStream ().Printf("\n"); + } + + return result.Succeeded(); +} + +lldb::OptionDefinition +CommandObjectArgs::CommandOptions::g_option_table[] = +{ + { 0, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable verbose debug logging of the expression parsing and evaluation."}, + { 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL } +}; + diff --git a/lldb/source/Commands/CommandObjectArgs.h b/lldb/source/Commands/CommandObjectArgs.h new file mode 100644 index 00000000000..d326d423247 --- /dev/null +++ b/lldb/source/Commands/CommandObjectArgs.h @@ -0,0 +1,76 @@ +//===-- CommandObjectArgs.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectArgs_h_ +#define liblldb_CommandObjectArgs_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/Language.h" + +namespace lldb_private { + + class CommandObjectArgs : public CommandObject + { + public: + + class CommandOptions : public Options + { + public: + + CommandOptions (); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues (); + + const lldb::OptionDefinition* + GetDefinitions (); + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + }; + + CommandObjectArgs (); + + virtual + ~CommandObjectArgs (); + + virtual + Options * + GetOptions (); + + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual bool + WantsRawCommandString() { return false; } + + protected: + + CommandOptions m_options; + }; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectArgs_h_ diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp new file mode 100644 index 00000000000..d24ba8f553b --- /dev/null +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -0,0 +1,953 @@ +//===-- CommandObjectBreakpoint.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectBreakpoint.h" +#include "CommandObjectBreakpointCommand.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Breakpoint/BreakpointIDList.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Target.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Target/StackFrame.h" + +using namespace lldb; +using namespace lldb_private; + +static void +AddBreakpointDescription (CommandContext *context, StreamString *s, Breakpoint *bp, lldb::DescriptionLevel level) +{ + s->IndentMore(); + bp->GetDescription (s, level, true); + s->IndentLess(); + s->EOL(); +} + +//------------------------------------------------------------------------- +// CommandObjectBreakpointSet::CommandOptions +//------------------------------------------------------------------------- + +CommandObjectBreakpointSet::CommandOptions::CommandOptions() : + Options (), + m_filename (), + m_line_num (0), + m_column (0), + m_ignore_inlines (false), + m_func_name (), + m_func_regexp (), + m_modules (), + m_load_addr() +{ + BuildValidOptionSets(); +} + +CommandObjectBreakpointSet::CommandOptions::~CommandOptions () +{ +} + +lldb::OptionDefinition +CommandObjectBreakpointSet::CommandOptions::g_option_table[] = +{ + { 0, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, "<filename>", + "Set the breakpoint by source location in this particular file."}, + + { 0, true, "line", 'l', required_argument, NULL, 0, "<linenum>", + "Set the breakpoint by source location at this particular line."}, + + { 0, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>", + "Set the breakpoint only in this shared library (can use this option multiple times for multiple shlibs)."}, + + // Comment out this option for the moment, as we don't actually use it, but will in the future. + // This way users won't see it, but the infrastructure is left in place. + // { 0, false, "column", 'c', required_argument, NULL, "<column>", + // "Set the breakpoint by source location at this particular column."}, + + { 0, false, "ignore_inlines", 'i', no_argument, NULL, 0, NULL, + "Ignore inlined subroutines when setting the breakppoint." }, + + { 1, true, "address", 'a', required_argument, NULL, 0, "<address>", + "Set the breakpoint by address, at the specified address."}, + + { 1, false, "ignore_inlines", 'i', no_argument, NULL, 0, NULL, + "Ignore inlined subroutines when setting the breakppoint." }, + + { 2, true, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, "<function-name>", + "Set the breakpoint by function name." }, + + { 2, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>", + "Set the breakpoint only in this shared library (can use this option multiple times for multiple shlibs)."}, + + { 2, false, "ignore_inlines", 'i', no_argument, NULL, 0, NULL, + "Ignore inlined subroutines when setting the breakpoint." }, + + { 3, true, "func_regex", 'r', required_argument, NULL, 0, "<regular-expression>", + "Set the breakpoint by function name, evaluating a regular-expression to find the function name(s)." }, + + { 3, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, "<shlib-name>", + "Set the breakpoint only in this shared library (can use this option multiple times for multiple shlibs)."}, + + { 3, false, "ignore_inlines", 'i', no_argument, NULL, 0, NULL, + "Ignore inlined subroutines when setting the breakpoint." }, + + { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + +const lldb::OptionDefinition* +CommandObjectBreakpointSet::CommandOptions::GetDefinitions () +{ + return g_option_table; +} + +Error +CommandObjectBreakpointSet::CommandOptions::SetOptionValue (int option_idx, const char *option_arg) +{ + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'a': + m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 0); + if (m_load_addr == LLDB_INVALID_ADDRESS) + m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 16); + + if (m_load_addr == LLDB_INVALID_ADDRESS) + error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", optarg); + break; + + case 'c': + m_column = Args::StringToUInt32 (option_arg, 0); + break; + case 'f': + m_filename = option_arg; + break; + case 'i': + m_ignore_inlines = true; + break; + case 'l': + m_line_num = Args::StringToUInt32 (option_arg, 0); + break; + case 'n': + m_func_name = option_arg; + break; + case 'r': + m_func_regexp = option_arg; + break; + case 's': + { + m_modules.push_back (std::string (option_arg)); + break; + } + default: + error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); + break; + } + + return error; +} + +void +CommandObjectBreakpointSet::CommandOptions::ResetOptionValues () +{ + Options::ResetOptionValues(); + + m_filename.clear(); + m_line_num = 0; + m_column = 0; + m_ignore_inlines = false; + m_func_name.clear(); + m_func_regexp.clear(); + m_load_addr = LLDB_INVALID_ADDRESS; + m_modules.clear(); +} + +//------------------------------------------------------------------------- +// CommandObjectBreakpointSet +//------------------------------------------------------------------------- + +CommandObjectBreakpointSet::CommandObjectBreakpointSet () : + CommandObject ("breakpoint set", "Sets a breakpoint or set of breakpoints in the executable.", + "breakpoint set <cmd-options>") +{ +} + +CommandObjectBreakpointSet::~CommandObjectBreakpointSet () +{ +} + +Options * +CommandObjectBreakpointSet::GetOptions () +{ + return &m_options; +} + +bool +CommandObjectBreakpointSet::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("Invalid target, set executable file using 'file' command."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // The following are the various types of breakpoints that could be set: + // 1). -f -l -p [-s -g] (setting breakpoint by source location) + // 2). -a [-s -g] (setting breakpoint by address) + // 3). -n [-s -g] (setting breakpoint by function name) + // 4). -r [-s -g] (setting breakpoint by function name regular expression) + + BreakpointSetType break_type = eSetTypeInvalid; + + if (m_options.m_line_num != 0) + break_type = eSetTypeFileAndLine; + else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) + break_type = eSetTypeAddress; + else if (!m_options.m_func_name.empty()) + break_type = eSetTypeFunctionName; + else if (!m_options.m_func_regexp.empty()) + break_type = eSetTypeFunctionRegexp; + + ModuleSP module_sp = target->GetExecutableModule(); + Breakpoint *bp = NULL; + FileSpec module; + bool use_module = false; + int num_modules = m_options.m_modules.size(); + + if ((num_modules > 0) && (break_type != eSetTypeAddress)) + use_module = true; + + switch (break_type) + { + case eSetTypeFileAndLine: // Breakpoint by source position + { + FileSpec file; + if (m_options.m_filename.empty()) + { + StackFrame *cur_frame = context->GetExecutionContext().frame; + if (cur_frame == NULL) + { + result.AppendError ("Attempting to set breakpoint by line number alone with no selected frame."); + result.SetStatus (eReturnStatusFailed); + break; + } + else if (!cur_frame->HasDebugInformation()) + { + result.AppendError ("Attempting to set breakpoint by line number alone but selected frame has no debug info."); + result.SetStatus (eReturnStatusFailed); + break; + } + else + { + const SymbolContext &context = cur_frame->GetSymbolContext(true); + if (context.line_entry.file) + { + file = context.line_entry.file; + } + else if (context.comp_unit != NULL) + { file = context.comp_unit; + } + else + { + result.AppendError ("Attempting to set breakpoint by line number alone but can't find the file for the selected frame."); + result.SetStatus (eReturnStatusFailed); + break; + } + } + } + else + { + file.SetFile(m_options.m_filename.c_str()); + } + + if (use_module) + { + for (int i = 0; i < num_modules; ++i) + { + module.SetFile(m_options.m_modules[i].c_str()); + bp = target->CreateBreakpoint (&module, + file, + m_options.m_line_num, + m_options.m_ignore_inlines).get(); + if (bp) + { + StreamString &output_stream = result.GetOutputStream(); + output_stream.Printf ("Breakpoint created: "); + bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief); + output_stream.EOL(); + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat("Breakpoint creation failed: No breakpoint created in module '%s'.\n", + m_options.m_modules[i].c_str()); + result.SetStatus (eReturnStatusFailed); + } + } + } + else + bp = target->CreateBreakpoint (NULL, + file, + m_options.m_line_num, + m_options.m_ignore_inlines).get(); + } + break; + case eSetTypeAddress: // Breakpoint by address + bp = target->CreateBreakpoint (m_options.m_load_addr, false).get(); + break; + case eSetTypeFunctionName: // Breakpoint by function name + if (use_module) + { + for (int i = 0; i < num_modules; ++i) + { + module.SetFile(m_options.m_modules[i].c_str()); + bp = target->CreateBreakpoint (&module, m_options.m_func_name.c_str()).get(); + if (bp) + { + StreamString &output_stream = result.GetOutputStream(); + output_stream.Printf ("Breakpoint created: "); + bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief); + output_stream.EOL(); + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat("Breakpoint creation failed: No breakpoint created in module '%s'.\n", + m_options.m_modules[i].c_str()); + result.SetStatus (eReturnStatusFailed); + } + } + } + else + bp = target->CreateBreakpoint (NULL, m_options.m_func_name.c_str()).get(); + break; + case eSetTypeFunctionRegexp: // Breakpoint by regular expression function name + { + RegularExpression regexp(m_options.m_func_regexp.c_str()); + if (use_module) + { + for (int i = 0; i < num_modules; ++i) + { + module.SetFile(m_options.m_modules[i].c_str()); + bp = target->CreateBreakpoint (&module, regexp).get(); + if (bp) + { + StreamString &output_stream = result.GetOutputStream(); + output_stream.Printf ("Breakpoint created: "); + bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief); + output_stream.EOL(); + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat("Breakpoint creation failed: No breakpoint created in module '%s'.\n", + m_options.m_modules[i].c_str()); + result.SetStatus (eReturnStatusFailed); + } + } + } + else + bp = target->CreateBreakpoint (NULL, regexp).get(); + } + break; + default: + break; + } + + if (bp && !use_module) + { + StreamString &output_stream = result.GetOutputStream(); + output_stream.Printf ("Breakpoint created: "); + bp->GetDescription(&output_stream, lldb::eDescriptionLevelBrief); + output_stream.EOL(); + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else if (!bp) + { + result.AppendError ("Breakpoint creation failed: No breakpoint created."); + result.SetStatus (eReturnStatusFailed); + } + + return result.Succeeded(); +} + + + +//------------------------------------------------------------------------- +// CommandObjectMultiwordBreakpoint +//------------------------------------------------------------------------- + +CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInterpreter *interpreter) : + CommandObjectMultiword ("breakpoint", + "A set of commands for operating on breakpoints.", + "breakpoint <command> [<command-options>]") +{ + bool status; + + CommandObjectSP list_command_object (new CommandObjectBreakpointList ()); + CommandObjectSP delete_command_object (new CommandObjectBreakpointDelete ()); + CommandObjectSP enable_command_object (new CommandObjectBreakpointEnable ()); + CommandObjectSP disable_command_object (new CommandObjectBreakpointDisable ()); + CommandObjectSP set_command_object (new CommandObjectBreakpointSet ()); + CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter)); + + enable_command_object->SetCommandName("breakpoint enable"); + disable_command_object->SetCommandName("breakpoint disable"); + set_command_object->SetCommandName("breakpoint set"); + command_command_object->SetCommandName ("breakpoint command"); + list_command_object->SetCommandName ("breakpoint list"); + + status = LoadSubCommand (list_command_object, "list", interpreter); + status = LoadSubCommand (enable_command_object, "enable", interpreter); + status = LoadSubCommand (disable_command_object, "disable", interpreter); + status = LoadSubCommand (delete_command_object, "delete", interpreter); + status = LoadSubCommand (set_command_object, "set", interpreter); + status = LoadSubCommand (command_command_object, "command", interpreter); +} + +CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint () +{ +} + +void +CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, + BreakpointIDList *valid_ids) +{ + // args can be strings representing 1). integers (for breakpoint ids) + // 2). the full breakpoint & location canonical representation + // 3). the word "to" or a hyphen, representing a range (in which case there + // had *better* be an entry both before & after of one of the first two types. + + Args temp_args; + + // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff directly from the old ARGS to + // the new TEMP_ARGS. Do not copy breakpoint id range strings over; instead generate a list of strings for + // all the breakpoint ids in the range, and shove all of those breakpoint id strings into TEMP_ARGS. + + BreakpointIDList::FindAndReplaceIDRanges (args, target, result, temp_args); + + // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList: + + valid_ids->InsertStringArray ((const char **) temp_args.GetArgumentVector(), temp_args.GetArgumentCount(), result); + + // At this point, all of the breakpoint ids that the user passed in have been converted to breakpoint IDs + // and put into valid_ids. + + if (result.Succeeded()) + { + // Now that we've converted everything from args into a list of breakpoint ids, go through our tentative list + // of breakpoint id's and verify that they correspond to valid/currently set breakpoints. + + for (int i = 0; i < valid_ids->Size(); ++i) + { + BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex (i); + Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + if (breakpoint != NULL) + { + int num_locations = breakpoint->GetNumLocations(); + if (cur_bp_id.GetLocationID() > num_locations) + { + StreamString id_str; + BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), + cur_bp_id.GetLocationID()); + i = valid_ids->Size() + 1; + result.AppendErrorWithFormat ("'%s' is not a currently valid breakpoint/location id.\n", + id_str.GetData()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + i = valid_ids->Size() + 1; + result.AppendErrorWithFormat ("'%d' is not a currently valid breakpoint id.\n", cur_bp_id.GetBreakpointID()); + result.SetStatus (eReturnStatusFailed); + } + } + } +} + +//------------------------------------------------------------------------- +// CommandObjectBreakpointList::Options +//------------------------------------------------------------------------- + +CommandObjectBreakpointList::CommandOptions::CommandOptions() : + Options (), + m_level (lldb::eDescriptionLevelFull) // Breakpoint List defaults to brief descriptions +{ + BuildValidOptionSets(); +} + +CommandObjectBreakpointList::CommandOptions::~CommandOptions () +{ +} + +lldb::OptionDefinition +CommandObjectBreakpointList::CommandOptions::g_option_table[] = +{ + { 0, false, "brief", 'b', no_argument, NULL, 0, NULL, + "Give a brief description of the breakpoint (no location info)."}, + + // FIXME: We need to add an "internal" command, and then add this sort of thing to it. + // But I need to see it for now, and don't want to wait. + { 0, false, "internal", 'i', no_argument, NULL, 0, NULL, + "Show debugger internal breakpoints" }, + + { 1, false, "full", 'f', no_argument, NULL, 0, NULL, + "Give a full description of the breakpoint and its locations."}, + // DITTO FIXME + { 1, false, "internal", 'i', no_argument, NULL, 0, NULL, + "Show debugger internal breakpoints" }, + + { 2, false, "verbose", 'v', no_argument, NULL, 0, NULL, + "Explain everything we know about the breakpoint (for debugging debugger bugs)." }, + // DITTO FIXME + { 2, false, "internal", 'i', no_argument, NULL, 0, NULL, + "Show debugger internal breakpoints" }, + + { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + +const lldb::OptionDefinition* +CommandObjectBreakpointList::CommandOptions::GetDefinitions () +{ + return g_option_table; +} + +Error +CommandObjectBreakpointList::CommandOptions::SetOptionValue (int option_idx, const char *option_arg) +{ + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'b': + m_level = lldb::eDescriptionLevelBrief; + break; + case 'f': + m_level = lldb::eDescriptionLevelFull; + break; + case 'v': + m_level = lldb::eDescriptionLevelVerbose; + break; + case 'i': + m_internal = true; + break; + default: + error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); + break; + } + + return error; +} + +void +CommandObjectBreakpointList::CommandOptions::ResetOptionValues () +{ + Options::ResetOptionValues(); + + m_level = lldb::eDescriptionLevelFull; + m_internal = false; +} + +//------------------------------------------------------------------------- +// CommandObjectBreakpointList +//------------------------------------------------------------------------- + +CommandObjectBreakpointList::CommandObjectBreakpointList () : + CommandObject ("breakpoint list", + "List some or all breakpoints at configurable levels of detail.", + "breakpoint list [<breakpoint-id>]") +{ +} + +CommandObjectBreakpointList::~CommandObjectBreakpointList () +{ +} + +Options * +CommandObjectBreakpointList::GetOptions () +{ + return &m_options; +} + +bool +CommandObjectBreakpointList::Execute +( + Args& args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("Invalid target, set executable file using 'file' command."); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return true; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(m_options.m_internal); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendMessage ("No breakpoints currently set."); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return true; + } + + StreamString &output_stream = result.GetOutputStream(); + + if (args.GetArgumentCount() == 0) + { + // No breakpoint selected; show info about all currently set breakpoints. + result.AppendMessage ("Current breakpoints:"); + for (int i = 0; i < num_breakpoints; ++i) + { + Breakpoint *breakpoint = breakpoints.GetBreakpointByIndex (i).get(); + AddBreakpointDescription (context, &output_stream, breakpoint, m_options.m_level); + } + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + // Particular breakpoints selected; show info about that breakpoint. + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + for (int i = 0; i < valid_bp_ids.Size(); ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + AddBreakpointDescription (context, &output_stream, breakpoint, m_options.m_level); + } + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError ("Invalid breakpoint id."); + result.SetStatus (eReturnStatusFailed); + } + } + + return result.Succeeded(); +} + +//------------------------------------------------------------------------- +// CommandObjectBreakpointEnable +//------------------------------------------------------------------------- + +CommandObjectBreakpointEnable::CommandObjectBreakpointEnable () : + CommandObject ("enable", + "Enables the specified disabled breakpoint(s). If no breakpoints are specified, enables all of them.", + "breakpoint enable [<breakpoint-id> | <breakpoint-id-list>]") +{ + // This command object can either be called via 'enable' or 'breakpoint enable'. Because it has two different + // potential invocation methods, we need to be a little tricky about generating the syntax string. + //StreamString tmp_string; + //tmp_string.Printf ("%s <breakpoint-id>", GetCommandName()); + //m_cmd_syntax.assign (tmp_string.GetData(), tmp_string.GetSize()); +} + + +CommandObjectBreakpointEnable::~CommandObjectBreakpointEnable () +{ +} + + +bool +CommandObjectBreakpointEnable::Execute (Args& args, CommandContext *context, + CommandInterpreter *interpreter, CommandReturnObject &result) +{ + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("Invalid target, set executable file using 'file' command."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendError ("No breakpoints exist to be enabled."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (args.GetArgumentCount() == 0) + { + // No breakpoint selected; enable all currently set breakpoints. + target->EnableAllBreakpoints (); + result.AppendMessageWithFormat ("All breakpoints enabled. (%d breakpoints)\n", num_breakpoints); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + // Particular breakpoint selected; enable that breakpoint. + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + int enable_count = 0; + int loc_count = 0; + for (int i = 0; i < valid_bp_ids.Size(); ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) + { + Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) + { + BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get(); + if (location) + { + location->SetEnabled (true); + breakpoint->SetEnabled (true); + ++loc_count; + } + } + else + { + target->EnableBreakpointByID (cur_bp_id.GetBreakpointID()); + ++enable_count; + + int num_locations = breakpoint->GetNumLocations (); + for (int j = 0; j < num_locations; ++j) + { + BreakpointLocation *cur_loc = breakpoint->GetLocationAtIndex(j).get(); + if (cur_loc) + cur_loc->SetEnabled (true); + } + } + } + } + result.AppendMessageWithFormat ("%d breakpoints enabled.\n", enable_count + loc_count); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + + return result.Succeeded(); +} + +//------------------------------------------------------------------------- +// CommandObjectBreakpointDisable +//------------------------------------------------------------------------- + +CommandObjectBreakpointDisable::CommandObjectBreakpointDisable () : + CommandObject ("disable", + "Disables the specified breakpoint(s) without removing it/them. If no breakpoints are specified, disables them all.", + "disable [<breakpoint-id> | <breakpoint-id-list>]") +{ + // This command object can either be called via 'enable' or 'breakpoint enable'. Because it has two different + // potential invocation methods, we need to be a little tricky about generating the syntax string. + //StreamString tmp_string; + //tmp_string.Printf ("%s <breakpoint-id>", GetCommandName()); + //m_cmd_syntax.assign(tmp_string.GetData(), tmp_string.GetSize()); +} + +CommandObjectBreakpointDisable::~CommandObjectBreakpointDisable () +{ +} + +bool +CommandObjectBreakpointDisable::Execute (Args& args, CommandContext *context, + CommandInterpreter *interpreter, CommandReturnObject &result) +{ + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("Invalid target, set executable file using 'file' command."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendError ("No breakpoints exist to be disabled."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (args.GetArgumentCount() == 0) + { + // No breakpoint selected; disable all currently set breakpoints. + target->DisableAllBreakpoints (); + result.AppendMessageWithFormat ("All breakpoints disabled. (%d breakpoints)\n", num_breakpoints); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + // Particular breakpoint selected; disable that breakpoint. + BreakpointIDList valid_bp_ids; + + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + int disable_count = 0; + int loc_count = 0; + for (int i = 0; i < valid_bp_ids.Size(); ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) + { + Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) + { + BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get(); + if (location) + { + location->SetEnabled (false); + ++loc_count; + } + } + else + { + target->DisableBreakpointByID (cur_bp_id.GetBreakpointID()); + ++disable_count; + + int num_locations = breakpoint->GetNumLocations(); + for (int j = 0; j < num_locations; ++j) + { + BreakpointLocation *cur_loc = breakpoint->GetLocationAtIndex(j).get(); + if (cur_loc) + cur_loc->SetEnabled (false); + } + } + } + } + result.AppendMessageWithFormat ("%d breakpoints disabled.\n", disable_count + loc_count); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + + return result.Succeeded(); +} + +//------------------------------------------------------------------------- +// CommandObjectBreakpointDelete +//------------------------------------------------------------------------- + +CommandObjectBreakpointDelete::CommandObjectBreakpointDelete() : + CommandObject ("breakpoint delete", + "Delete the specified breakpoint(s). If no breakpoints are specified, deletes them all.", + "breakpoint delete [<breakpoint-id> | <breakpoint-id-list>]") +{ +} + + +CommandObjectBreakpointDelete::~CommandObjectBreakpointDelete () +{ +} + +bool +CommandObjectBreakpointDelete::Execute (Args& args, CommandContext *context, + CommandInterpreter *interpreter, CommandReturnObject &result) +{ + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("Invalid target, set executable file using 'file' command."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendError ("No breakpoints exist to be deleted."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (args.GetArgumentCount() == 0) + { + // No breakpoint selected; disable all currently set breakpoints. + if (args.GetArgumentCount() != 0) + { + result.AppendErrorWithFormat ("Specify breakpoints to delete with the -i option.\n"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + target->RemoveAllBreakpoints (); + result.AppendMessageWithFormat ("All breakpoints removed. (%d breakpoints)\n", num_breakpoints); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + // Particular breakpoint selected; disable that breakpoint. + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (args, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + int delete_count = 0; + int disable_count = 0; + for (int i = 0; i < valid_bp_ids.Size(); ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) + { + if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) + { + Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get(); + // It makes no sense to try to delete individual locations, so we disable them instead. + if (location) + { + location->SetEnabled (false); + ++disable_count; + } + } + else + { + target->RemoveBreakpointByID (cur_bp_id.GetBreakpointID()); + ++delete_count; + } + } + } + result.AppendMessageWithFormat ("%d breakpoints deleted; %d breakpoint locations disabled.\n", + delete_count, disable_count); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + return result.Succeeded(); +} diff --git a/lldb/source/Commands/CommandObjectBreakpoint.h b/lldb/source/Commands/CommandObjectBreakpoint.h new file mode 100644 index 00000000000..49007438b28 --- /dev/null +++ b/lldb/source/Commands/CommandObjectBreakpoint.h @@ -0,0 +1,235 @@ +//===-- CommandObjectBreakpoint.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectBreakpoint_h_ +#define liblldb_CommandObjectBreakpoint_h_ + +// C Includes +// C++ Includes + +#include <utility> +#include <vector> + +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Address.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/STLUtils.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectMultiwordBreakpoint +//------------------------------------------------------------------------- + +class CommandObjectMultiwordBreakpoint : public CommandObjectMultiword +{ +public: + CommandObjectMultiwordBreakpoint (CommandInterpreter *interpreter); + + virtual + ~CommandObjectMultiwordBreakpoint (); + + static void + VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids); + +}; + +//------------------------------------------------------------------------- +// CommandObjectMultiwordBreakpointSet +//------------------------------------------------------------------------- + + +class CommandObjectBreakpointSet : public CommandObject +{ +public: + + typedef enum BreakpointSetType + { + eSetTypeInvalid, + eSetTypeFileAndLine, + eSetTypeAddress, + eSetTypeFunctionName, + eSetTypeFunctionRegexp, + } BreakpointSetType; + + CommandObjectBreakpointSet (); + + virtual + ~CommandObjectBreakpointSet (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual Options * + GetOptions (); + + class CommandOptions : public Options + { + public: + + CommandOptions (); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues (); + + const lldb::OptionDefinition* + GetDefinitions (); + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + std::string m_filename; + unsigned int m_line_num; + unsigned int m_column; + bool m_ignore_inlines; + std::string m_func_name; + std::string m_func_regexp; + lldb::addr_t m_load_addr; + STLStringArray m_modules; + + }; + +private: + CommandOptions m_options; +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointEnable +//------------------------------------------------------------------------- + +class CommandObjectBreakpointEnable : public CommandObject +{ +public: + CommandObjectBreakpointEnable (); + + virtual + ~CommandObjectBreakpointEnable (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +private: +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointDisable +//------------------------------------------------------------------------- + +class CommandObjectBreakpointDisable : public CommandObject +{ +public: + CommandObjectBreakpointDisable (); + + virtual + ~CommandObjectBreakpointDisable (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +private: +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointList +//------------------------------------------------------------------------- + +class CommandObjectBreakpointList : public CommandObject +{ +public: + CommandObjectBreakpointList (); + + virtual + ~CommandObjectBreakpointList (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual Options * + GetOptions (); + + class CommandOptions : public Options + { + public: + + CommandOptions (); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues (); + + const lldb::OptionDefinition * + GetDefinitions (); + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + lldb::DescriptionLevel m_level; + + bool m_internal; + }; + +private: + CommandOptions m_options; +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointDelete +//------------------------------------------------------------------------- + +class CommandObjectBreakpointDelete : public CommandObject +{ +public: + CommandObjectBreakpointDelete (); + + virtual + ~CommandObjectBreakpointDelete (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +private: +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectBreakpoint_h_ diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp new file mode 100644 index 00000000000..8a5a443ea8e --- /dev/null +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -0,0 +1,695 @@ +//===-- CommandObjectBreakpointCommand.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes + + +#include "CommandObjectBreakpointCommand.h" +#include "CommandObjectBreakpoint.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Breakpoint/BreakpointIDList.h" +#include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/State.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandAdd::CommandOptions +//------------------------------------------------------------------------- + +CommandObjectBreakpointCommandAdd::CommandOptions::CommandOptions () : + Options () +{ + BuildValidOptionSets(); +} + +CommandObjectBreakpointCommandAdd::CommandOptions::~CommandOptions () +{ +} + +lldb::OptionDefinition +CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] = +{ + { 0, true, "script", 's', no_argument, NULL, 0, NULL, + "Write the breakpoint command script in the default scripting language."}, + + { 1, true, "python", 'p', no_argument, NULL, 0, NULL, + "Write the breakpoint command script in the Python scripting language."}, + + { 2, true, "commands", 'c', no_argument, NULL, 0, NULL, + "Write the breakpoint command script using the command line commands."}, + + { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + +const lldb::OptionDefinition* +CommandObjectBreakpointCommandAdd::CommandOptions::GetDefinitions () +{ + return g_option_table; +} + + +Error +CommandObjectBreakpointCommandAdd::CommandOptions::SetOptionValue +( + int option_idx, + const char *option_arg +) +{ + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 's': + m_use_commands = false; + m_use_script_language = true; + m_script_language = eScriptLanguageDefault; + break; + case 'p': + m_use_commands = false; + m_use_script_language = true; + m_script_language = eScriptLanguagePython; + break; + case 'c': + m_use_commands = true; + m_use_script_language = false; + m_script_language = eScriptLanguageNone; + break; + default: + break; + } + return error; +} + +void +CommandObjectBreakpointCommandAdd::CommandOptions::ResetOptionValues () +{ + Options::ResetOptionValues(); + + m_use_commands = false; + m_use_script_language = false; + m_script_language = eScriptLanguageNone; +} + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandAdd +//------------------------------------------------------------------------- + + +CommandObjectBreakpointCommandAdd::CommandObjectBreakpointCommandAdd () : + CommandObject ("add", + "Adds a set of commands to a breakpoint to be executed whenever a breakpoint is hit.", + "breakpoint command add <cmd-options> <breakpoint-id>") +{ + SetHelpLong ( +"\nGeneral information about entering breakpoint commands \n\ +------------------------------------------------------ \n\ + \n\ +This command will cause you to be prompted to enter the command or set \n\ +of commands you wish to be executed when the specified breakpoint is \n\ +hit. You will be told to enter your command(s), and will see a '> ' \n\ +prompt. Because you can enter one or many commands to be executed when \n\ +a breakpoint is hit, you will continue to be prompted after each \n\ +new-line that you enter, until you enter the word 'DONE', which will \n\ +cause the commands you have entered to be stored with the breakpoint \n\ +and executed when the breakpoint is hit. \n\ + \n\ +Syntax checking is not necessarily done when breakpoint commands are \n\ +entered. An improperly written breakpoint command will attempt to get \n\ +executed when the breakpoint gets hit, and usually silently fail. If \n\ +your breakpoint command does not appear to be getting executed, go \n\ +back and check your syntax. \n\ + \n\ + \n\ +Special information about PYTHON breakpoint commands \n\ +---------------------------------------------------- \n\ + \n\ +You may enter either one line of Python or multiple lines of Python \n\ +(including defining whole functions, if desired). If you enter a \n\ +single line of Python, that will be passed to the Python interpreter \n\ +'as is' when the breakpoint gets hit. If you enter function \n\ +definitions, they will be passed to the Python interpreter as soon as \n\ +you finish entering the breakpoint command, and they can be called \n\ +later (don't forget to add calls to them, if you want them called when \n\ +the breakpoint is hit). If you enter multiple lines of Python that \n\ +are not function definitions, they will be collected into a new, \n\ +automatically generated Python function, and a call to the newly \n\ +generated function will be attached to the breakpoint. Important \n\ +Note: Because loose Python code gets collected into functions, if you \n\ +want to access global variables in the 'loose' code, you need to \n\ +specify that they are global, using the 'global' keyword. Be sure to \n\ +use correct Python syntax, including indentation, when entering Python \n\ +breakpoint commands. \n\ + \n\ +Example Python one-line breakpoint command: \n\ + \n\ +(lldb) breakpoint command add -p 1 \n\ +Enter your Python command(s). Type 'DONE' to end. \n\ +> print \"Hit this breakpoint!\" \n\ +> DONE \n\ + \n\ +Example multiple line Python breakpoint command, using function definition: \n\ + \n\ +(lldb) breakpoint command add -p 1 \n\ +Enter your Python command(s). Type 'DONE' to end. \n\ +> def breakpoint_output (bp_no): \n\ +> out_string = \"Hit breakpoint number \" + repr (bp_no) \n\ +> print out_string \n\ +> return True \n\ +> breakpoint_output (1) \n\ +> DONE \n\ + \n\ + \n\ +Example multiple line Python breakpoint command, using 'loose' Python: \n\ + \n\ +(lldb) breakpoint command add -p 1 \n\ +Enter your Python command(s). Type 'DONE' to end. \n\ +> global bp_count \n\ +> bp_count = bp_count + 1 \n\ +> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\" \n\ +> DONE \n\ + \n\ +In this case, since there is a reference to a global variable, \n\ +'bp_count', you will also need to make sure 'bp_count' exists and is \n\ +initialized: \n\ + \n\ +(lldb) script \n\ +>>> bp_count = 0 \n\ +>>> quit() \n\ + \n\ +(lldb) \n\ + \n\ +Special information debugger command breakpoint commands \n\ +--------------------------------------------------------- \n\ + \n\ +You may enter any debugger command, exactly as you would at the \n\ +debugger prompt. You may enter as many debugger commands as you like, \n\ +but do NOT enter more than one command per line. \n" ); +} + +CommandObjectBreakpointCommandAdd::~CommandObjectBreakpointCommandAdd () +{ +} + +bool +CommandObjectBreakpointCommandAdd::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + Target *target = context->GetTarget(); + + if (target == NULL) + { + result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendError ("No breakpoints exist to have commands added"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() == 0) + { + result.AppendError ("No breakpoint specified to which to add the commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + for (int i = 0; i < valid_bp_ids.Size(); ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) + { + Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) + { + BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); + if (bp_loc_sp) + { + if (m_options.m_use_script_language) + { + interpreter->GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_loc_sp->GetLocationOptions(), + result); + } + else + { + CollectDataForBreakpointCommandCallback (bp_loc_sp->GetLocationOptions(), result); + } + } + } + else + { + if (m_options.m_use_script_language) + { + interpreter->GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp->GetOptions(), + result); + } + else + { + CollectDataForBreakpointCommandCallback (bp->GetOptions(), result); + } + } + } + } + } + + return result.Succeeded(); +} + +Options * +CommandObjectBreakpointCommandAdd::GetOptions () +{ + return &m_options; +} + +const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end."; + +void +CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback +( + BreakpointOptions *bp_options, + CommandReturnObject &result +) +{ + InputReaderSP reader_sp (new InputReader()); + std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); + if (reader_sp && data_ap.get()) + { + BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); + bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp); + + Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback, + bp_options, // baton + eInputReaderGranularityLine, // token size, to pass to callback function + "DONE", // end token + "> ", // prompt + true)); // echo input + if (err.Success()) + { + Debugger::GetSharedInstance().PushInputReader (reader_sp); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError (err.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError("out of memory"); + result.SetStatus (eReturnStatusFailed); + } + +} + +size_t +CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback +( + void *baton, + InputReader *reader, + lldb::InputReaderAction notification, + const char *bytes, + size_t bytes_len +) +{ + FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle(); + + switch (notification) + { + case eInputReaderActivate: + if (out_fh) + { + ::fprintf (out_fh, "%s\n", g_reader_instructions); + if (reader->GetPrompt()) + ::fprintf (out_fh, "%s", reader->GetPrompt()); + } + break; + + case eInputReaderDeactivate: + break; + + case eInputReaderReactivate: + if (out_fh && reader->GetPrompt()) + ::fprintf (out_fh, "%s", reader->GetPrompt()); + break; + + case eInputReaderGotToken: + if (bytes && bytes_len && baton) + { + BreakpointOptions *bp_options = (BreakpointOptions *) baton; + if (bp_options) + { + Baton *bp_options_baton = bp_options->GetBaton(); + if (bp_options_baton) + ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); + } + } + if (out_fh && !reader->IsDone() && reader->GetPrompt()) + ::fprintf (out_fh, "%s", reader->GetPrompt()); + break; + + case eInputReaderDone: + break; + } + + return bytes_len; +} + + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandRemove +//------------------------------------------------------------------------- + +CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove () : + CommandObject ("remove", + "Remove the set of commands from a breakpoint.", + "breakpoint command remove <breakpoint-id>") +{ +} + +CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove () +{ +} + +bool +CommandObjectBreakpointCommandRemove::Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) +{ + Target *target = context->GetTarget(); + + if (target == NULL) + { + result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendError ("No breakpoints exist to have commands removed"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() == 0) + { + result.AppendError ("No breakpoint specified from which to remove the commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + for (int i = 0; i < valid_bp_ids.Size(); ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) + { + Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) + { + BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); + if (bp_loc_sp) + bp_loc_sp->ClearCallback(); + else + { + result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", + cur_bp_id.GetBreakpointID(), + cur_bp_id.GetLocationID()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + bp->ClearCallback(); + } + } + } + } + return result.Succeeded(); +} + + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandList +//------------------------------------------------------------------------- + +CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList () : + CommandObject ("List", + "List the script or set of commands to be executed when the breakpoint is hit.", + "breakpoint command list <breakpoint-id>") +{ +} + +CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList () +{ +} + +bool +CommandObjectBreakpointCommandList::Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) +{ + Target *target = context->GetTarget(); + + if (target == NULL) + { + result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const BreakpointList &breakpoints = target->GetBreakpointList(); + size_t num_breakpoints = breakpoints.GetSize(); + + if (num_breakpoints == 0) + { + result.AppendError ("No breakpoints exist for which to list commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() == 0) + { + result.AppendError ("No breakpoint specified for which to list the commands"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + BreakpointIDList valid_bp_ids; + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); + + if (result.Succeeded()) + { + for (int i = 0; i < valid_bp_ids.Size(); ++i) + { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) + { + Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); + + if (bp) + { + BreakpointOptions *bp_options = NULL; + if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) + { + BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); + if (bp_loc_sp) + bp_options = bp_loc_sp->GetOptionsNoCopy(); + else + { + result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", + cur_bp_id.GetBreakpointID(), + cur_bp_id.GetLocationID()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + bp_options = bp->GetOptions(); + } + + if (bp_options) + { + StreamString id_str; + BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); + Baton *baton = bp_options->GetBaton(); + if (baton) + { + result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); + result.GetOutputStream().IndentMore (); + baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); + result.GetOutputStream().IndentLess (); + } + else + { + result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData()); + } + } + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); + result.SetStatus (eReturnStatusFailed); + } + + } + } + } + + return result.Succeeded(); +} + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommand +//------------------------------------------------------------------------- + +CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter *interpreter) : + CommandObjectMultiword ("command", + "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').", + "command <sub-command> [<sub-command-options>] <breakpoint-id>") +{ + bool status; + CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd ()); + CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove ()); + CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList ()); + + add_command_object->SetCommandName ("breakpoint command add"); + remove_command_object->SetCommandName ("breakpoint command remove"); + list_command_object->SetCommandName ("breakpoint command list"); + + status = LoadSubCommand (add_command_object, "add", interpreter); + status = LoadSubCommand (remove_command_object, "remove", interpreter); + status = LoadSubCommand (list_command_object, "list", interpreter); +} + + +CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () +{ +} + +bool +CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction +( + void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id +) +{ + bool ret_value = true; + if (baton == NULL) + return true; + + + BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton; + StringList &commands = data->user_source; + + if (commands.GetSize() > 0) + { + uint32_t num_commands = commands.GetSize(); + CommandInterpreter &interpreter = Debugger::GetSharedInstance().GetCommandInterpreter(); + CommandReturnObject result; + ExecutionContext exe_ctx = context->context; + + FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle(); + FILE *err_fh = Debugger::GetSharedInstance().GetErrorFileHandle(); + + + uint32_t i; + for (i = 0; i < num_commands; ++i) + { + + // First time through we use the context from the stoppoint, after that we use whatever + // has been set by the previous command. + + if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &exe_ctx)) + break; + + // FIXME: This isn't really the right way to do this. We should be able to peek at the public + // to see if there is any new events, but that is racey, since the internal process thread has to run and + // deliver the event to the public queue before a run will show up. So for now we check + // the internal thread state. + + lldb::StateType internal_state = exe_ctx.process->GetPrivateState(); + if (internal_state != eStateStopped) + { + if (i < num_commands - 1) + { + if (out_fh) + ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s." + " last command: \"%s\"\n", StateAsCString(internal_state), + commands.GetStringAtIndex(i)); + } + break; + } + + // First time through we use the context from the stoppoint, after that we use whatever + // has been set by the previous command. + exe_ctx = Debugger::GetSharedInstance().GetCurrentExecutionContext(); + + + if (out_fh) + ::fprintf (out_fh, "%s", result.GetErrorStream().GetData()); + if (err_fh) + ::fprintf (err_fh, "%s", result.GetOutputStream().GetData()); + result.Clear(); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + + if (err_fh && !result.Succeeded() && i < num_commands) + ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i)); + + if (out_fh) + ::fprintf (out_fh, "%s", result.GetErrorStream().GetData()); + + if (err_fh) + ::fprintf (err_fh, "%s", result.GetOutputStream().GetData()); + } + return ret_value; +} + diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.h b/lldb/source/Commands/CommandObjectBreakpointCommand.h new file mode 100644 index 00000000000..2ba2c6075e8 --- /dev/null +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.h @@ -0,0 +1,169 @@ +//===-- CommandObjectBreakpointCommand.h ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectBreakpointCommand_h_ +#define liblldb_CommandObjectBreakpointCommand_h_ + +// C Includes +// C++ Includes + + +// Other libraries and framework includes +// Project includes + +#include "lldb/lldb-types.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/InputReader.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" + + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectMultiwordBreakpoint +//------------------------------------------------------------------------- + +class CommandObjectBreakpointCommand : public CommandObjectMultiword +{ +public: + CommandObjectBreakpointCommand (CommandInterpreter *interpreter); + + virtual + ~CommandObjectBreakpointCommand (); + + + static bool + BreakpointOptionsCallbackFunction (void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandAdd +//------------------------------------------------------------------------- + + +class CommandObjectBreakpointCommandAdd : public CommandObject +{ +public: + + CommandObjectBreakpointCommandAdd (); + + virtual + ~CommandObjectBreakpointCommandAdd (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual Options * + GetOptions (); + + void + CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, + CommandReturnObject &result); + + static size_t + GenerateBreakpointCommandCallback (void *baton, + InputReader *reader, + lldb::InputReaderAction notification, + const char *bytes, + size_t bytes_len); + + static bool + BreakpointOptionsCallbackFunction (void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + + class CommandOptions : public Options + { + public: + + CommandOptions (); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues (); + + const lldb::OptionDefinition* + GetDefinitions (); + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + bool m_use_commands; + bool m_use_script_language; + lldb::ScriptLanguage m_script_language; + }; + +private: + CommandOptions m_options; +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandRemove +//------------------------------------------------------------------------- + +class CommandObjectBreakpointCommandRemove : public CommandObject +{ +public: + CommandObjectBreakpointCommandRemove (); + + virtual + ~CommandObjectBreakpointCommandRemove (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +private: +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointCommandList +//------------------------------------------------------------------------- + +class CommandObjectBreakpointCommandList : public CommandObject +{ +public: + CommandObjectBreakpointCommandList (); + + virtual + ~CommandObjectBreakpointCommandList (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +private: +}; + + +} // namespace lldb_private + +#endif // liblldb_CommandObjectBreakpointCommand_h_ diff --git a/lldb/source/Commands/CommandObjectCall.cpp b/lldb/source/Commands/CommandObjectCall.cpp new file mode 100644 index 00000000000..58d0a0e9f11 --- /dev/null +++ b/lldb/source/Commands/CommandObjectCall.cpp @@ -0,0 +1,307 @@ +//===-- CommandObjectCall.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectCall.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Value.h" +#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangExpressionVariable.h" +#include "lldb/Expression/ClangFunction.h" +#include "lldb/Host/Host.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/StackFrame.h" + +using namespace lldb; +using namespace lldb_private; + +// This command is a toy. I'm just using it to have a way to construct the arguments to +// calling functions. +// + +CommandObjectCall::CommandOptions::CommandOptions () : + Options() +{ + // Keep only one place to reset the values to their defaults + ResetOptionValues(); +} + + +CommandObjectCall::CommandOptions::~CommandOptions () +{ +} + +Error +CommandObjectCall::CommandOptions::SetOptionValue (int option_idx, const char *option_arg) +{ + Error error; + + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'l': + if (language.SetLanguageFromCString (option_arg) == false) + { + error.SetErrorStringWithFormat("Invalid language option argument '%s'.\n", option_arg); + } + break; + + case 'g': + debug = true; + break; + + case 'f': + error = Args::StringToFormat(option_arg,format); + break; + + case 'n': + noexecute = true; + break; + + case 'a': + use_abi = true; + break; + + default: + error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); + break; + } + + return error; +} + +void +CommandObjectCall::CommandOptions::ResetOptionValues () +{ + Options::ResetOptionValues(); + language.Clear(); + debug = false; + format = eFormatDefault; + show_types = true; + show_summary = true; + noexecute = false; + use_abi = false; +} + +const lldb::OptionDefinition* +CommandObjectCall::CommandOptions::GetDefinitions () +{ + return g_option_table; +} + +CommandObjectCall::CommandObjectCall () : + CommandObject ( + "call", + "Call a function.", + "call <return_type> <function-name> [[<arg1-type> <arg1-value>] ... <argn-type> <argn-value>] [<cmd-options>]", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) +{ +} + +CommandObjectCall::~CommandObjectCall () +{ +} + +Options * +CommandObjectCall::GetOptions () +{ + return &m_options; +} + +bool +CommandObjectCall::Execute +( + Args &command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + ConstString target_triple; + int num_args = command.GetArgumentCount(); + + Target *target = context->GetTarget (); + if (target) + target->GetTargetTriple(target_triple); + + if (!target_triple) + target_triple = Host::GetTargetTriple (); + + ExecutionContext exe_ctx(context->GetExecutionContext()); + if (exe_ctx.thread == NULL || exe_ctx.frame == NULL) + { + result.AppendError ("No currently selected thread and frame."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (num_args < 2) + { + result.AppendErrorWithFormat ("Invalid usage, should be: %s.\n", GetSyntax()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if ((num_args - 2) %2 != 0) + { + result.AppendErrorWithFormat ("Invalid usage - unmatched args & types, should be: %s.\n", GetSyntax()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (target_triple) + { + //const char *return_type = command.GetArgumentAtIndex(0); + const char *function_name = command.GetArgumentAtIndex(1); + // Look up the called function: + + Function *target_fn = exe_ctx.frame->GetSymbolContext(eSymbolContextEverything).FindFunctionByName (function_name); + + // FIXME: If target_fn is NULL, we should look up the name as a symbol and use it and the provided + // return type. + + if (target_fn == NULL) + { + result.AppendErrorWithFormat ("Could not find function '%s'.\n", function_name); + result.SetStatus (eReturnStatusFailed); + return false; + } + + ValueList value_list; + // Okay, now parse arguments. For now we only accept basic types. + for (int i = 2; i < num_args; i+= 2) + { + const char *type_str = command.GetArgumentAtIndex(i); + const char *value_str = command.GetArgumentAtIndex(i + 1); + bool success; + if (strcmp(type_str, "int") == 0 + || strcmp(type_str, "int32_t") == 0) + { + value_list.PushValue(Value(Args::StringToSInt32(value_str, 0, 0, &success))); + } + else if (strcmp (type_str, "int64_t") == 0) + { + value_list.PushValue(Value(Args::StringToSInt64(value_str, 0, 0, &success))); + } + else if (strcmp(type_str, "uint") == 0 + || strcmp(type_str, "uint32_t") == 0) + { + value_list.PushValue(Value(Args::StringToUInt32(value_str, 0, 0, &success))); + } + else if (strcmp (type_str, "uint64_t") == 0) + { + value_list.PushValue(Value(Args::StringToUInt64(value_str, 0, 0, &success))); + } + else if (strcmp (type_str, "cstr") == 0) + { + Value val ((intptr_t)value_str); + val.SetValueType (Value::eValueTypeHostAddress); + + + void *cstr_type = target->GetScratchClangASTContext()->GetCStringType(true); + val.SetContext (Value::eContextTypeOpaqueClangQualType, cstr_type); + value_list.PushValue(val); + + success = true; + } + + if (!success) + { + result.AppendErrorWithFormat ("Could not convert value: '%s' to type '%s'.\n", value_str, type_str); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + // Okay, we have the function and the argument list and the return type. Now make a ClangFunction object and + // run it: + + StreamString errors; + ClangFunction clang_fun (target_triple.GetCString(), *target_fn, target->GetScratchClangASTContext(), value_list); + if (m_options.noexecute) + { + // Now write down the argument values for this call. + lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; + if (!clang_fun.InsertFunction (exe_ctx, args_addr, errors)) + { + result.AppendErrorWithFormat("Error inserting function: '%s'.\n", errors.GetData()); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + result.Succeeded(); + return true; + } + } + + ClangFunction::ExecutionResults return_status; + Value return_value; + + if (m_options.use_abi) + { + return_status = clang_fun.ExecuteFunctionWithABI(exe_ctx, errors, return_value); + } + else + { + bool stop_others = true; + return_status = clang_fun.ExecuteFunction(exe_ctx, errors, stop_others, NULL, return_value); + } + + // Now figure out what to do with the return value. + if (return_status == ClangFunction::eExecutionSetupError) + { + result.AppendErrorWithFormat("Error setting up function execution: '%s'.\n", errors.GetData()); + result.SetStatus (eReturnStatusFailed); + return false; + } + else if (return_status != ClangFunction::eExecutionCompleted) + { + result.AppendWarningWithFormat("Interrupted while calling function: '%s'.\n", errors.GetData()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } + else + { + // Now print out the result. + result.GetOutputStream().Printf("Return value: "); + return_value.Dump(&(result.GetOutputStream())); + result.Succeeded(); + } + + } + else + { + result.AppendError ("invalid target triple"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); +} + +lldb::OptionDefinition +CommandObjectCall::CommandOptions::g_option_table[] = +{ +{ 0, true, "language", 'l', required_argument, NULL, 0, "[c|c++|objc|objc++]", "Sets the language to use when parsing the expression."}, +{ 0, false, "format", 'f', required_argument, NULL, 0, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]", "Specify the format that the expression output should use."}, +{ 0, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable verbose debug logging of the expression parsing and evaluation."}, +{ 0, false, "noexecute", 'n', no_argument, NULL, 0, "no execute", "Only JIT and copy the wrapper & arguments, but don't execute."}, +{ 0, false, "useabi", 'a', no_argument, NULL, 0, NULL, "Use the ABI instead of the JIT to marshall arguments."}, +{ 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL } +}; + diff --git a/lldb/source/Commands/CommandObjectCall.h b/lldb/source/Commands/CommandObjectCall.h new file mode 100644 index 00000000000..c051a142ece --- /dev/null +++ b/lldb/source/Commands/CommandObjectCall.h @@ -0,0 +1,84 @@ +//===-- CommandObjectCall.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectCall_h_ +#define liblldb_CommandObjectCall_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/Language.h" + +namespace lldb_private { + +class CommandObjectCall : public CommandObject +{ +public: + + class CommandOptions : public Options + { + public: + + CommandOptions (); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues (); + + const lldb::OptionDefinition* + GetDefinitions (); + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + Language language; + lldb::Encoding encoding; + lldb::Format format; + bool debug; + bool show_types; + bool show_summary; + bool noexecute; + bool use_abi; + }; + + CommandObjectCall (); + + virtual + ~CommandObjectCall (); + + virtual + Options * + GetOptions (); + + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual bool + WantsRawCommandString() { return false; } + +protected: + + CommandOptions m_options; +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectCall_h_ diff --git a/lldb/source/Commands/CommandObjectDelete.cpp b/lldb/source/Commands/CommandObjectDelete.cpp new file mode 100644 index 00000000000..2fc072e2de4 --- /dev/null +++ b/lldb/source/Commands/CommandObjectDelete.cpp @@ -0,0 +1,32 @@ +//===-- CommandObjectDelete.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectDelete.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectDelete +//------------------------------------------------------------------------- + +CommandObjectDelete::CommandObjectDelete () : +CommandObjectCrossref ("delete", "Lists the kinds of objects you can delete, and shows syntax for deleting them.", "delete") +{ +} + +CommandObjectDelete::~CommandObjectDelete () +{ +} + + diff --git a/lldb/source/Commands/CommandObjectDelete.h b/lldb/source/Commands/CommandObjectDelete.h new file mode 100644 index 00000000000..f7d86b7aef7 --- /dev/null +++ b/lldb/source/Commands/CommandObjectDelete.h @@ -0,0 +1,37 @@ +//===-- CommandObjectDelete.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectDelete_h_ +#define liblldb_CommandObjectDelete_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectCrossref.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectDelete +//------------------------------------------------------------------------- + +class CommandObjectDelete : public CommandObjectCrossref +{ +public: + CommandObjectDelete (); + + virtual + ~CommandObjectDelete (); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectDelete_h_ diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp new file mode 100644 index 00000000000..0985504e4ff --- /dev/null +++ b/lldb/source/Commands/CommandObjectDisassemble.cpp @@ -0,0 +1,431 @@ +//===-- CommandObjectDisassemble.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectDisassemble.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/AddressRange.h" +#include "lldb/Core/Args.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/SourceManager.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#define DEFAULT_DISASM_BYTE_SIZE 32 + +using namespace lldb; +using namespace lldb_private; + +CommandObjectDisassemble::CommandOptions::CommandOptions () : + Options(), + m_func_name(), + m_load_addr() +{ + ResetOptionValues(); +} + +CommandObjectDisassemble::CommandOptions::~CommandOptions () +{ +} + +Error +CommandObjectDisassemble::CommandOptions::SetOptionValue (int option_idx, const char *option_arg) +{ + Error error; + + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'm': + show_mixed = true; + break; + + case 'c': + num_lines_context = Args::StringToUInt32(option_arg, 0, 0); + break; + + case 'b': + show_bytes = true; + break; + + case 'a': + m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 0); + if (m_load_addr == LLDB_INVALID_ADDRESS) + m_load_addr = Args::StringToUInt64(optarg, LLDB_INVALID_ADDRESS, 16); + + if (m_load_addr == LLDB_INVALID_ADDRESS) + error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", optarg); + break; + + case 'n': + m_func_name = option_arg; + break; + + case 'r': + raw = true; + break; + + default: + error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option); + break; + } + + return error; +} + +void +CommandObjectDisassemble::CommandOptions::ResetOptionValues () +{ + Options::ResetOptionValues(); + show_mixed = false; + show_bytes = false; + num_lines_context = 0; + m_func_name.clear(); + m_load_addr = LLDB_INVALID_ADDRESS; +} + +const lldb::OptionDefinition* +CommandObjectDisassemble::CommandOptions::GetDefinitions () +{ + return g_option_table; +} + +lldb::OptionDefinition +CommandObjectDisassemble::CommandOptions::g_option_table[] = +{ +{ 0, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."}, +{ 0, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."}, +{ 0, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."}, +{ 0, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."}, + +{ 1, false, "address", 'a', required_argument, NULL, 0, "<address>", "Address to start disassembling."}, +{ 1, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."}, +{ 1, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."}, +{ 1, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."}, +{ 1, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."}, + +{ 2, false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, "<function-name>", "Disassemble entire contents of the given function name."}, +{ 2, false, "bytes", 'b', no_argument, NULL, 0, NULL, "Show opcode bytes when disassembling."}, +{ 2, false, "context", 'c', required_argument, NULL, 0, "<num-lines>", "Number of context lines of source to show."}, +{ 2, false, "mixed", 'm', no_argument, NULL, 0, NULL, "Enable mixed source and assembly display."}, +{ 2, false, "raw", 'r', no_argument, NULL, 0, NULL, "Print raw disassembly with no symbol information."}, + +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + + +//------------------------------------------------------------------------- +// CommandObjectDisassemble +//------------------------------------------------------------------------- + +CommandObjectDisassemble::CommandObjectDisassemble () : + CommandObject ("disassemble", + "Disassemble bytes in the current function or anywhere in the inferior program.", + "disassemble [[<start-addr> [<end-addr>]] | <function-name>] [<cmd-options>]") +{ +} + +CommandObjectDisassemble::~CommandObjectDisassemble() +{ +} + +void +CommandObjectDisassemble::Disassemble +( + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result, + Disassembler *disassembler, + const SymbolContextList &sc_list +) +{ + const size_t count = sc_list.GetSize(); + SymbolContext sc; + AddressRange range; + for (size_t i=0; i<count; ++i) + { + if (sc_list.GetContextAtIndex(i, sc) == false) + break; + if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, range)) + { + lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(context->GetExecutionContext().process); + if (addr != LLDB_INVALID_ADDRESS) + { + lldb::addr_t end_addr = addr + range.GetByteSize(); + Disassemble (context, interpreter, result, disassembler, addr, end_addr); + } + } + } +} + +void +CommandObjectDisassemble::Disassemble +( + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result, + Disassembler *disassembler, + lldb::addr_t addr, + lldb::addr_t end_addr +) +{ + if (addr == LLDB_INVALID_ADDRESS) + return; + + if (end_addr == LLDB_INVALID_ADDRESS || addr >= end_addr) + end_addr = addr + DEFAULT_DISASM_BYTE_SIZE; + + ExecutionContext exe_ctx (context->GetExecutionContext()); + DataExtractor data; + size_t bytes_disassembled = disassembler->ParseInstructions (&exe_ctx, eAddressTypeLoad, addr, end_addr - addr, data); + if (bytes_disassembled == 0) + { + // Nothing got disassembled... + } + else + { + // We got some things disassembled... + size_t num_instructions = disassembler->GetInstructionList().GetSize(); + uint32_t offset = 0; + Stream &output_stream = result.GetOutputStream(); + SymbolContext sc; + SymbolContext prev_sc; + AddressRange sc_range; + if (m_options.show_mixed) + output_stream.IndentMore (); + + for (size_t i=0; i<num_instructions; ++i) + { + Disassembler::Instruction *inst = disassembler->GetInstructionList().GetInstructionAtIndex (i); + if (inst) + { + lldb::addr_t curr_addr = addr + offset; + if (m_options.show_mixed) + { + Process *process = context->GetExecutionContext().process; + if (!sc_range.ContainsLoadAddress (curr_addr, process)) + { + prev_sc = sc; + Address curr_so_addr; + if (process && process->ResolveLoadAddress (curr_addr, curr_so_addr)) + { + if (curr_so_addr.GetSection()) + { + Module *module = curr_so_addr.GetSection()->GetModule(); + uint32_t resolved_mask = module->ResolveSymbolContextForAddress(curr_so_addr, eSymbolContextEverything, sc); + if (resolved_mask) + { + sc.GetAddressRange (eSymbolContextEverything, sc_range); + if (sc != prev_sc) + { + if (offset != 0) + output_stream.EOL(); + + sc.DumpStopContext(&output_stream, process, curr_so_addr); + output_stream.EOL(); + if (sc.comp_unit && sc.line_entry.IsValid()) + { + interpreter->GetSourceManager().DisplaySourceLinesWithLineNumbers ( + sc.line_entry.file, + sc.line_entry.line, + m_options.num_lines_context, + m_options.num_lines_context, + m_options.num_lines_context ? "->" : "", + &output_stream); + } + } + } + } + } + } + } + if (m_options.show_mixed) + output_stream.IndentMore (); + output_stream.Indent(); + size_t inst_byte_size = inst->GetByteSize(); + inst->Dump(&output_stream, curr_addr, m_options.show_bytes ? &data : NULL, offset, exe_ctx, m_options.raw); + output_stream.EOL(); + offset += inst_byte_size; + if (m_options.show_mixed) + output_stream.IndentLess (); + } + else + { + break; + } + } + if (m_options.show_mixed) + output_stream.IndentLess (); + + } +} + +bool +CommandObjectDisassemble::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + ArchSpec arch(target->GetArchitecture()); + if (!arch.IsValid()) + { + result.AppendError ("target needs valid architecure in order to be able to disassemble"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Disassembler *disassembler = Disassembler::FindPlugin(arch); + + if (disassembler == NULL) + { + result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for %s architecture.\n", arch.AsCString()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + result.SetStatus (eReturnStatusSuccessFinishResult); + + lldb::addr_t addr = LLDB_INVALID_ADDRESS; + lldb::addr_t end_addr = LLDB_INVALID_ADDRESS; + ConstString name; + const size_t argc = command.GetArgumentCount(); + if (argc == 0 && m_options.m_load_addr != LLDB_INVALID_ADDRESS) + { + addr = m_options.m_load_addr; + end_addr = addr + DEFAULT_DISASM_BYTE_SIZE; + } else if (argc == 0 && !m_options.m_func_name.empty()) + { + ConstString tmpname(m_options.m_func_name.c_str()); + name = tmpname; + } else if (argc == 0) + { + ExecutionContext exe_ctx(context->GetExecutionContext()); + if (exe_ctx.frame) + { + SymbolContext sc(exe_ctx.frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); + if (sc.function) + { + addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(exe_ctx.process); + if (addr != LLDB_INVALID_ADDRESS) + end_addr = addr + sc.function->GetAddressRange().GetByteSize(); + } + else if (sc.symbol && sc.symbol->GetAddressRangePtr()) + { + addr = sc.symbol->GetAddressRangePtr()->GetBaseAddress().GetLoadAddress(exe_ctx.process); + if (addr != LLDB_INVALID_ADDRESS) + { + end_addr = addr + sc.symbol->GetAddressRangePtr()->GetByteSize(); + if (addr == end_addr) + end_addr += DEFAULT_DISASM_BYTE_SIZE; + } + } + else + { + addr = exe_ctx.frame->GetPC().GetLoadAddress(exe_ctx.process); + if (addr != LLDB_INVALID_ADDRESS) + end_addr = addr + DEFAULT_DISASM_BYTE_SIZE; + } + } + else + { + result.AppendError ("invalid frame"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else if (argc == 1) + { + const char *arg = command.GetArgumentAtIndex(0); + addr = Args::StringToAddress (arg); + if (addr == LLDB_INVALID_ADDRESS) + { + // Lookup function or symbol name? + ConstString tmpname(arg); + name = tmpname; + } + else + { + end_addr = addr + DEFAULT_DISASM_BYTE_SIZE; + } + } + else if (argc >= 1 && argc <= 2) + { + addr = Args::StringToAddress (command.GetArgumentAtIndex(0)); + if (addr == LLDB_INVALID_ADDRESS) + { + result.AppendErrorWithFormat ("Unable to parse address '%s'.\n", command.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + end_addr = Args::StringToAddress (command.GetArgumentAtIndex(1), addr); + if (end_addr == LLDB_INVALID_ADDRESS) + { + result.AppendErrorWithFormat ("Unable to parse address '%s'.\n", command.GetArgumentAtIndex(1)); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + + if (!name.IsEmpty()) + { + SymbolContextList sc_list; + + if (target->GetImages().FindFunctions(name, sc_list)) + { + Disassemble (context, interpreter, result, disassembler, sc_list); + } + else if (target->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeCode, sc_list)) + { + Disassemble (context, interpreter, result, disassembler, sc_list); + } + else + { + result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + + if (addr < end_addr) + { + Disassemble (context, interpreter, result, disassembler, addr, end_addr); + } + + if (addr == LLDB_INVALID_ADDRESS && name.IsEmpty()) + { + result.AppendError ("No recognizable address of function name provided"); + result.SetStatus (eReturnStatusFailed); + return false; + } + { + return result.Succeeded(); + } +} diff --git a/lldb/source/Commands/CommandObjectDisassemble.h b/lldb/source/Commands/CommandObjectDisassemble.h new file mode 100644 index 00000000000..2cf800d2f59 --- /dev/null +++ b/lldb/source/Commands/CommandObjectDisassemble.h @@ -0,0 +1,95 @@ +//===-- CommandObjectDisassemble.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectDisassemble_h_ +#define liblldb_CommandObjectDisassemble_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Core/Options.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectDisassemble +//------------------------------------------------------------------------- + +class CommandObjectDisassemble : public CommandObject +{ +public: + class CommandOptions : public Options + { + public: + + CommandOptions (); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues (); + + const lldb::OptionDefinition* + GetDefinitions (); + + bool show_mixed; // Show mixed source/assembly + bool show_bytes; + uint32_t num_lines_context; + bool raw; + std::string m_func_name; + lldb::addr_t m_load_addr; + static lldb::OptionDefinition g_option_table[]; + }; + + CommandObjectDisassemble (); + + virtual + ~CommandObjectDisassemble (); + + virtual + Options * + GetOptions () + { + return &m_options; + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +protected: + CommandOptions m_options; + + void + Disassemble (CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result, + Disassembler *disassembler, + lldb::addr_t addr, + lldb::addr_t end_addr); + + void + Disassemble (CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result, + Disassembler *disassembler, + const SymbolContextList &sc_list); +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectDisassemble_h_ diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp new file mode 100644 index 00000000000..9afc8c0a1a3 --- /dev/null +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -0,0 +1,554 @@ +//===-- CommandObjectExpression.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectExpression.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/InputReader.h" +#include "lldb/Expression/ClangExpression.h" +#include "lldb/Expression/ClangExpressionDeclMap.h" +#include "lldb/Expression/ClangExpressionVariable.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Host/Host.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +CommandObjectExpression::CommandOptions::CommandOptions () : + Options() +{ + // Keep only one place to reset the values to their defaults + ResetOptionValues(); +} + + +CommandObjectExpression::CommandOptions::~CommandOptions () +{ +} + +Error +CommandObjectExpression::CommandOptions::SetOptionValue (int option_idx, const char *option_arg) +{ + Error error; + + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'l': + if (language.SetLanguageFromCString (option_arg) == false) + { + error.SetErrorStringWithFormat("Invalid language option argument '%s'.\n", option_arg); + } + break; + + case 'g': + debug = true; + break; + + case 'f': + error = Args::StringToFormat(option_arg, format); + break; + + default: + error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); + break; + } + + return error; +} + +void +CommandObjectExpression::CommandOptions::ResetOptionValues () +{ + Options::ResetOptionValues(); + language.Clear(); + debug = false; + format = eFormatDefault; + show_types = true; + show_summary = true; +} + +const lldb::OptionDefinition* +CommandObjectExpression::CommandOptions::GetDefinitions () +{ + return g_option_table; +} + +CommandObjectExpression::CommandObjectExpression () : + CommandObject ( + "expression", + "Evaluate a C expression in the current program context, using variables currently in scope.", + "expression [<cmd-options>] <expr>"), + m_expr_line_count (0), + m_expr_lines () +{ + SetHelpLong( +"Examples: \n\ +\n\ + expr my_struct->a = my_array[3] \n\ + expr -f bin -- (index * 8) + 5 \n\ + expr char c[] = \"foo\"; c[0]\n"); +} + +CommandObjectExpression::~CommandObjectExpression () +{ +} + +Options * +CommandObjectExpression::GetOptions () +{ + return &m_options; +} + + +bool +CommandObjectExpression::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + return false; +} + + +size_t +CommandObjectExpression::MultiLineExpressionCallback +( + void *baton, + InputReader *reader, + lldb::InputReaderAction notification, + const char *bytes, + size_t bytes_len +) +{ + FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle(); + CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton; + + switch (notification) + { + case eInputReaderActivate: + if (out_fh) + ::fprintf (out_fh, "%s\n", "Enter expressions, then terminate with an empty line to evaluate:"); + // Fall through + case eInputReaderReactivate: + //if (out_fh) + // ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count); + break; + + case eInputReaderDeactivate: + break; + + case eInputReaderGotToken: + ++cmd_object_expr->m_expr_line_count; + if (bytes && bytes_len) + { + cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1); + } + + if (bytes_len == 0) + reader->SetIsDone(true); + //else if (out_fh && !reader->IsDone()) + // ::fprintf (out_fh, "%3u: ", cmd_object_expr->m_expr_line_count); + break; + + case eInputReaderDone: + { + StreamFile out_stream(Debugger::GetSharedInstance().GetOutputFileHandle()); + StreamFile err_stream(Debugger::GetSharedInstance().GetErrorFileHandle()); + bool bare = false; + cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(), + bare, + out_stream, + err_stream); + } + break; + } + + return bytes_len; +} + +bool +CommandObjectExpression::EvaluateExpression (const char *expr, bool bare, Stream &output_stream, Stream &error_stream) +{ + bool success = false; + ConstString target_triple; + Target *target = m_exe_ctx.target; + if (target) + target->GetTargetTriple(target_triple); + + if (!target_triple) + target_triple = Host::GetTargetTriple (); + + + if (target_triple) + { + const bool show_types = m_options.show_types; + const bool show_summary = m_options.show_summary; + const bool debug = m_options.debug; + + ClangExpressionDeclMap expr_decl_map(&m_exe_ctx); + ClangExpression clang_expr(target_triple.AsCString(), &expr_decl_map); + + unsigned num_errors = 0; + + if (bare) + num_errors = clang_expr.ParseBareExpression (llvm::StringRef(expr), error_stream); + else + num_errors = clang_expr.ParseExpression (expr, error_stream); + + if (num_errors == 0) + { + StreamString dwarf_opcodes; + dwarf_opcodes.SetByteOrder(eByteOrderHost); + dwarf_opcodes.GetFlags().Set(Stream::eBinary); + ClangExpressionVariableList expr_local_vars; + clang_expr.ConvertExpressionToDWARF (expr_local_vars, dwarf_opcodes); + + success = true; + + DataExtractor dwarf_opcodes_data(dwarf_opcodes.GetData(), dwarf_opcodes.GetSize(), eByteOrderHost, 8); + DWARFExpression expr(dwarf_opcodes_data, 0, dwarf_opcodes_data.GetByteSize(), NULL); + expr.SetExpressionLocalVariableList(&expr_local_vars); + if (debug) + { + output_stream << "Expression parsed ok, dwarf opcodes:"; + output_stream.IndentMore(); + expr.GetDescription(&output_stream, lldb::eDescriptionLevelVerbose); + output_stream.IndentLess(); + output_stream.EOL(); + } + + clang::ASTContext *ast_context = clang_expr.GetASTContext(); + Value expr_result; + Error expr_error; + bool expr_success = expr.Evaluate (&m_exe_ctx, ast_context, NULL, expr_result, &expr_error); + if (expr_success) + { + lldb::Format format = m_options.format; + + // Resolve any values that are possible + expr_result.ResolveValue(&m_exe_ctx, ast_context); + + if (expr_result.GetContextType() == Value::eContextTypeInvalid && + expr_result.GetValueType() == Value::eValueTypeScalar && + format == eFormatDefault) + { + // The expression result is just a scalar with no special formatting + expr_result.GetScalar().GetValue (&output_stream, show_types); + output_stream.EOL(); + } + else + { + DataExtractor data; + expr_error = expr_result.GetValueAsData (&m_exe_ctx, ast_context, data, 0); + if (expr_error.Success()) + { + if (format == eFormatDefault) + format = expr_result.GetValueDefaultFormat (); + + void *clang_type = expr_result.GetValueOpaqueClangQualType(); + if (clang_type) + { + if (show_types) + Type::DumpClangTypeName(&output_stream, clang_type); + + Type::DumpValue ( + &m_exe_ctx, // The execution context for memory and variable access + ast_context, // The ASTContext that the clang type belongs to + clang_type, // The opaque clang type we want to dump that value of + &output_stream, // Stream to dump to + format, // Format to use when dumping + data, // A buffer containing the bytes for the clang type + 0, // Byte offset within "data" where value is + data.GetByteSize(), // Size in bytes of the value we are dumping + 0, // Bitfield bit size + 0, // Bitfield bit offset + show_types, // Show types? + show_summary, // Show summary? + debug, // Debug logging output? + UINT32_MAX); // Depth to dump in case this is an aggregate type + } + else + { + data.Dump(&output_stream, // Stream to dump to + 0, // Byte offset within "data" + format, // Format to use when dumping + data.GetByteSize(), // Size in bytes of each item we are dumping + 1, // Number of items to dump + UINT32_MAX, // Number of items per line + LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context + 0, // Bitfield bit size + 0); // Bitfield bit offset + } + output_stream.EOL(); + } + else + { + error_stream.Printf ("error: %s\n", expr_error.AsCString()); + success = false; + } + } + } + else + { + error_stream.Printf ("error: %s\n", expr_error.AsCString()); + } + } + } + else + { + error_stream.PutCString ("error: invalid target triple\n"); + } + + return success; +} + +bool +CommandObjectExpression::ExecuteRawCommandString +( + const char *command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + ConstString target_triple; + Target *target = context->GetTarget (); + if (target) + target->GetTargetTriple(target_triple); + + if (!target_triple) + target_triple = Host::GetTargetTriple (); + + ExecutionContext exe_ctx(context->GetExecutionContext()); + + Stream &output_stream = result.GetOutputStream(); + + m_options.ResetOptionValues(); + + const char * expr = NULL; + + if (command[0] == '\0') + { + m_expr_lines.clear(); + m_expr_line_count = 0; + + InputReaderSP reader_sp (new InputReader()); + if (reader_sp) + { + Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback, + this, // baton + eInputReaderGranularityLine, // token size, to pass to callback function + NULL, // end token + NULL, // prompt + true)); // echo input + if (err.Success()) + { + Debugger::GetSharedInstance().PushInputReader (reader_sp); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError (err.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError("out of memory"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } + + if (command[0] == '-') + { + // We have some options and these options MUST end with --. + const char *end_options = NULL; + const char *s = command; + while (s && s[0]) + { + end_options = ::strstr (s, "--"); + if (end_options) + { + end_options += 2; // Get past the "--" + if (::isspace (end_options[0])) + { + expr = end_options; + while (::isspace (*expr)) + ++expr; + break; + } + } + s = end_options; + } + + if (end_options) + { + Args args(command, end_options - command); + if (!ParseOptions(args, interpreter, result)) + return false; + } + } + + const bool show_types = m_options.show_types; + const bool show_summary = m_options.show_summary; + const bool debug = m_options.debug; + + + if (expr == NULL) + expr = command; + + if (target_triple) + { + ClangExpressionDeclMap expr_decl_map(&exe_ctx); + + ClangExpression clang_expr(target_triple.AsCString(), &expr_decl_map); + + unsigned num_errors = clang_expr.ParseExpression (expr, result.GetErrorStream()); + + if (num_errors == 0) + { + StreamString dwarf_opcodes; + dwarf_opcodes.SetByteOrder(eByteOrderHost); + dwarf_opcodes.GetFlags().Set(Stream::eBinary); + ClangExpressionVariableList expr_local_vars; + clang_expr.ConvertExpressionToDWARF (expr_local_vars, dwarf_opcodes); + + result.SetStatus (eReturnStatusSuccessFinishResult); + + DataExtractor dwarf_opcodes_data(dwarf_opcodes.GetData(), dwarf_opcodes.GetSize(), eByteOrderHost, 8); + DWARFExpression expr(dwarf_opcodes_data, 0, dwarf_opcodes_data.GetByteSize(), NULL); + expr.SetExpressionLocalVariableList(&expr_local_vars); + expr.SetExpressionDeclMap(&expr_decl_map); + if (debug) + { + output_stream << "Expression parsed ok, dwarf opcodes:"; + output_stream.IndentMore(); + expr.GetDescription(&output_stream, lldb::eDescriptionLevelVerbose); + output_stream.IndentLess(); + output_stream.EOL(); + } + + clang::ASTContext *ast_context = clang_expr.GetASTContext(); + Value expr_result; + Error expr_error; + bool expr_success = expr.Evaluate (&exe_ctx, ast_context, NULL, expr_result, &expr_error); + if (expr_success) + { + lldb::Format format = m_options.format; + + // Resolve any values that are possible + expr_result.ResolveValue(&exe_ctx, ast_context); + + if (expr_result.GetContextType() == Value::eContextTypeInvalid && + expr_result.GetValueType() == Value::eValueTypeScalar && + format == eFormatDefault) + { + // The expression result is just a scalar with no special formatting + expr_result.GetScalar().GetValue (&output_stream, show_types); + output_stream.EOL(); + } + else + { + DataExtractor data; + expr_error = expr_result.GetValueAsData (&exe_ctx, ast_context, data, 0); + if (expr_error.Success()) + { + if (format == eFormatDefault) + format = expr_result.GetValueDefaultFormat (); + + void *clang_type = expr_result.GetValueOpaqueClangQualType(); + if (clang_type) + { + if (show_types) + Type::DumpClangTypeName(&output_stream, clang_type); + + Type::DumpValue ( + &exe_ctx, // The execution context for memory and variable access + ast_context, // The ASTContext that the clang type belongs to + clang_type, // The opaque clang type we want to dump that value of + &output_stream, // Stream to dump to + format, // Format to use when dumping + data, // A buffer containing the bytes for the clang type + 0, // Byte offset within "data" where value is + data.GetByteSize(), // Size in bytes of the value we are dumping + 0, // Bitfield bit size + 0, // Bitfield bit offset + show_types, // Show types? + show_summary, // Show summary? + debug, // Debug logging output? + UINT32_MAX); // Depth to dump in case this is an aggregate type + } + else + { + data.Dump(&output_stream, // Stream to dump to + 0, // Byte offset within "data" + format, // Format to use when dumping + data.GetByteSize(), // Size in bytes of each item we are dumping + 1, // Number of items to dump + UINT32_MAX, // Number of items per line + LLDB_INVALID_ADDRESS, // Invalid address, don't show any offset/address context + 0, // Bitfield bit size + 0); // Bitfield bit offset + } + output_stream.EOL(); + } + else + { + result.AppendError(expr_error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + } + else + { + result.AppendError (expr_error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("invalid target triple"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); +} + +lldb::OptionDefinition +CommandObjectExpression::CommandOptions::g_option_table[] = +{ +{ 0, true, "language", 'l', required_argument, NULL, 0, "[c|c++|objc|objc++]", "Sets the language to use when parsing the expression."}, +{ 0, false, "format", 'f', required_argument, NULL, 0, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]", "Specify the format that the expression output should use."}, +{ 0, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable verbose debug logging of the expression parsing and evaluation."}, +{ 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL } +}; + diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h new file mode 100644 index 00000000000..c67ba745af2 --- /dev/null +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -0,0 +1,105 @@ +//===-- CommandObjectExpression.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectExpression_h_ +#define liblldb_CommandObjectExpression_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/Language.h" +#include "lldb/Target/ExecutionContext.h" + +namespace lldb_private { + +class CommandObjectExpression : public CommandObject +{ +public: + + class CommandOptions : public Options + { + public: + + CommandOptions (); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues (); + + const lldb::OptionDefinition* + GetDefinitions (); + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + Language language; + lldb::Encoding encoding; + lldb::Format format; + bool debug; + bool show_types; + bool show_summary; + }; + + CommandObjectExpression (); + + virtual + ~CommandObjectExpression (); + + virtual + Options * + GetOptions (); + + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual bool + WantsRawCommandString() { return true; } + + virtual bool + ExecuteRawCommandString (const char *command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +protected: + + static size_t + MultiLineExpressionCallback (void *baton, + InputReader *reader, + lldb::InputReaderAction notification, + const char *bytes, + size_t bytes_len); + + bool + EvaluateExpression (const char *expr, + bool bare, + Stream &output_stream, + Stream &error_stream); + + CommandOptions m_options; + ExecutionContext m_exe_ctx; + uint32_t m_expr_line_count; + std::string m_expr_lines; // Multi-line expression support +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectExpression_h_ diff --git a/lldb/source/Commands/CommandObjectFile.cpp b/lldb/source/Commands/CommandObjectFile.cpp new file mode 100644 index 00000000000..01576c5b6d5 --- /dev/null +++ b/lldb/source/Commands/CommandObjectFile.cpp @@ -0,0 +1,170 @@ +//===-- CommandObjectFile.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectFile.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Timer.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; + +CommandObjectFile::CommandOptions::CommandOptions() : + Options (), + m_arch () // Breakpoint info defaults to brief descriptions +{ + BuildValidOptionSets(); +} + +CommandObjectFile::CommandOptions::~CommandOptions () +{ +} + +lldb::OptionDefinition +CommandObjectFile::CommandOptions::g_option_table[] = +{ + { 0, false, "arch", 'a', required_argument, NULL, 0, "<arch>", "Specify the architecture to launch."}, + { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + +const lldb::OptionDefinition * +CommandObjectFile::CommandOptions::GetDefinitions () +{ + return g_option_table; +} + +Error +CommandObjectFile::CommandOptions::SetOptionValue (int option_idx, const char *option_arg) +{ + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'a': + { + ArchSpec option_arch (option_arg); + if (option_arch.IsValid()) + m_arch = option_arch; + else + error.SetErrorStringWithFormat ("Invalid arch string '%s'.\n", optarg); + } + break; + + default: + error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option); + break; + } + + return error; +} + +void +CommandObjectFile::CommandOptions::ResetOptionValues () +{ + Options::ResetOptionValues(); + m_arch.Clear(); +} + +//------------------------------------------------------------------------- +// CommandObjectFile +//------------------------------------------------------------------------- + +CommandObjectFile::CommandObjectFile() : + CommandObject ("file", + "Sets the file to be used as the main executable by the debugger.", + "file [<cmd-options>] <filename>") +{ +} + +CommandObjectFile::~CommandObjectFile () +{ +} + +Options * +CommandObjectFile::GetOptions () +{ + return &m_options; +} + +bool +CommandObjectFile::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + const char *file_path = command.GetArgumentAtIndex(0); + Timer scoped_timer(__PRETTY_FUNCTION__, "(dbg) file '%s'", file_path); + const int argc = command.GetArgumentCount(); + if (argc == 1) + { + FileSpec file_spec (file_path); + + if (! file_spec.Exists()) + { + result.AppendErrorWithFormat ("File '%s' does not exist.\n", file_path); + result.SetStatus (eReturnStatusFailed); + return result.Succeeded(); + } + + TargetSP target_sp; + + ArchSpec arch; + if (m_options.m_arch.IsValid()) + arch = m_options.m_arch; + else + { + arch = lldb_private::GetDefaultArchitecture (); + if (!arch.IsValid()) + arch = LLDB_ARCH_DEFAULT; + } + + Error error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file_spec, arch, NULL, true, target_sp); + + if (error.Fail() && !m_options.m_arch.IsValid()) + { + if (arch == LLDB_ARCH_DEFAULT_32BIT) + arch = LLDB_ARCH_DEFAULT_64BIT; + else + arch = LLDB_ARCH_DEFAULT_32BIT; + error = Debugger::GetSharedInstance().GetTargetList().CreateTarget (file_spec, arch, NULL, true, target_sp); + } + + if (target_sp) + { + Debugger::GetSharedInstance().GetTargetList().SetCurrentTarget(target_sp.get()); + result.AppendMessageWithFormat ("Current executable set to '%s' (%s).\n", file_path, arch.AsCString()); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError(error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat("'%s' takes exactly one executable path argument.\n", m_cmd_name.c_str()); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + +} diff --git a/lldb/source/Commands/CommandObjectFile.h b/lldb/source/Commands/CommandObjectFile.h new file mode 100644 index 00000000000..c44f610d970 --- /dev/null +++ b/lldb/source/Commands/CommandObjectFile.h @@ -0,0 +1,79 @@ +//===-- CommandObjectFile.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectFile_h_ +#define liblldb_CommandObjectFile_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Options.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectFile +//------------------------------------------------------------------------- + +class CommandObjectFile : public CommandObject +{ +public: + + CommandObjectFile (); + + virtual + ~CommandObjectFile (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual Options * + GetOptions (); + + class CommandOptions : public Options + { + public: + + CommandOptions (); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues (); + + const lldb::OptionDefinition* + GetDefinitions (); + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + ArchSpec m_arch; + }; + +private: + CommandOptions m_options; + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectFile_h_ diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp new file mode 100644 index 00000000000..78682dc0ca3 --- /dev/null +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -0,0 +1,171 @@ +//===-- CommandObjectFrame.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectFrame.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Timer.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" + +#include "CommandObjectThread.h" + +using namespace lldb; +using namespace lldb_private; + +#pragma mark CommandObjectFrameInfo + +//------------------------------------------------------------------------- +// CommandObjectFrameInfo +//------------------------------------------------------------------------- + +class CommandObjectFrameInfo : public CommandObject +{ +public: + + CommandObjectFrameInfo () : + CommandObject ("frame info", + "Lists information about the currently selected frame in the current thread.", + "frame info", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) + { + } + + ~CommandObjectFrameInfo () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + ExecutionContext exe_ctx(context->GetExecutionContext()); + if (exe_ctx.frame) + { + exe_ctx.frame->Dump (&result.GetOutputStream(), true); + result.GetOutputStream().EOL(); + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendError ("no current frame"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + +#pragma mark CommandObjectFrameSelect + +//------------------------------------------------------------------------- +// CommandObjectFrameSelect +//------------------------------------------------------------------------- + +class CommandObjectFrameSelect : public CommandObject +{ +public: + + CommandObjectFrameSelect () : + CommandObject ("frame select", + "Select the current frame by index in the current thread.", + "frame select <frame-index>", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) + { + } + + ~CommandObjectFrameSelect () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + ExecutionContext exe_ctx (context->GetExecutionContext()); + if (exe_ctx.thread) + { + if (command.GetArgumentCount() == 1) + { + const char *frame_idx_cstr = command.GetArgumentAtIndex(0); + + const uint32_t num_frames = exe_ctx.thread->GetStackFrameCount(); + const uint32_t frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0); + if (frame_idx < num_frames) + { + exe_ctx.thread->SetCurrentFrameByIndex (frame_idx); + exe_ctx.frame = exe_ctx.thread->GetCurrentFrame ().get(); + + if (exe_ctx.frame) + { + if (DisplayFrameForExecutionContext (exe_ctx.thread, + exe_ctx.frame, + interpreter, + result.GetOutputStream(), + true, + true, + 3, + 3)) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } + } + } + if (frame_idx == UINT32_MAX) + result.AppendErrorWithFormat ("Invalid frame index: %s.\n", frame_idx_cstr); + else + result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx); + } + else + { + result.AppendError ("invalid arguments"); + result.AppendErrorWithFormat ("Usage: %s\n", m_cmd_syntax.c_str()); + } + } + else + { + result.AppendError ("no current thread"); + } + result.SetStatus (eReturnStatusFailed); + return false; + } +}; + +#pragma mark CommandObjectMultiwordFrame + +//------------------------------------------------------------------------- +// CommandObjectMultiwordFrame +//------------------------------------------------------------------------- + +CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter *interpreter) : + CommandObjectMultiword ("frame", + "A set of commands for operating on the current thread's frames.", + "frame <subcommand> [<subcommand-options>]") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectFrameInfo ()), "info", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectFrameSelect ()), "select", interpreter); +} + +CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame () +{ +} + diff --git a/lldb/source/Commands/CommandObjectFrame.h b/lldb/source/Commands/CommandObjectFrame.h new file mode 100644 index 00000000000..cb9cafe3a74 --- /dev/null +++ b/lldb/source/Commands/CommandObjectFrame.h @@ -0,0 +1,40 @@ +//===-- CommandObjectFrame.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectFrame_h_ +#define liblldb_CommandObjectFrame_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Options.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectMultiwordFrame +//------------------------------------------------------------------------- + +class CommandObjectMultiwordFrame : public CommandObjectMultiword +{ +public: + + CommandObjectMultiwordFrame (CommandInterpreter *interpreter); + + virtual + ~CommandObjectMultiwordFrame (); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectFrame_h_ diff --git a/lldb/source/Commands/CommandObjectHelp.cpp b/lldb/source/Commands/CommandObjectHelp.cpp new file mode 100644 index 00000000000..35e5b2ee5c4 --- /dev/null +++ b/lldb/source/Commands/CommandObjectHelp.cpp @@ -0,0 +1,266 @@ +//===-- CommandObjectHelp.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectHelp.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Core/Options.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectHelp +//------------------------------------------------------------------------- + +CommandObjectHelp::CommandObjectHelp () : + CommandObject ("help", + "Shows a list of all debugger commands, or give details about specific commands.", + "help [<cmd-name>]") +{ +} + +CommandObjectHelp::~CommandObjectHelp() +{ +} + + +bool +CommandObjectHelp::OldExecute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + CommandObject::CommandMap::iterator pos; + CommandObject *cmd_obj; + + const int argc = command.GetArgumentCount(); + if (argc > 0) + { + cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex(0), false, false); + if (cmd_obj == NULL) + { + cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex(0), true, false); + if (cmd_obj != NULL) + { + StreamString alias_help_str; + interpreter->GetAliasHelp (command.GetArgumentAtIndex(0), cmd_obj->GetCommandName(), alias_help_str); + result.AppendMessageWithFormat ("'%s' is an alias for %s.\n", command.GetArgumentAtIndex (0), + alias_help_str.GetData()); + } + } + + if (cmd_obj) + { + Stream &output_strm = result.GetOutputStream(); + if (cmd_obj->GetOptions() != NULL) + { + const char * long_help = cmd_obj->GetHelpLong(); + if ((long_help!= NULL) + && strlen (long_help) > 0) + output_strm.Printf ("\n%s", cmd_obj->GetHelpLong()); + else + output_strm.Printf ("\n%s\n", cmd_obj->GetHelp()); + output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax()); + cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, cmd_obj); + } + else if (cmd_obj->IsMultiwordObject()) + { + bool done = false; + if (argc > 1) + { + CommandObject::CommandMap::iterator pos; + std::string sub_command = command.GetArgumentAtIndex(1); + pos = ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.find(sub_command); + if (pos != ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.end()) + { + CommandObject *sub_cmd_obj = pos->second.get(); + if (sub_cmd_obj->GetOptions() != NULL) + { + output_strm.Printf ("\n%s\n", sub_cmd_obj->GetHelp()); + output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax()); + sub_cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, sub_cmd_obj); + done = true; + } + else + { + output_strm.Printf ("\n%s\n", sub_cmd_obj->GetHelp()); + output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax()); + done = true; + } + } + } + if (!done) + { + output_strm.Printf ("%s\n", cmd_obj->GetHelp()); + ((CommandObjectMultiword *) cmd_obj)->GenerateHelpText (result, interpreter); + } + } + else + { + const char *long_help = cmd_obj->GetHelpLong(); + if ((long_help != NULL) + && (strlen (long_help) > 0)) + output_strm.Printf ("\n%s", cmd_obj->GetHelpLong()); + else + output_strm.Printf ("\n%s\n", cmd_obj->GetHelp()); + output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax()); + } + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendErrorWithFormat + ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n", + command.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + interpreter->GetHelp(result); + } + return result.Succeeded(); +} + +bool +CommandObjectHelp::Execute (Args &command, CommandContext *context, CommandInterpreter *interpreter, + CommandReturnObject &result) +{ + CommandObject::CommandMap::iterator pos; + CommandObject *cmd_obj; + const int argc = command.GetArgumentCount (); + + // 'help' doesn't take any options or arguments, other than command names. If argc is 0, we show the user + // all commands and aliases. Otherwise every argument must be the name of a command or a sub-command. + + if (argc == 0) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + interpreter->GetHelp (result); // General help, for ALL commands. + } + else + { + // Get command object for the first command argument. Only search built-in command dictionary. + cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex (0), false, false); + if (cmd_obj == NULL) + { + // That failed, so now search in the aliases dictionary, too. + cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex (0), true, false); + } + + if (cmd_obj != NULL) + { + bool all_okay = true; + CommandObject *sub_cmd_obj = cmd_obj; + // Loop down through sub_command dictionaries until we find the command object that corresponds + // to the help command entered. + for (int i = 1; i < argc && all_okay; ++i) + { + std::string sub_command = command.GetArgumentAtIndex(i); + if (! sub_cmd_obj->IsMultiwordObject ()) + { + all_okay = false; + } + else + { + pos = ((CommandObjectMultiword *) sub_cmd_obj)->m_subcommand_dict.find (sub_command); + if (pos != ((CommandObjectMultiword *) sub_cmd_obj)->m_subcommand_dict.end()) + sub_cmd_obj = pos->second.get(); + else + all_okay = false; + } + } + + if (!all_okay || (sub_cmd_obj == NULL)) + { + std::string cmd_string; + command.GetCommandString (cmd_string); + result.AppendErrorWithFormat + ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n", + cmd_string.c_str()); + result.SetStatus (eReturnStatusFailed); + } + else + { + Stream &output_strm = result.GetOutputStream(); + if (sub_cmd_obj->GetOptions() != NULL) + { + output_strm.Printf ("%s\n", sub_cmd_obj->GetHelp()); + output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax()); + sub_cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, sub_cmd_obj); + const char *long_help = sub_cmd_obj->GetHelpLong(); + if ((long_help != NULL) + && (strlen (long_help) > 0)) + output_strm.Printf ("\n%s", long_help); + } + else if (sub_cmd_obj->IsMultiwordObject()) + { + output_strm.Printf ("%s\n", sub_cmd_obj->GetHelp()); + ((CommandObjectMultiword *) sub_cmd_obj)->GenerateHelpText (result, interpreter); + } + else + { + const char *long_help = sub_cmd_obj->GetHelpLong(); + if ((long_help != NULL) + && (strlen (long_help) > 0)) + output_strm.Printf ("%s", long_help); + else + output_strm.Printf ("%s\n", sub_cmd_obj->GetHelp()); + output_strm.Printf ("\nSyntax: %s\n", sub_cmd_obj->GetSyntax()); + } + } + } + else + { + result.AppendErrorWithFormat + ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n", + command.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + } + } + + return result.Succeeded(); +} + +int +CommandObjectHelp::HandleCompletion +( + Args &input, + int &cursor_index, + int &cursor_char_position, + int match_start_point, + int max_return_elements, + CommandInterpreter *interpreter, + StringList &matches +) +{ + // Return the completions of the commands in the help system: + if (cursor_index == 0) + { + return interpreter->HandleCompletionMatches(input, cursor_index, cursor_char_position, match_start_point, max_return_elements, matches); + } + else + { + CommandObject *cmd_obj = interpreter->GetCommandObject (input.GetArgumentAtIndex(0), true, false); + input.Shift(); + cursor_index--; + return cmd_obj->HandleCompletion (input, cursor_index, cursor_char_position, match_start_point, max_return_elements, interpreter, matches); + } +} diff --git a/lldb/source/Commands/CommandObjectHelp.h b/lldb/source/Commands/CommandObjectHelp.h new file mode 100644 index 00000000000..a8084aa704d --- /dev/null +++ b/lldb/source/Commands/CommandObjectHelp.h @@ -0,0 +1,59 @@ +//===-- CommandObjectHelp.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectHelp_h_ +#define liblldb_CommandObjectHelp_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectHelp +//------------------------------------------------------------------------- + +class CommandObjectHelp : public CommandObject +{ +public: + + CommandObjectHelp (); + + virtual + ~CommandObjectHelp (); + + bool + OldExecute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual int + HandleCompletion (Args &input, + int &cursor_index, + int &cursor_char_position, + int match_start_point, + int max_return_elements, + CommandInterpreter *interpreter, + StringList &matches); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectHelp_h_ diff --git a/lldb/source/Commands/CommandObjectImage.cpp b/lldb/source/Commands/CommandObjectImage.cpp new file mode 100644 index 00000000000..ab728e9d32d --- /dev/null +++ b/lldb/source/Commands/CommandObjectImage.cpp @@ -0,0 +1,1419 @@ +//===-- CommandObjectImage.cpp ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectImage.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Core/Options.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Core/FileSpec.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Stream.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Core/Module.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Interpreter/CommandCompletions.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Static Helper functions +//---------------------------------------------------------------------- +static void +DumpModuleArchitecture (Stream &strm, Module *module, uint32_t width) +{ + if (module) + { + if (width) + strm.Printf("%-*s", width, module->GetArchitecture().AsCString()); + else + strm.PutCString(module->GetArchitecture().AsCString()); + } +} + +static void +DumpModuleUUID (Stream &strm, Module *module) +{ + module->GetUUID().Dump (&strm); +} + +static uint32_t +DumpCompileUnitLineTable +( + CommandContext *context, + Stream &strm, + Module *module, + const FileSpec &file_spec, + bool load_addresses +) +{ + uint32_t num_matches = 0; + if (module) + { + SymbolContextList sc_list; + num_matches = module->ResolveSymbolContextsForFileSpec (file_spec, + 0, + false, + eSymbolContextCompUnit, + sc_list); + + for (uint32_t i=0; i<num_matches; ++i) + { + SymbolContext sc; + if (sc_list.GetContextAtIndex(i, sc)) + { + if (i > 0) + strm << "\n\n"; + + strm << "Line table for " << *dynamic_cast<FileSpec*> (sc.comp_unit) << " in `" + << module->GetFileSpec().GetFilename() << "\n"; + LineTable *line_table = sc.comp_unit->GetLineTable(); + if (line_table) + line_table->GetDescription (&strm, context->GetExecutionContext().process, lldb::eDescriptionLevelBrief); + else + strm << "No line table"; + } + } + } + return num_matches; +} + +static void +DumpFullpath (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width) +{ + if (file_spec_ptr) + { + if (width > 0) + { + char fullpath[PATH_MAX]; + if (file_spec_ptr->GetPath(fullpath, sizeof(fullpath))) + { + strm.Printf("%-*s", width, fullpath); + return; + } + } + else + { + file_spec_ptr->Dump(&strm); + return; + } + } + // Keep the width spacing correct if things go wrong... + if (width > 0) + strm.Printf("%-*s", width, ""); +} + +static void +DumpDirectory (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width) +{ + if (file_spec_ptr) + { + if (width > 0) + strm.Printf("%-*s", width, file_spec_ptr->GetDirectory().AsCString("")); + else + file_spec_ptr->GetDirectory().Dump(&strm); + return; + } + // Keep the width spacing correct if things go wrong... + if (width > 0) + strm.Printf("%-*s", width, ""); +} + +static void +DumpBasename (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width) +{ + if (file_spec_ptr) + { + if (width > 0) + strm.Printf("%-*s", width, file_spec_ptr->GetFilename().AsCString("")); + else + file_spec_ptr->GetFilename().Dump(&strm); + return; + } + // Keep the width spacing correct if things go wrong... + if (width > 0) + strm.Printf("%-*s", width, ""); +} + + +static void +DumpModuleSymtab (CommandContext *context, Stream &strm, Module *module) +{ + if (module) + { + ObjectFile *objfile = module->GetObjectFile (); + if (objfile) + { + Symtab *symtab = objfile->GetSymtab(); + if (symtab) + symtab->Dump(&strm, context->GetExecutionContext().process); + } + } +} + +static void +DumpModuleSections (CommandContext *context, Stream &strm, Module *module) +{ + if (module) + { + ObjectFile *objfile = module->GetObjectFile (); + if (objfile) + { + SectionList *section_list = objfile->GetSectionList(); + if (section_list) + section_list->Dump(&strm, context->GetExecutionContext().process, true); + } + } +} + +static bool +DumpModuleSymbolVendor (Stream &strm, Module *module) +{ + if (module) + { + SymbolVendor *symbol_vendor = module->GetSymbolVendor(true); + if (symbol_vendor) + { + symbol_vendor->Dump(&strm); + return true; + } + } + return false; +} + +static bool +LookupAddressInModule (CommandContext *context, Stream &strm, Module *module, uint32_t resolve_mask, lldb::addr_t raw_addr, lldb::addr_t offset) +{ + if (module) + { + lldb::addr_t addr = raw_addr - offset; + Address so_addr; + SymbolContext sc; + Process *process = context->GetExecutionContext().process; + if (process && process->IsAlive()) + { + if (!process->ResolveLoadAddress (addr, so_addr)) + return false; + else if (so_addr.GetModule() != module) + return false; + } + else + { + if (!module->ResolveFileAddress (addr, so_addr)) + return false; + } + + // If an offset was given, print out the address we ended up looking up + if (offset) + strm.Printf("0x%llx: ", addr); + + ExecutionContextScope *exe_scope = context->GetExecutionContext().GetBestExecutionContextScope(); + if (so_addr.Dump (&strm, exe_scope, Address::DumpStyleSectionNameOffset)) + strm.PutCString(": "); + so_addr.Dump (&strm, exe_scope, Address::DumpStyleResolvedDescription); + return true; + } + + return false; +} + +static uint32_t +LookupSymbolInModule (CommandContext *context, Stream &strm, Module *module, const char *name, bool name_is_regex) +{ + if (module) + { + SymbolContext sc; + + ObjectFile *objfile = module->GetObjectFile (); + if (objfile) + { + Symtab *symtab = objfile->GetSymtab(); + if (symtab) + { + uint32_t i; + std::vector<uint32_t> match_indexes; + ConstString symbol_name (name); + uint32_t num_matches = 0; + if (name_is_regex) + { + RegularExpression name_regexp(name); + num_matches = symtab->AppendSymbolIndexesMatchingRegExAndType (name_regexp, eSymbolTypeAny, + match_indexes); + } + else + { + num_matches = symtab->AppendSymbolIndexesWithName (symbol_name, match_indexes); + } + + + if (num_matches > 0) + { + strm.Indent (); + strm.Printf("%u symbols match %s'%s' in ", num_matches, + name_is_regex ? "the regular expression " : "", name); + DumpFullpath (strm, &module->GetFileSpec(), 0); + strm.PutCString(":\n"); + strm.IndentMore (); + Symtab::DumpSymbolHeader (&strm); + for (i=0; i < num_matches; ++i) + { + Symbol *symbol = symtab->SymbolAtIndex(match_indexes[i]); + strm.Indent (); + symbol->Dump (&strm, context->GetExecutionContext().process, i); + } + strm.IndentLess (); + return num_matches; + } + } + } + } + return 0; +} + + +static void +DumpSymbolContextList (CommandContext *context, Stream &strm, SymbolContextList &sc_list, bool prepend_addr) +{ + strm.IndentMore (); + uint32_t i; + const uint32_t num_matches = sc_list.GetSize(); + + for (i=0; i<num_matches; ++i) + { + SymbolContext sc; + if (sc_list.GetContextAtIndex(i, sc)) + { + strm.Indent(); + if (prepend_addr) + { + if (sc.line_entry.range.GetBaseAddress().IsValid()) + { + lldb::addr_t vm_addr = + sc.line_entry.range.GetBaseAddress().GetLoadAddress(context->GetExecutionContext().process); + int addr_size = sizeof (addr_t); + Process *process = context->GetExecutionContext().process; + if (process) + addr_size = process->GetAddressByteSize(); + if (vm_addr != LLDB_INVALID_ADDRESS) + strm.Address (vm_addr, addr_size); + else + sc.line_entry.range.GetBaseAddress().Dump (&strm, NULL, Address::DumpStyleSectionNameOffset); + + strm.PutCString(" in "); + } + } + sc.DumpStopContext(&strm, context->GetExecutionContext().process, sc.line_entry.range.GetBaseAddress()); + } + } + strm.IndentLess (); +} + +static uint32_t +LookupFunctionInModule (CommandContext *context, Stream &strm, Module *module, const char *name, bool name_is_regex) +{ + if (module && name && name[0]) + { + SymbolContextList sc_list; + + SymbolVendor *symbol_vendor = module->GetSymbolVendor(); + if (symbol_vendor) + { + uint32_t num_matches = 0; + if (name_is_regex) + { + RegularExpression function_name_regex (name); + num_matches = symbol_vendor->FindFunctions(function_name_regex, true, sc_list); + + } + else + { + ConstString function_name(name); + num_matches = symbol_vendor->FindFunctions(function_name, true, sc_list); + } + + if (num_matches) + { + strm.Indent (); + strm.Printf("%u match%s found in ", num_matches, num_matches > 1 ? "es" : ""); + DumpFullpath (strm, &module->GetFileSpec(), 0); + strm.PutCString(":\n"); + DumpSymbolContextList (context, strm, sc_list, true); + } + return num_matches; + } + } + return 0; +} + +static uint32_t +LookupFileAndLineInModule (CommandContext *context, Stream &strm, Module *module, const FileSpec &file_spec, uint32_t line, bool check_inlines) +{ + if (module && file_spec) + { + SymbolContextList sc_list; + const uint32_t num_matches = module->ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines, + eSymbolContextEverything, sc_list); + if (num_matches > 0) + { + strm.Indent (); + strm.Printf("%u match%s found in ", num_matches, num_matches > 1 ? "es" : ""); + strm << file_spec; + if (line > 0) + strm.Printf (":%u", line); + strm << " in "; + DumpFullpath (strm, &module->GetFileSpec(), 0); + strm.PutCString(":\n"); + DumpSymbolContextList (context, strm, sc_list, true); + return num_matches; + } + } + return 0; + +} + + +//---------------------------------------------------------------------- +// Image symbol table dumping command +//---------------------------------------------------------------------- + +class CommandObjectImageDumpModuleList : public CommandObject +{ +public: + + CommandObjectImageDumpModuleList (const char *name, + const char *help, + const char *syntax) : + CommandObject (name, help, syntax) + { + } + + virtual + ~CommandObjectImageDumpModuleList () + { + } + + virtual int + HandleArgumentCompletion (Args &input, + int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, + int max_return_elements, + CommandInterpreter *interpreter, + StringList &matches) + { + // Arguments are the standard module completer. + std::string completion_str (input.GetArgumentAtIndex(cursor_index)); + completion_str.erase (cursor_char_position); + + CommandCompletions::InvokeCommonCompletionCallbacks (CommandCompletions::eModuleCompletion, + completion_str.c_str(), + match_start_point, + max_return_elements, + interpreter, + NULL, + matches); + return matches.GetSize(); + } +}; + +class CommandObjectImageDumpSourceFileList : public CommandObject +{ +public: + + CommandObjectImageDumpSourceFileList (const char *name, + const char *help, + const char *syntax) : + CommandObject (name, help, syntax) + { + } + + virtual + ~CommandObjectImageDumpSourceFileList () + { + } + + virtual int + HandleArgumentCompletion (Args &input, + int &cursor_index, + int &cursor_char_position, + OptionElementVector &opt_element_vector, + int match_start_point, + int max_return_elements, + CommandInterpreter *interpreter, + StringList &matches) + { + // Arguments are the standard source file completer. + std::string completion_str (input.GetArgumentAtIndex(cursor_index)); + completion_str.erase (cursor_char_position); + + CommandCompletions::InvokeCommonCompletionCallbacks (CommandCompletions::eSourceFileCompletion, + completion_str.c_str(), + match_start_point, + max_return_elements, + interpreter, + NULL, + matches); + return matches.GetSize(); + } +}; + + +class CommandObjectImageDumpSymtab : public CommandObjectImageDumpModuleList +{ +public: + CommandObjectImageDumpSymtab () : + CommandObjectImageDumpModuleList ("image dump symtab", + "Dump the symbol table from one or more executable images.", + "image dump symtab [<file1> ...]") + { + } + + virtual + ~CommandObjectImageDumpSymtab () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + uint32_t num_dumped = 0; + + uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); + result.GetOutputStream().SetAddressByteSize(addr_byte_size); + result.GetErrorStream().SetAddressByteSize(addr_byte_size); + + if (command.GetArgumentCount() == 0) + { + // Dump all sections for all modules images + const uint32_t num_modules = target->GetImages().GetSize(); + if (num_modules > 0) + { + result.GetOutputStream().Printf("Dumping symbol table for %u modules.\n", num_modules); + for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx) + { + num_dumped++; + DumpModuleSymtab (context, result.GetOutputStream(), target->GetImages().GetModulePointerAtIndex(image_idx)); + } + } + else + { + result.AppendError ("the target has no associated executable images"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + // Dump specified images (by basename or fullpath) + const char *arg_cstr; + for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) + { + FileSpec image_file(arg_cstr); + ModuleList matching_modules; + const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); + + if (num_matching_modules > 0) + { + for (size_t i=0; i<num_matching_modules; ++i) + { + Module *image_module = matching_modules.GetModulePointerAtIndex(i); + if (image_module) + { + num_dumped++; + DumpModuleSymtab (context, result.GetOutputStream(), image_module); + } + } + } + else + result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr); + } + } + + if (num_dumped > 0) + result.SetStatus (eReturnStatusSuccessFinishResult); + else + { + result.AppendError ("no matching executable images found"); + result.SetStatus (eReturnStatusFailed); + } + } + return result.Succeeded(); + } + +}; + +//---------------------------------------------------------------------- +// Image section dumping command +//---------------------------------------------------------------------- +class CommandObjectImageDumpSections : public CommandObjectImageDumpModuleList +{ +public: + CommandObjectImageDumpSections () : + CommandObjectImageDumpModuleList ( + "image dump sections", + "Dump the sections from one or more executable images.", + "image dump sections [<file1> ...]") + { + } + + virtual + ~CommandObjectImageDumpSections () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + uint32_t num_dumped = 0; + + uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); + result.GetOutputStream().SetAddressByteSize(addr_byte_size); + result.GetErrorStream().SetAddressByteSize(addr_byte_size); + + if (command.GetArgumentCount() == 0) + { + // Dump all sections for all modules images + const uint32_t num_modules = target->GetImages().GetSize(); + if (num_modules > 0) + { + result.GetOutputStream().Printf("Dumping sections for %u modules.\n", num_modules); + for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx) + { + num_dumped++; + DumpModuleSections (context, result.GetOutputStream(), target->GetImages().GetModulePointerAtIndex(image_idx)); + } + } + else + { + result.AppendError ("the target has no associated executable images"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + // Dump specified images (by basename or fullpath) + const char *arg_cstr; + for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) + { + FileSpec image_file(arg_cstr); + ModuleList matching_modules; + const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); + + if (num_matching_modules > 0) + { + for (size_t i=0; i<num_matching_modules; ++i) + { + Module * image_module = matching_modules.GetModulePointerAtIndex(i); + if (image_module) + { + num_dumped++; + DumpModuleSections (context, result.GetOutputStream(), image_module); + } + } + } + else + result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr); + } + } + + if (num_dumped > 0) + result.SetStatus (eReturnStatusSuccessFinishResult); + else + { + result.AppendError ("no matching executable images found"); + result.SetStatus (eReturnStatusFailed); + } + } + return result.Succeeded(); + } +}; + +//---------------------------------------------------------------------- +// Image debug symbol dumping command +//---------------------------------------------------------------------- +class CommandObjectImageDumpSymfile : public CommandObjectImageDumpModuleList +{ +public: + CommandObjectImageDumpSymfile () : + CommandObjectImageDumpModuleList ("image dump symfile", + "Dump the debug symbol file for one or more executable images.", + "image dump symfile [<file1> ...]") + { + } + + virtual + ~CommandObjectImageDumpSymfile () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + uint32_t num_dumped = 0; + + uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); + result.GetOutputStream().SetAddressByteSize(addr_byte_size); + result.GetErrorStream().SetAddressByteSize(addr_byte_size); + + if (command.GetArgumentCount() == 0) + { + // Dump all sections for all modules images + const uint32_t num_modules = target->GetImages().GetSize(); + if (num_modules > 0) + { + result.GetOutputStream().Printf("Dumping debug symbols for %u modules.\n", num_modules); + for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx) + { + if (DumpModuleSymbolVendor (result.GetOutputStream(), target->GetImages().GetModulePointerAtIndex(image_idx))) + num_dumped++; + } + } + else + { + result.AppendError ("the target has no associated executable images"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + // Dump specified images (by basename or fullpath) + const char *arg_cstr; + for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) + { + FileSpec image_file(arg_cstr); + ModuleList matching_modules; + const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); + + if (num_matching_modules > 0) + { + for (size_t i=0; i<num_matching_modules; ++i) + { + Module * image_module = matching_modules.GetModulePointerAtIndex(i); + if (image_module) + { + if (DumpModuleSymbolVendor (result.GetOutputStream(), image_module)) + num_dumped++; + } + } + } + else + result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr); + } + } + + if (num_dumped > 0) + result.SetStatus (eReturnStatusSuccessFinishResult); + else + { + result.AppendError ("no matching executable images found"); + result.SetStatus (eReturnStatusFailed); + } + } + return result.Succeeded(); + } +}; + +//---------------------------------------------------------------------- +// Image debug symbol dumping command +//---------------------------------------------------------------------- +class CommandObjectImageDumpLineTable : public CommandObjectImageDumpSourceFileList +{ +public: + CommandObjectImageDumpLineTable () : + CommandObjectImageDumpSourceFileList ("image dump line-table", + "Dump the debug symbol file for one or more executable images.", + "image dump line-table <file1> [<file2> ...]") + { + } + + virtual + ~CommandObjectImageDumpLineTable () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + ExecutionContext exe_ctx(context->GetExecutionContext()); + uint32_t total_num_dumped = 0; + + uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); + result.GetOutputStream().SetAddressByteSize(addr_byte_size); + result.GetErrorStream().SetAddressByteSize(addr_byte_size); + + if (command.GetArgumentCount() == 0) + { + result.AppendErrorWithFormat ("\nSyntax: %s\n", m_cmd_syntax.c_str()); + result.SetStatus (eReturnStatusFailed); + } + else + { + // Dump specified images (by basename or fullpath) + const char *arg_cstr; + for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) + { + FileSpec file_spec(arg_cstr); + const uint32_t num_modules = target->GetImages().GetSize(); + if (num_modules > 0) + { + uint32_t num_dumped = 0; + for (uint32_t i = 0; i<num_modules; ++i) + { + if (DumpCompileUnitLineTable (context, + result.GetOutputStream(), + target->GetImages().GetModulePointerAtIndex(i), + file_spec, + exe_ctx.process != NULL && exe_ctx.process->IsAlive())) + num_dumped++; + } + if (num_dumped == 0) + result.AppendWarningWithFormat ("No source filenames matched '%s'.\n", arg_cstr); + else + total_num_dumped += num_dumped; + } + } + } + + if (total_num_dumped > 0) + result.SetStatus (eReturnStatusSuccessFinishResult); + else + { + result.AppendError ("no source filenames matched any command arguments"); + result.SetStatus (eReturnStatusFailed); + } + } + return result.Succeeded(); + } +}; + +//---------------------------------------------------------------------- +// Dump multi-word command +//---------------------------------------------------------------------- +class CommandObjectImageDump : public CommandObjectMultiword +{ +public: + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CommandObjectImageDump(CommandInterpreter *interpreter) : + CommandObjectMultiword ("image dump", + "Dumps information in one or more executable images; 'line-table' expects a source file name", + "image dump [symtab|sections|symfile|line-table] [<file1> <file2> ...]") + { + LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpSymtab ()), "symtab", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpSections ()), "sections", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpSymfile ()), "symfile", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageDumpLineTable ()), "line-table", interpreter); + } + + virtual + ~CommandObjectImageDump() + { + } +}; + +//---------------------------------------------------------------------- +// List images with associated information +//---------------------------------------------------------------------- +class CommandObjectImageList : public CommandObject +{ +public: + + class CommandOptions : public Options + { + public: + + CommandOptions () : + Options(), + m_format_array() + { + } + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (int option_idx, const char *option_arg) + { + char short_option = (char) m_getopt_table[option_idx].val; + uint32_t width = 0; + if (option_arg) + width = strtoul (option_arg, NULL, 0); + m_format_array.push_back(std::make_pair(short_option, width)); + Error error; + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + m_format_array.clear(); + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + typedef std::vector< std::pair<char, uint32_t> > FormatWidthCollection; + FormatWidthCollection m_format_array; + }; + + CommandObjectImageList () : + CommandObject ( + "image list", + "List current executable and dependent shared library images.", + "image list [<cmd-options>]") + { + } + + virtual + ~CommandObjectImageList () + { + } + + virtual + Options * + GetOptions () + { + return &m_options; + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); + result.GetOutputStream().SetAddressByteSize(addr_byte_size); + result.GetErrorStream().SetAddressByteSize(addr_byte_size); + // Dump all sections for all modules images + const uint32_t num_modules = target->GetImages().GetSize(); + if (num_modules > 0) + { + Stream &strm = result.GetOutputStream(); + + for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx) + { + Module *module = target->GetImages().GetModulePointerAtIndex(image_idx); + strm.Printf("[%3u] ", image_idx); + + if (m_options.m_format_array.empty()) + { + DumpFullpath(strm, &module->GetFileSpec(), 0); + } + else + { + const size_t num_entries = m_options.m_format_array.size(); + for (size_t i=0; i<num_entries; ++i) + { + if (i > 0) + strm.PutChar(' '); + char format_char = m_options.m_format_array[i].first; + uint32_t width = m_options.m_format_array[i].second; + switch (format_char) + { + case 'a': + DumpModuleArchitecture (strm, module, width); + break; + + case 'f': + DumpFullpath (strm, &module->GetFileSpec(), width); + break; + + case 'd': + DumpDirectory (strm, &module->GetFileSpec(), width); + break; + + case 'b': + DumpBasename (strm, &module->GetFileSpec(), width); + break; + + case 's': + case 'S': + { + SymbolVendor *symbol_vendor = module->GetSymbolVendor(); + if (symbol_vendor) + { + SymbolFile *symbol_file = symbol_vendor->GetSymbolFile(); + if (symbol_file) + { + if (format_char == 'S') + DumpBasename(strm, &symbol_file->GetObjectFile()->GetFileSpec(), width); + else + DumpFullpath (strm, &symbol_file->GetObjectFile()->GetFileSpec(), width); + break; + } + } + strm.Printf("%.*s", width, "<NONE>"); + } + break; + + case 'u': + DumpModuleUUID(strm, module); + break; + + default: + break; + } + } + } + strm.EOL(); + } + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendError ("the target has no associated executable images"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + return result.Succeeded(); + } +protected: + + CommandOptions m_options; +}; + +lldb::OptionDefinition +CommandObjectImageList::CommandOptions::g_option_table[] = +{ +{ 0, false, "arch", 'a', optional_argument, NULL, 0, "<width>", "Display the architecture when listing images."}, +{ 0, false, "uuid", 'u', no_argument, NULL, 0, NULL, "Display the UUID when listing images."}, +{ 0, false, "fullpath", 'f', optional_argument, NULL, 0, "<width>", "Display the fullpath to the image object file."}, +{ 0, false, "directory", 'd', optional_argument, NULL, 0, "<width>", "Display the directory with optional width for the image object file."}, +{ 0, false, "basename", 'b', optional_argument, NULL, 0, "<width>", "Display the basename with optional width for the image object file."}, +{ 0, false, "symfile", 's', optional_argument, NULL, 0, "<width>", "Display the fullpath to the image symbol file with optional width."}, +{ 0, false, "symfile-basename", 'S', optional_argument, NULL, 0, "<width>", "Display the basename to the image symbol file with optional width."}, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + + +//---------------------------------------------------------------------- +// Lookup information in images +//---------------------------------------------------------------------- +class CommandObjectImageLookup : public CommandObject +{ +public: + + enum + { + eLookupTypeInvalid = -1, + eLookupTypeAddress = 0, + eLookupTypeSymbol, + eLookupTypeFileLine, // Line is optional + eLookupTypeFunction, + kNumLookupTypes + }; + + class CommandOptions : public Options + { + public: + + CommandOptions () : + Options() + { + ResetOptionValues(); + } + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (int option_idx, const char *option_arg) + { + Error error; + + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'a': + m_type = eLookupTypeAddress; + m_addr = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS); + if (m_addr == LLDB_INVALID_ADDRESS) + error.SetErrorStringWithFormat ("Invalid address string '%s'.\n", option_arg); + break; + + case 'o': + m_offset = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS); + if (m_offset == LLDB_INVALID_ADDRESS) + error.SetErrorStringWithFormat ("Invalid offset string '%s'.\n", option_arg); + break; + + case 's': + m_str = option_arg; + m_type = eLookupTypeSymbol; + break; + + case 'f': + m_file.SetFile (option_arg); + m_type = eLookupTypeFileLine; + break; + + case 'i': + m_check_inlines = false; + break; + + case 'l': + m_line_number = Args::StringToUInt32(option_arg, UINT32_MAX); + if (m_line_number == UINT32_MAX) + error.SetErrorStringWithFormat ("Invalid line number string '%s'.\n", option_arg); + else if (m_line_number == 0) + error.SetErrorString ("Zero is an invalid line number."); + m_type = eLookupTypeFileLine; + break; + + case 'n': + m_str = option_arg; + m_type = eLookupTypeFunction; + break; + + case 'r': + m_use_regex = true; + break; + } + + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + m_type = eLookupTypeInvalid; + m_str.clear(); + m_file.Clear(); + m_addr = LLDB_INVALID_ADDRESS; + m_offset = 0; + m_line_number = 0; + m_use_regex = false; + m_check_inlines = true; + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + int m_type; // Should be a eLookupTypeXXX enum after parsing options + std::string m_str; // Holds name lookup + FileSpec m_file; // Files for file lookups + lldb::addr_t m_addr; // Holds the address to lookup + lldb::addr_t m_offset; // Subtract this offset from m_addr before doing lookups. + uint32_t m_line_number; // Line number for file+line lookups + bool m_use_regex; // Name lookups in m_str are regular expressions. + bool m_check_inlines;// Check for inline entries when looking up by file/line. + }; + + CommandObjectImageLookup () : + CommandObject ( + "image lookup", + "Look up information within executable and dependent shared library images.", + "image lookup [<cmd-options>] [<file1>...]") + { + } + + virtual + ~CommandObjectImageLookup () + { + } + + virtual + Options * + GetOptions () + { + return &m_options; + } + + + bool + LookupInModule (CommandContext *context, Module *module, CommandReturnObject &result, bool &syntax_error) + { + switch (m_options.m_type) + { + case eLookupTypeAddress: + if (m_options.m_addr != LLDB_INVALID_ADDRESS) + { + if (LookupAddressInModule (context, result.GetOutputStream(), module, eSymbolContextEverything, m_options.m_addr, m_options.m_offset)) + { + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } + break; + + case eLookupTypeSymbol: + if (!m_options.m_str.empty()) + { + if (LookupSymbolInModule (context, result.GetOutputStream(), module, m_options.m_str.c_str(), m_options.m_use_regex)) + { + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } + break; + + case eLookupTypeFileLine: + if (m_options.m_file) + { + + if (LookupFileAndLineInModule (context, + result.GetOutputStream(), + module, + m_options.m_file, + m_options.m_line_number, + m_options.m_check_inlines)) + { + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } + break; + + case eLookupTypeFunction: + if (!m_options.m_str.empty()) + { + if (LookupFunctionInModule (context, + result.GetOutputStream(), + module, + m_options.m_str.c_str(), + m_options.m_use_regex)) + { + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + } + break; + + default: + m_options.GenerateOptionUsage (result.GetErrorStream(), this); + syntax_error = true; + break; + } + + result.SetStatus (eReturnStatusFailed); + return false; + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + bool syntax_error = false; + uint32_t i; + uint32_t num_successful_lookups = 0; + uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize(); + result.GetOutputStream().SetAddressByteSize(addr_byte_size); + result.GetErrorStream().SetAddressByteSize(addr_byte_size); + // Dump all sections for all modules images + + if (command.GetArgumentCount() == 0) + { + // Dump all sections for all modules images + const uint32_t num_modules = target->GetImages().GetSize(); + if (num_modules > 0) + { + for (i = 0; i<num_modules && syntax_error == false; ++i) + { + if (LookupInModule (context, target->GetImages().GetModulePointerAtIndex(i), result, syntax_error)) + { + result.GetOutputStream().EOL(); + num_successful_lookups++; + } + } + } + else + { + result.AppendError ("the target has no associated executable images"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + // Dump specified images (by basename or fullpath) + const char *arg_cstr; + for (i = 0; (arg_cstr = command.GetArgumentAtIndex(i)) != NULL && syntax_error == false; ++i) + { + FileSpec image_file(arg_cstr); + ModuleList matching_modules; + const size_t num_matching_modules = target->GetImages().FindModules(&image_file, NULL, NULL, NULL, matching_modules); + + if (num_matching_modules > 0) + { + for (size_t i=0; i<num_matching_modules; ++i) + { + Module * image_module = matching_modules.GetModulePointerAtIndex(i); + if (image_module) + { + if (LookupInModule (context, image_module, result, syntax_error)) + { + result.GetOutputStream().EOL(); + num_successful_lookups++; + } + } + } + } + else + result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr); + } + } + + if (num_successful_lookups > 0) + result.SetStatus (eReturnStatusSuccessFinishResult); + else + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +protected: + + CommandOptions m_options; +}; + +lldb::OptionDefinition +CommandObjectImageLookup::CommandOptions::g_option_table[] = +{ +{ 1, true, "address", 'a', required_argument, NULL, 0, "<addr>", "Lookup an address in one or more executable images."}, +{ 1, false, "offset", 'o', required_argument, NULL, 0, "<offset>", "When looking up an address subtract <offset> from any addresses before doing the lookup."}, +{ 2, true, "symbol", 's', required_argument, NULL, 0, "<name>", "Lookup a symbol by name in the symbol tables in one or more executable images."}, +{ 2, false, "regex", 'r', no_argument, NULL, 0, NULL, "The <name> argument for name lookups are regular expressions."}, +{ 3, true, "file", 'f', required_argument, NULL, 0, "<file>", "Lookup a file by fullpath or basename in one or more executable images."}, +{ 3, false, "line", 'l', required_argument, NULL, 0, "<line>", "Lookup a line number in a file (must be used in conjunction with --file)."}, +{ 3, false, "no-inlines", 'i', no_argument, NULL, 0, NULL, "Check inline line entries (must be used in conjunction with --file)."}, +{ 4, true, "function", 'n', required_argument, NULL, 0, "<name>", "Lookup a function by name in the debug symbols in one or more executable images."}, +{ 5, false, "regex", 'r', no_argument, NULL, 0, NULL, "The <name> argument for name lookups are regular expressions."}, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + + + + +//---------------------------------------------------------------------- +// CommandObjectImage constructor +//---------------------------------------------------------------------- +CommandObjectImage::CommandObjectImage(CommandInterpreter *interpreter) : + CommandObjectMultiword ("image", + "Access information for one or more executable images.", + "image [dump|list] ...") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectImageDump (interpreter)), "dump", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageList ()), "list", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectImageLookup ()), "lookup", interpreter); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CommandObjectImage::~CommandObjectImage() +{ +} + diff --git a/lldb/source/Commands/CommandObjectImage.h b/lldb/source/Commands/CommandObjectImage.h new file mode 100644 index 00000000000..8863a3649a3 --- /dev/null +++ b/lldb/source/Commands/CommandObjectImage.h @@ -0,0 +1,44 @@ +//===-- CommandObjectImage.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectImage_h_ +#define liblldb_CommandObjectImage_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectImage +//------------------------------------------------------------------------- + +class CommandObjectImage : public CommandObjectMultiword +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CommandObjectImage(CommandInterpreter *interpreter); + virtual + ~CommandObjectImage(); + +private: + //------------------------------------------------------------------ + // For CommandObjectImage only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN (CommandObjectImage); +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectImage_h_ diff --git a/lldb/source/Commands/CommandObjectInfo.cpp b/lldb/source/Commands/CommandObjectInfo.cpp new file mode 100644 index 00000000000..f817cc189b4 --- /dev/null +++ b/lldb/source/Commands/CommandObjectInfo.cpp @@ -0,0 +1,32 @@ +//===-- CommandObjectInfo.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectInfo.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectInfo +//------------------------------------------------------------------------- + +CommandObjectInfo::CommandObjectInfo () : +CommandObjectCrossref ("info", "Lists the kinds of objects for which you can get information, and shows the syntax for doing so.", "info") +{ +} + +CommandObjectInfo::~CommandObjectInfo () +{ +} + + diff --git a/lldb/source/Commands/CommandObjectInfo.h b/lldb/source/Commands/CommandObjectInfo.h new file mode 100644 index 00000000000..44f9bd1a394 --- /dev/null +++ b/lldb/source/Commands/CommandObjectInfo.h @@ -0,0 +1,37 @@ +//===-- CommandObjectInfo.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectInfo_h_ +#define liblldb_CommandObjectInfo_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectCrossref.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectInfo +//------------------------------------------------------------------------- + +class CommandObjectInfo : public CommandObjectCrossref +{ +public: + CommandObjectInfo (); + + virtual + ~CommandObjectInfo (); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectInfo_h_ diff --git a/lldb/source/Commands/CommandObjectLog.cpp b/lldb/source/Commands/CommandObjectLog.cpp new file mode 100644 index 00000000000..6b54badd7fc --- /dev/null +++ b/lldb/source/Commands/CommandObjectLog.cpp @@ -0,0 +1,452 @@ +//===-- CommandObjectLog.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectLog.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private-log.h" + +#include "lldb/Core/Args.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/FileSpec.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/Timer.h" + +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/SymbolVendor.h" + +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + + +static LogChannelSP +GetLogChannelPluginForChannel (const char *channel) +{ + std::string log_channel_plugin_name(channel); + log_channel_plugin_name += LogChannel::GetPluginSuffix(); + LogChannelSP log_channel_sp (LogChannel::FindPlugin (log_channel_plugin_name.c_str())); + return log_channel_sp; +} + + +class CommandObjectLogEnable : public CommandObject +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CommandObjectLogEnable() : + CommandObject ("log enable", + "Enable logging for a single log channel.", + "log enable [<cmd-options>] <channel>") + { + } + + virtual + ~CommandObjectLogEnable() + { + } + + Options * + GetOptions () + { + return &m_options; + } + + virtual bool + Execute (Args& args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + if (args.GetArgumentCount() < 1) + { + result.GetErrorStream() << m_cmd_syntax.c_str(); + } + else + { + Log::Callbacks log_callbacks; + + std::string channel(args.GetArgumentAtIndex(0)); + args.Shift (); // Shift off the channel + StreamSP log_stream_sp; + + if (m_options.log_file.empty()) + { + std::string log_file("<lldb.debugger>"); + LogStreamMap::iterator pos = m_log_streams.find(log_file); + if (pos == m_log_streams.end()) + { + log_stream_sp = Log::GetStreamForSTDOUT (); + if (log_stream_sp) + m_log_streams[log_file] = log_stream_sp; + } + else + log_stream_sp = pos->second; + } + else + { + LogStreamMap::iterator pos = m_log_streams.find(m_options.log_file); + if (pos == m_log_streams.end()) + { + log_stream_sp.reset (new StreamFile (m_options.log_file.c_str(), "w")); + m_log_streams[m_options.log_file] = log_stream_sp; + } + else + log_stream_sp = pos->second; + } + assert (log_stream_sp.get()); + uint32_t log_options = m_options.log_options; + if (log_options == 0) + log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE; + if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks)) + { + log_callbacks.enable (log_stream_sp, log_options, args, &result.GetErrorStream()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + else + { + LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str())); + if (log_channel_sp) + { + if (log_channel_sp->Enable (log_stream_sp, log_options, &result.GetErrorStream(), args)) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat("Invalid log channel '%s'.\n", channel.c_str()); + result.SetStatus (eReturnStatusFailed); + } + } + } + return result.Succeeded(); + } + + + class CommandOptions : public Options + { + public: + + CommandOptions () : + Options (), + log_file (), + log_options (0) + { + } + + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (int option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'f': log_file = option_arg; break; + case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break; + case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break; + case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break; + case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break; + case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break; + case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break; + case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break; + default: + error.SetErrorStringWithFormat ("Unrecognized option '%c'\n", short_option); + break; + } + + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + log_file.clear(); + log_options = 0; + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + std::string log_file; + uint32_t log_options; + }; + +protected: + typedef std::map<std::string, StreamSP> LogStreamMap; + CommandOptions m_options; + LogStreamMap m_log_streams; +}; + +lldb::OptionDefinition +CommandObjectLogEnable::CommandOptions::g_option_table[] = +{ +{ 0, false, "file", 'f', required_argument, NULL, 0, "<filename>", "Set the destination file to log to."}, +{ 0, false, "threadsafe", 't', no_argument, NULL, 0, NULL, "Enable thread safe logging to avoid interweaved log lines." }, +{ 0, false, "verbose", 'v', no_argument, NULL, 0, NULL, "Enable verbose logging." }, +{ 0, false, "debug", 'g', no_argument, NULL, 0, NULL, "Enable debug logging." }, +{ 0, false, "sequence", 's', no_argument, NULL, 0, NULL, "Prepend all log lines with an increasing integer sequence id." }, +{ 0, false, "timestamp", 'T', no_argument, NULL, 0, NULL, "Prepend all log lines with a timestamp." }, +{ 0, false, "pid-tid", 'p', no_argument, NULL, 0, NULL, "Prepend all log lines with the process and thread ID that generates the log line." }, +{ 0, false, "thread-name",'n', no_argument, NULL, 0, NULL, "Prepend all log lines with the thread name for the thread that generates the log line." }, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + +class CommandObjectLogDisable : public CommandObject +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CommandObjectLogDisable() : + CommandObject ("log disable", + "Disable one or more log channels.", + "log disable <channel> [<channel> ...]") + { + } + + virtual + ~CommandObjectLogDisable() + { + } + + virtual bool + Execute (Args& args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + const size_t argc = args.GetArgumentCount(); + if (argc == 0) + { + result.GetErrorStream() << m_cmd_syntax.c_str(); + } + else + { + for (size_t i=0; i<argc; ++i) + { + Log::Callbacks log_callbacks; + + std::string channel(args.GetArgumentAtIndex(i)); + if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks)) + { + log_callbacks.disable (); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + else if (channel == "all") + { + Log::DisableAllLogChannels(); + } + else + { + LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str())); + if (log_channel_sp) + { + log_channel_sp->Disable(); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + else + result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0)); + } + } + } + return result.Succeeded(); + } +}; + +class CommandObjectLogList : public CommandObject +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CommandObjectLogList() : + CommandObject ("log list", + "List the log categories for one or more log channels.", + "log list <channel> [<channel> ...]") + { + } + + virtual + ~CommandObjectLogList() + { + } + + virtual bool + Execute (Args& args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + const size_t argc = args.GetArgumentCount(); + if (argc == 0) + { + Log::ListAllLogChannels (&result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + } + else + { + for (size_t i=0; i<argc; ++i) + { + Log::Callbacks log_callbacks; + + std::string channel(args.GetArgumentAtIndex(i)); + if (Log::GetLogChannelCallbacks (channel.c_str(), log_callbacks)) + { + log_callbacks.list_categories (&result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + } + else if (channel == "all") + { + Log::ListAllLogChannels (&result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + } + else + { + LogChannelSP log_channel_sp (GetLogChannelPluginForChannel(channel.c_str())); + if (log_channel_sp) + { + log_channel_sp->ListCategories(&result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + else + result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0)); + } + } + } + return result.Succeeded(); + } +}; + +class CommandObjectLogTimer : public CommandObject +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CommandObjectLogTimer() : + CommandObject ("log timers", + "Enable, disable, dump, and reset LLDB internal performance timers.", + "log timers < enable | disable | dump | reset >") + { + } + + virtual + ~CommandObjectLogTimer() + { + } + + virtual bool + Execute (Args& args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + const size_t argc = args.GetArgumentCount(); + result.SetStatus(eReturnStatusFailed); + + if (argc == 1) + { + const char *sub_command = args.GetArgumentAtIndex(0); + + if (strcasecmp(sub_command, "enable") == 0) + { + Timer::SetDisplayDepth (UINT32_MAX); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + } + else if (strcasecmp(sub_command, "disable") == 0) + { + Timer::DumpCategoryTimes (&result.GetOutputStream()); + Timer::SetDisplayDepth (0); + result.SetStatus(eReturnStatusSuccessFinishResult); + } + else if (strcasecmp(sub_command, "dump") == 0) + { + Timer::DumpCategoryTimes (&result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + } + else if (strcasecmp(sub_command, "reset") == 0) + { + Timer::ResetCategoryTimes (); + result.SetStatus(eReturnStatusSuccessFinishResult); + } + + } + if (!result.Succeeded()) + { + result.AppendError("Missing subcommand"); + result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str()); + } + return result.Succeeded(); + } +}; + +//---------------------------------------------------------------------- +// CommandObjectLog constructor +//---------------------------------------------------------------------- +CommandObjectLog::CommandObjectLog(CommandInterpreter *interpreter) : + CommandObjectMultiword ("log", + "A set of commands for operating on logs.", + "log <command> [<command-options>]") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectLogEnable), "enable", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectLogDisable), "disable", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectLogList), "list", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectLogTimer), "timers", interpreter); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CommandObjectLog::~CommandObjectLog() +{ +} + + + + diff --git a/lldb/source/Commands/CommandObjectLog.h b/lldb/source/Commands/CommandObjectLog.h new file mode 100644 index 00000000000..a1ba258ea33 --- /dev/null +++ b/lldb/source/Commands/CommandObjectLog.h @@ -0,0 +1,48 @@ +//===-- CommandObjectLog.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectLog_h_ +#define liblldb_CommandObjectLog_h_ + +// C Includes +// C++ Includes +#include <map> +#include <string> + +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectLog +//------------------------------------------------------------------------- + +class CommandObjectLog : public CommandObjectMultiword +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CommandObjectLog(CommandInterpreter *interpreter); + + virtual + ~CommandObjectLog(); + +private: + //------------------------------------------------------------------ + // For CommandObjectLog only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN (CommandObjectLog); +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectLog_h_ diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp new file mode 100644 index 00000000000..91abd81e9fd --- /dev/null +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -0,0 +1,680 @@ +//===-- CommandObjectMemory.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectMemory.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Read memory from the inferior process +//---------------------------------------------------------------------- +class CommandObjectMemoryRead : public CommandObject +{ +public: + + class CommandOptions : public Options + { + public: + CommandOptions () : + Options() + { + ResetOptionValues(); + } + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (int option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'f': + error = Args::StringToFormat (option_arg, m_format); + + switch (m_format) + { + default: + break; + + case eFormatBoolean: + if (m_byte_size == 0) + m_byte_size = 1; + if (m_num_per_line == 0) + m_num_per_line = 1; + break; + + case eFormatCString: + if (m_num_per_line == 0) + m_num_per_line = 1; + break; + + case eFormatPointer: + break; + + case eFormatBinary: + case eFormatFloat: + case eFormatOctal: + case eFormatDecimal: + case eFormatEnum: + case eFormatUnicode16: + case eFormatUnicode32: + case eFormatUnsigned: + if (m_byte_size == 0) + m_byte_size = 4; + if (m_num_per_line == 0) + m_num_per_line = 1; + break; + + case eFormatBytes: + case eFormatBytesWithASCII: + case eFormatChar: + case eFormatCharPrintable: + if (m_byte_size == 0) + m_byte_size = 1; + break; + case eFormatComplex: + if (m_byte_size == 0) + m_byte_size = 8; + break; + case eFormatHex: + if (m_byte_size == 0) + m_byte_size = 4; + break; + + case eFormatVectorOfChar: + case eFormatVectorOfSInt8: + case eFormatVectorOfUInt8: + case eFormatVectorOfSInt16: + case eFormatVectorOfUInt16: + case eFormatVectorOfSInt32: + case eFormatVectorOfUInt32: + case eFormatVectorOfSInt64: + case eFormatVectorOfUInt64: + case eFormatVectorOfFloat32: + case eFormatVectorOfFloat64: + case eFormatVectorOfUInt128: + break; + } + break; + + case 'l': + m_num_per_line = Args::StringToUInt32 (option_arg, 0); + if (m_num_per_line == 0) + error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg); + break; + + case 'c': + m_count = Args::StringToUInt32 (option_arg, 0); + if (m_count == 0) + error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg); + break; + + case 's': + m_byte_size = Args::StringToUInt32 (option_arg, 0); + if (m_byte_size == 0) + error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg); + break; + + default: + error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option); + break; + } + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + m_format = eFormatBytesWithASCII; + m_byte_size = 0; + m_count = 0; + m_num_per_line = 0; + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + lldb::Format m_format; + uint32_t m_byte_size; + uint32_t m_count; + uint32_t m_num_per_line; + }; + + CommandObjectMemoryRead () : + CommandObject ("memory read", + "Read memory from the process being debugged.", + "memory read [<cmd-options>] <start-addr> [<end-addr>]", + eFlagProcessMustBeLaunched) + { + } + + virtual + ~CommandObjectMemoryRead () + { + } + + Options * + GetOptions () + { + return &m_options; + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + result.AppendError("need a process to read memory"); + result.SetStatus(eReturnStatusFailed); + return false; + } + const size_t argc = command.GetArgumentCount(); + + if (argc == 0 || argc > 2) + { + result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + size_t item_byte_size = m_options.m_byte_size; + if (item_byte_size == 0) + { + if (m_options.m_format == eFormatPointer) + item_byte_size = process->GetAddressByteSize(); + else + item_byte_size = 1; + } + + size_t item_count = m_options.m_count; + + size_t num_per_line = m_options.m_num_per_line; + if (num_per_line == 0) + { + num_per_line = (16/item_byte_size); + if (num_per_line == 0) + num_per_line = 1; + } + + size_t total_byte_size = m_options.m_count * item_byte_size; + if (total_byte_size == 0) + total_byte_size = 32; + + lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); + + if (addr == LLDB_INVALID_ADDRESS) + { + result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0)); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (argc == 2) + { + lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0); + if (end_addr == LLDB_INVALID_ADDRESS) + { + result.AppendErrorWithFormat("Invalid end address string '%s'.\n", command.GetArgumentAtIndex(1)); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (end_addr <= addr) + { + result.AppendErrorWithFormat("End address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (item_count != 0) + { + result.AppendErrorWithFormat("Specify either the end address (0x%llx) or the count (--count %u), not both.\n", end_addr, item_count); + result.SetStatus(eReturnStatusFailed); + return false; + } + + total_byte_size = end_addr - addr; + item_count = total_byte_size / item_byte_size; + } + else + { + if (item_count == 0) + item_count = 32; + } + + DataBufferSP data_sp(new DataBufferHeap (total_byte_size, '\0')); + Error error; + size_t bytes_read = process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error); + if (bytes_read == 0) + { + result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr); + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (bytes_read < total_byte_size) + result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr); + + result.SetStatus(eReturnStatusSuccessFinishResult); + DataExtractor data(data_sp, process->GetByteOrder(), process->GetAddressByteSize()); + + Stream &output_stream = result.GetOutputStream(); + data.Dump(&output_stream, + 0, + m_options.m_format, + item_byte_size, + item_count, + num_per_line, + addr, + 0, + 0); + output_stream.EOL(); + return true; + } + +protected: + CommandOptions m_options; +}; + +lldb::OptionDefinition +CommandObjectMemoryRead::CommandOptions::g_option_table[] = +{ + { 0, false, "format", 'f', required_argument, NULL, 0, "<format>", "The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."}, + { 0, false, "size", 's', required_argument, NULL, 0, "<byte-size>","The size in bytes to use when displaying with the selected format."}, + { 0, false, "num-per-line", 'l', required_argument, NULL, 0, "<N>", "The number of items per line to display."}, + { 0, false, "count", 'c', required_argument, NULL, 0, "<N>", "The number of total items to display."}, + { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + +//---------------------------------------------------------------------- +// Write memory to the inferior process +//---------------------------------------------------------------------- +class CommandObjectMemoryWrite : public CommandObject +{ +public: + + class CommandOptions : public Options + { + public: + CommandOptions () : + Options() + { + ResetOptionValues(); + } + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (int option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + switch (short_option) + { + case 'f': + error = Args::StringToFormat (option_arg, m_format); + break; + + case 's': + m_byte_size = Args::StringToUInt32 (option_arg, 0); + if (m_byte_size == 0) + error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg); + break; + + + default: + error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option); + break; + } + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + m_format = eFormatBytes; + m_byte_size = 1; + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + lldb::Format m_format; + uint32_t m_byte_size; + }; + + CommandObjectMemoryWrite () : + CommandObject ("memory write", + "Write memory to the process being debugged.", + "memory write [<cmd-options>] <addr> [value1 value2 ...]", + eFlagProcessMustBeLaunched) + { + } + + virtual + ~CommandObjectMemoryWrite () + { + } + + Options * + GetOptions () + { + return &m_options; + } + + bool + UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size) + { + if (total_byte_size > 8) + return false; + + if (total_byte_size == 8) + return true; + + const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; + return uval64 <= max; + } + + bool + SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size) + { + if (total_byte_size > 8) + return false; + + if (total_byte_size == 8) + return true; + + const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1; + const int64_t min = ~(max); + return min <= sval64 && sval64 <= max; + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + result.AppendError("need a process to read memory"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + const size_t argc = command.GetArgumentCount(); + + if (argc < 2) + { + result.AppendErrorWithFormat ("%s takes an address and at least one value.\n", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + size_t item_byte_size = m_options.m_byte_size ? m_options.m_byte_size : 1; + StreamString buffer (Stream::eBinary, + process->GetAddressByteSize(), + process->GetByteOrder()); + + lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0); + + if (addr == LLDB_INVALID_ADDRESS) + { + result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0)); + result.SetStatus(eReturnStatusFailed); + return false; + } + command.Shift(); // shift off the address argument + uint64_t uval64; + int64_t sval64; + bool success = false; + const uint32_t num_value_args = command.GetArgumentCount(); + uint32_t i; + for (i=0; i<num_value_args; ++i) + { + const char *value_str = command.GetArgumentAtIndex(i); + + switch (m_options.m_format) + { + case eFormatFloat: // TODO: add support for floats soon + case eFormatCharPrintable: + case eFormatBytesWithASCII: + case eFormatComplex: + case eFormatEnum: + case eFormatUnicode16: + case eFormatUnicode32: + case eFormatVectorOfChar: + case eFormatVectorOfSInt8: + case eFormatVectorOfUInt8: + case eFormatVectorOfSInt16: + case eFormatVectorOfUInt16: + case eFormatVectorOfSInt32: + case eFormatVectorOfUInt32: + case eFormatVectorOfSInt64: + case eFormatVectorOfUInt64: + case eFormatVectorOfFloat32: + case eFormatVectorOfFloat64: + case eFormatVectorOfUInt128: + result.AppendError("unsupported format for writing memory"); + result.SetStatus(eReturnStatusFailed); + return false; + + case eFormatDefault: + case eFormatBytes: + case eFormatHex: + // Decode hex bytes + uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success); + if (!success) + { + result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (!UIntValueIsValidForSize (uval64, item_byte_size)) + { + result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; + } + buffer.PutMaxHex64 (uval64, item_byte_size); + break; + + case eFormatBoolean: + uval64 = Args::StringToBoolean(value_str, false, &success); + if (!success) + { + result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str); + result.SetStatus(eReturnStatusFailed); + return false; + } + buffer.PutMaxHex64 (uval64, item_byte_size); + break; + + case eFormatBinary: + uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success); + if (!success) + { + result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (!UIntValueIsValidForSize (uval64, item_byte_size)) + { + result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; + } + buffer.PutMaxHex64 (uval64, item_byte_size); + break; + + case eFormatChar: + case eFormatCString: + if (value_str[0]) + { + size_t len = strlen (value_str); + // Include the NULL for C strings... + if (m_options.m_format == eFormatCString) + ++len; + Error error; + if (process->WriteMemory (addr, value_str, len, error) == len) + { + addr += len; + } + else + { + result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + break; + + case eFormatDecimal: + sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success); + if (!success) + { + result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (!SIntValueIsValidForSize (sval64, item_byte_size)) + { + result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; + } + buffer.PutMaxHex64 (sval64, item_byte_size); + break; + + case eFormatUnsigned: + uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success); + if (!success) + { + result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (!UIntValueIsValidForSize (uval64, item_byte_size)) + { + result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; + } + buffer.PutMaxHex64 (uval64, item_byte_size); + break; + + case eFormatOctal: + uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success); + if (!success) + { + result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (!UIntValueIsValidForSize (uval64, item_byte_size)) + { + result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; + } + buffer.PutMaxHex64 (uval64, item_byte_size); + break; + } + } + + if (!buffer.GetString().empty()) + { + Error error; + if (process->WriteMemory (addr, buffer.GetString().data(), buffer.GetString().size(), error) == buffer.GetString().size()) + return true; + else + { + result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + return true; + } + +protected: + CommandOptions m_options; +}; + +lldb::OptionDefinition +CommandObjectMemoryWrite::CommandOptions::g_option_table[] = +{ + { 0, false, "format", 'f', required_argument, NULL, 0, "<format>", "The format value types that will be decoded and written to memory."}, + { 0, false, "size", 's', required_argument, NULL, 0, "<byte-size>","The size in bytes of the values to write to memory."}, + { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + +//------------------------------------------------------------------------- +// CommandObjectMemory +//------------------------------------------------------------------------- + +CommandObjectMemory::CommandObjectMemory (CommandInterpreter *interpreter) : + CommandObjectMultiword ("memory", + "A set of commands for operating on a memory.", + "memory <subcommand> [<subcommand-options>]") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectMemoryRead ()), "read", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectMemoryWrite ()), "write", interpreter); +} + +CommandObjectMemory::~CommandObjectMemory () +{ +} diff --git a/lldb/source/Commands/CommandObjectMemory.h b/lldb/source/Commands/CommandObjectMemory.h new file mode 100644 index 00000000000..a4665401510 --- /dev/null +++ b/lldb/source/Commands/CommandObjectMemory.h @@ -0,0 +1,33 @@ +//===-- CommandObjectMemory.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectMemory_h_ +#define liblldb_CommandObjectMemory_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectMemory : public CommandObjectMultiword +{ +public: + CommandObjectMemory (CommandInterpreter *interpreter); + + virtual + ~CommandObjectMemory (); +}; + + +} // namespace lldb_private + +#endif // liblldb_CommandObjectMemory_h_ diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp new file mode 100644 index 00000000000..ea0f6aff5eb --- /dev/null +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -0,0 +1,833 @@ +//===-- CommandObjectProcess.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectProcess.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/State.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectProcessLaunch +//------------------------------------------------------------------------- + +class CommandObjectProcessLaunch : public CommandObject +{ +public: + + class CommandOptions : public Options + { + public: + + CommandOptions () : + Options() + { + // Keep default values of all options in one place: ResetOptionValues () + ResetOptionValues (); + } + + ~CommandOptions () + { + } + + Error + SetOptionValue (int option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 's': stop_at_entry = true; break; + case 'e': stderr_path = option_arg; break; + case 'i': stdin_path = option_arg; break; + case 'o': stdout_path = option_arg; break; + case 'p': plugin_name = option_arg; break; + default: + error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); + break; + + } + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + stop_at_entry = false; + stdin_path.clear(); + stdout_path.clear(); + stderr_path.clear(); + plugin_name.clear(); + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + bool stop_at_entry; + std::string stderr_path; + std::string stdin_path; + std::string stdout_path; + std::string plugin_name; + + }; + + CommandObjectProcessLaunch () : + CommandObject ("process launch", + "Launches the executable in the debugger.", + "process launch [<cmd-options>] [<arguments-for-running-the-program>]") + { + } + + + ~CommandObjectProcessLaunch () + { + } + + Options * + GetOptions () + { + return &m_options; + } + + bool + Execute (Args& launch_args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + bool synchronous_execution = interpreter->GetSynchronous (); + // bool launched = false; + // bool stopped_after_launch = false; + + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // If our listener is NULL, users aren't allows to launch + Listener *listener = interpreter->GetListener(); + if (listener == NULL) + { + result.AppendError ("operation not allowed through the command interpreter"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + char filename[PATH_MAX]; + Module *exe_module = target->GetExecutableModule().get(); + exe_module->GetFileSpec().GetPath(filename, sizeof(filename)); + + Process *process = context->GetExecutionContext().process; + if (process) + { + if (process->IsAlive()) + { + result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before running again.\n", + process->GetID()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + + const char *plugin_name; + if (!m_options.plugin_name.empty()) + plugin_name = m_options.plugin_name.c_str(); + else + plugin_name = NULL; + + process = target->CreateProcess (*listener, plugin_name).get(); + + const Args *environment = interpreter->GetEnvironmentVariables(); + const Args *run_args = interpreter->GetProgramArguments(); + + // There are two possible sources of args to be passed to the process upon launching: Those the user + // typed at the run command (launch_args); or those the user pre-set in the run-args variable (run_args). + + // If launch_args is empty, use run_args. + if (launch_args.GetArgumentCount() == 0) + { + if (run_args != NULL) + launch_args.AppendArguments (*run_args); + } + else + { + // launch-args was not empty; use that, AND re-set run-args to contains launch-args values. + StateVariable *run_args_var = interpreter->GetStateVariable ("run-args"); + if (run_args_var != NULL) + { + run_args_var->ArrayClearValues(); + run_args_var->GetArgs().AppendArguments (launch_args); + } + } + + + if (process) + { + const char *archname = exe_module->GetArchitecture().AsCString(); + + const char * stdin_path = NULL; + const char * stdout_path = NULL; + const char * stderr_path = NULL; + + if (!(m_options.stdin_path.empty() && + m_options.stdout_path.empty() && + m_options.stderr_path.empty())) + { + stdin_path = m_options.stdin_path.empty() ? "/dev/null" : m_options.stdin_path.c_str(); + stdout_path = m_options.stdout_path.empty() ? "/dev/null" : m_options.stdout_path.c_str(); + stderr_path = m_options.stderr_path.empty() ? "/dev/null" : m_options.stderr_path.c_str(); + } + + Error error (process->Launch (launch_args.GetConstArgumentVector(), + environment ? environment->GetConstArgumentVector() : NULL, + stdin_path, + stdout_path, + stderr_path)); + + if (error.Success()) + { + result.AppendMessageWithFormat ("Launching '%s' (%s)\n", filename, archname); + result.SetStatus (eReturnStatusSuccessContinuingNoResult); + if (m_options.stop_at_entry == false) + { + StateType state = process->WaitForProcessToStop (NULL); + + if (state == eStateStopped) + { + // Call continue_command. + CommandReturnObject continue_result; + interpreter->HandleCommand("process continue", false, continue_result); + } + + if (synchronous_execution) + { + result.SetDidChangeProcessState (true); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + } + else + { + result.AppendErrorWithFormat ("Process launch failed: %s", + error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat ("Process launch failed: unable to create a process object.\n"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + return result.Succeeded(); + } + +protected: + + CommandOptions m_options; +}; + + +lldb::OptionDefinition +CommandObjectProcessLaunch::CommandOptions::g_option_table[] = +{ +{ 0, false, "stop-at-entry", 's', no_argument, NULL, 0, NULL, "Stop at the entry point of the program when launching a process."}, +{ 0, false, "stdin", 'i', required_argument, NULL, 0, "<path>", "Redirect stdin for the process to <path>."}, +{ 0, false, "stdout", 'o', required_argument, NULL, 0, "<path>", "Redirect stdout for the process to <path>."}, +{ 0, false, "stderr", 'e', required_argument, NULL, 0, "<path>", "Redirect stderr for the process to <path>."}, +{ 0, false, "plugin", 'p', required_argument, NULL, 0, "<plugin>", "Name of the process plugin you want to use."}, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + +//------------------------------------------------------------------------- +// CommandObjectProcessAttach +//------------------------------------------------------------------------- + +class CommandObjectProcessAttach : public CommandObject +{ +public: + + CommandObjectProcessAttach () : + CommandObject ("process attach", + "Attaches to a process.", + "process attach <cmd-options>") + { + SetHelpLong("Currently, you must set the executable file before you can attach " + "to a process.\n"); + } + + ~CommandObjectProcessAttach () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + // If our listener is NULL, users aren't allows to launch + Listener *listener = interpreter->GetListener(); + if (listener == NULL) + { + result.AppendError ("operation not allowed through the command interpreter"); + result.SetStatus (eReturnStatusFailed); + return false; + } + Process *process = context->GetExecutionContext().process; + if (process) + { + if (process->IsAlive()) + { + result.AppendErrorWithFormat ("Process %u is currently being debugged, kill the process before attaching.\n", process->GetID()); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + + if (command.GetArgumentCount()) + { + result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); + result.SetStatus (eReturnStatusFailed); + } + else + { + const char *plugin_name = NULL; + + if (!m_options.plugin_name.empty()) + plugin_name = m_options.plugin_name.c_str(); + + process = target->CreateProcess (*listener, plugin_name).get(); + + if (process) + { + Error error; + int attach_pid = m_options.pid; + + if (attach_pid != LLDB_INVALID_PROCESS_ID) + { + error = process->Attach (attach_pid); + if (error.Success()) + { + result.SetStatus (eReturnStatusSuccessContinuingNoResult); + } + else + { + result.AppendErrorWithFormat ("Attaching to process %i failed: %s.\n", + attach_pid, + error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else if (!m_options.name.empty()) + { + error = process->Attach (m_options.name.c_str(), m_options.waitfor); + if (error.Success()) + { + result.SetStatus (eReturnStatusSuccessContinuingNoResult); + } + else + { + if (m_options.waitfor) + result.AppendErrorWithFormat ("Waiting for a process to launch named '%s': %s\n", + m_options.name.c_str(), + error.AsCString()); + else + result.AppendErrorWithFormat ("Failed to a process named '%s': %s\n", + m_options.name.c_str(), + error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + } + } + return result.Succeeded(); + } + + Options * + GetOptions () + { + return &m_options; + } + + class CommandOptions : public Options + { + public: + + CommandOptions () : + Options() + { + // Keep default values of all options in one place: ResetOptionValues () + ResetOptionValues (); + } + + ~CommandOptions () + { + } + + Error + SetOptionValue (int option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + bool success = false; + switch (short_option) + { + case 'p': + pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success); + if (!success || pid == LLDB_INVALID_PROCESS_ID) + { + error.SetErrorStringWithFormat("Invalid process ID '%s'.\n", option_arg); + } + break; + + case 'P': + plugin_name = option_arg; + break; + + case 'n': + name.assign(option_arg); + break; + + case 'w': + waitfor = true; + break; + + default: + error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); + break; + } + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + pid = LLDB_INVALID_PROCESS_ID; + name.clear(); + waitfor = false; + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + lldb::pid_t pid; + std::string plugin_name; + std::string name; + bool waitfor; + }; + +protected: + + CommandOptions m_options; +}; + + +lldb::OptionDefinition +CommandObjectProcessAttach::CommandOptions::g_option_table[] = +{ +{ 0, false, "pid", 'p', required_argument, NULL, 0, "<pid>", "The process ID of an existing process to attach to."}, +{ 0, false, "plugin", 'P', required_argument, NULL, 0, "<plugin>", "Name of the process plugin you want to use."}, +{ 1, true, "name", 'n', required_argument, NULL, 0, "<process-name>", "The name of the process to attach to."}, +{ 1, false, "waitfor", 'w', no_argument, NULL, 0, NULL, "Wait for the the process with <process-name> to launch."}, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + +//------------------------------------------------------------------------- +// CommandObjectProcessContinue +//------------------------------------------------------------------------- + +class CommandObjectProcessContinue : public CommandObject +{ +public: + + CommandObjectProcessContinue () : + CommandObject ("process continue", + "Continues execution all threads in the current process.", + "process continue", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) + { + } + + + ~CommandObjectProcessContinue () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Process *process = context->GetExecutionContext().process; + bool synchronous_execution = interpreter->GetSynchronous (); + + if (process == NULL) + { + result.AppendError ("no process to continue"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + StateType state = process->GetState(); + if (state == eStateStopped) + { + if (command.GetArgumentCount() != 0) + { + result.AppendErrorWithFormat ("The '%s' command does not take any arguments.\n", m_cmd_name.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const uint32_t num_threads = process->GetThreadList().GetSize(); + + // Set the actions that the threads should each take when resuming + for (uint32_t idx=0; idx<num_threads; ++idx) + { + process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning); + } + + Error error(process->Resume()); + if (error.Success()) + { + result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID()); + if (synchronous_execution) + { + StateType state = process->WaitForProcessToStop (NULL); + + result.SetDidChangeProcessState (true); + result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.SetStatus (eReturnStatusSuccessContinuingNoResult); + } + } + else + { + result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n", + StateAsCString(state)); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + +//------------------------------------------------------------------------- +// CommandObjectProcessDetach +//------------------------------------------------------------------------- + +class CommandObjectProcessDetach : public CommandObject +{ +public: + + CommandObjectProcessDetach () : + CommandObject ("process detach", + "Detaches from the current process being debugged.", + "process detach", + eFlagProcessMustBeLaunched) + { + } + + ~CommandObjectProcessDetach () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + result.AppendError ("must have a valid process in order to detach"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Error error (process->Detach()); + if (error.Success()) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat ("Detach failed: %s\n", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + return false; + } + return result.Succeeded(); + } +}; + +//------------------------------------------------------------------------- +// CommandObjectProcessSignal +//------------------------------------------------------------------------- + +class CommandObjectProcessSignal : public CommandObject +{ +public: + + CommandObjectProcessSignal () : + CommandObject ("process signal", + "Sends a UNIX signal to the current process being debugged.", + "process signal <unix-signal-number>") + { + } + + ~CommandObjectProcessSignal () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + result.AppendError ("no process to signal"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() == 1) + { + int signo = Args::StringToSInt32(command.GetArgumentAtIndex(0), -1, 0); + if (signo == -1) + { + result.AppendErrorWithFormat ("Invalid signal argument '%s'.\n", command.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + } + else + { + Error error (process->Signal (signo)); + if (error.Success()) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat ("Failed to send signal %i: %s\n", signo, error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + } + else + { + result.AppendErrorWithFormat("'%s' takes exactly one signal number argument:\nUsage: \n", m_cmd_name.c_str(), + m_cmd_syntax.c_str()); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + + +//------------------------------------------------------------------------- +// CommandObjectProcessInterrupt +//------------------------------------------------------------------------- + +class CommandObjectProcessInterrupt : public CommandObject +{ +public: + + + CommandObjectProcessInterrupt () : + CommandObject ("process interrupt", + "Interrupts the current process being debugged.", + "process interrupt", + eFlagProcessMustBeLaunched) + { + } + + ~CommandObjectProcessInterrupt () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + result.AppendError ("no process to halt"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() == 0) + { + Error error(process->Halt ()); + if (error.Success()) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + + // Maybe we should add a "SuspendThreadPlans so we + // can halt, and keep in place all the current thread plans. + process->GetThreadList().DiscardThreadPlans(); + } + else + { + result.AppendErrorWithFormat ("Failed to halt process: %s\n", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: \n", + m_cmd_name.c_str(), + m_cmd_syntax.c_str()); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + +//------------------------------------------------------------------------- +// CommandObjectProcessKill +//------------------------------------------------------------------------- + +class CommandObjectProcessKill : public CommandObject +{ +public: + + CommandObjectProcessKill () : + CommandObject ("process kill", + "Terminates the current process being debugged.", + "process kill", + eFlagProcessMustBeLaunched) + { + } + + ~CommandObjectProcessKill () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + result.AppendError ("no process to kill"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (command.GetArgumentCount() == 0) + { + Error error (process->Destroy()); + if (error.Success()) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat ("Failed to kill process: %s\n", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: \n", + m_cmd_name.c_str(), + m_cmd_syntax.c_str()); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + +//------------------------------------------------------------------------- +// CommandObjectMultiwordProcess +//------------------------------------------------------------------------- + +CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter *interpreter) : + CommandObjectMultiword ("process", + "A set of commands for operating on a process.", + "process <subcommand> [<subcommand-options>]") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectProcessAttach ()), "attach", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectProcessLaunch ()), "launch", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectProcessContinue ()), "continue", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectProcessDetach ()), "detach", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectProcessSignal ()), "signal", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectProcessInterrupt ()), "interrupt", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectProcessKill ()), "kill", interpreter); +} + +CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess () +{ +} + diff --git a/lldb/source/Commands/CommandObjectProcess.h b/lldb/source/Commands/CommandObjectProcess.h new file mode 100644 index 00000000000..9a8d59e70e6 --- /dev/null +++ b/lldb/source/Commands/CommandObjectProcess.h @@ -0,0 +1,37 @@ +//===-- CommandObjectProcess.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectProcess_h_ +#define liblldb_CommandObjectProcess_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectMultiwordProcess +//------------------------------------------------------------------------- + +class CommandObjectMultiwordProcess : public CommandObjectMultiword +{ +public: + CommandObjectMultiwordProcess (CommandInterpreter *interpreter); + + virtual + ~CommandObjectMultiwordProcess (); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectProcess_h_ diff --git a/lldb/source/Commands/CommandObjectQuit.cpp b/lldb/source/Commands/CommandObjectQuit.cpp new file mode 100644 index 00000000000..b66f4b108ff --- /dev/null +++ b/lldb/source/Commands/CommandObjectQuit.cpp @@ -0,0 +1,48 @@ +//===-- CommandObjectQuit.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectQuit.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "CommandInterpreter.h" +#include "CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectQuit +//------------------------------------------------------------------------- + +CommandObjectQuit::CommandObjectQuit () : + CommandObject ("quit", "Quits out of the LLDB debugger.", "quit") +{ +} + +CommandObjectQuit::~CommandObjectQuit () +{ +} + +bool +CommandObjectQuit::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + interpreter->BroadcastEvent (CommandInterpreter::eBroadcastBitQuitCommandReceived); + result.SetStatus (eReturnStatusQuit); + return true; +} + diff --git a/lldb/source/Commands/CommandObjectQuit.h b/lldb/source/Commands/CommandObjectQuit.h new file mode 100644 index 00000000000..a45d8a4b51b --- /dev/null +++ b/lldb/source/Commands/CommandObjectQuit.h @@ -0,0 +1,51 @@ +//===-- CommandObjectQuit.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectQuit_h_ +#define liblldb_CommandObjectQuit_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectQuit +//------------------------------------------------------------------------- + +// SPECIAL NOTE!! The CommandObjectQuit is special, because the actual function to execute +// when the user types 'quit' is passed (via function pointer) to the Command Interpreter when it +// is constructed. The function pointer is then stored in this CommandObjectQuit, and is invoked +// via the CommandObjectQuit::Execute function. This is the only command object that works this +// way; it was done this way because different Command Interpreter callers may want or need different things +// to be done in order to shut down properly. + +class CommandObjectQuit : public CommandObject +{ +public: + + CommandObjectQuit (); + + virtual + ~CommandObjectQuit (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectQuit_h_ diff --git a/lldb/source/Commands/CommandObjectRegister.cpp b/lldb/source/Commands/CommandObjectRegister.cpp new file mode 100644 index 00000000000..c4cb705c725 --- /dev/null +++ b/lldb/source/Commands/CommandObjectRegister.cpp @@ -0,0 +1,231 @@ +//===-- CommandObjectRegister.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectRegister.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/RegisterContext.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// "register read" +//---------------------------------------------------------------------- +class CommandObjectRegisterRead : public CommandObject +{ +public: + CommandObjectRegisterRead () : + CommandObject ("register read", + "Dump the one or more register values from the current frame.", + "register read [<reg-name1> [<reg-name2> [...]]]", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) + { + } + + virtual + ~CommandObjectRegisterRead () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + StreamString &output_stream = result.GetOutputStream(); + DataExtractor reg_data; + ExecutionContext exe_ctx(context->GetExecutionContext()); + RegisterContext *reg_context = exe_ctx.GetRegisterContext (); + + if (reg_context) + { + const RegisterInfo *reg_info = NULL; + if (command.GetArgumentCount() == 0) + { + uint32_t set_idx; + const uint32_t num_register_sets = reg_context->GetRegisterSetCount(); + for (set_idx = 0; set_idx < num_register_sets; ++set_idx) + { + uint32_t unavailable_count = 0; + const RegisterSet * const reg_set = reg_context->GetRegisterSet(set_idx); + output_stream.Printf ("%s:\n", reg_set->name); + output_stream.IndentMore (); + const uint32_t num_registers = reg_set->num_registers; + for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) + { + uint32_t reg = reg_set->registers[reg_idx]; + reg_info = reg_context->GetRegisterInfoAtIndex(reg); + if (reg_context->ReadRegisterBytes(reg, reg_data)) + { + output_stream.Indent (); + output_stream.Printf ("%-12s = ", reg_info ? reg_info->name : "<INVALID REGINFO>"); + reg_data.Dump(&output_stream, 0, reg_info->format, reg_info->byte_size, 1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0); + output_stream.EOL(); + } + else + { + ++unavailable_count; + } + } + if (unavailable_count) + { + output_stream.Indent (); + output_stream.Printf("%u registers were unavailable.\n", unavailable_count); + } + output_stream.IndentLess (); + output_stream.EOL(); + } + } + else + { + const char *arg_cstr; + for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx) + { + reg_info = reg_context->GetRegisterInfoByName(arg_cstr); + + if (reg_info) + { + output_stream.Printf("%-12s = ", reg_info->name); + if (reg_context->ReadRegisterBytes(reg_info->reg, reg_data)) + { + reg_data.Dump(&output_stream, 0, reg_info->format, reg_info->byte_size, 1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0); + } + else + { + output_stream.PutCString ("error: unavailable"); + } + output_stream.EOL(); + } + else + { + result.AppendErrorWithFormat ("Invalid register name '%s'.\n", arg_cstr); + } + } + } + } + else + { + result.AppendError ("no current frame"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + + +//---------------------------------------------------------------------- +// "register write" +//---------------------------------------------------------------------- +class CommandObjectRegisterWrite : public CommandObject +{ +public: + CommandObjectRegisterWrite () : + CommandObject ("register write", + "Modify a single register value.", + "register write <reg-name> <value>", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) + { + } + + virtual + ~CommandObjectRegisterWrite () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + DataExtractor reg_data; + ExecutionContext exe_ctx(context->GetExecutionContext()); + RegisterContext *reg_context = exe_ctx.GetRegisterContext (); + + if (reg_context) + { + if (command.GetArgumentCount() != 2) + { + result.AppendError ("register write takes exactly 2 arguments: <reg-name> <value>"); + result.SetStatus (eReturnStatusFailed); + } + else + { + const char *reg_name = command.GetArgumentAtIndex(0); + const char *value_str = command.GetArgumentAtIndex(1); + const RegisterInfo *reg_info = reg_context->GetRegisterInfoByName(reg_name); + + if (reg_info) + { + Scalar scalar; + Error error(scalar.SetValueFromCString (value_str, reg_info->encoding, reg_info->byte_size)); + if (error.Success()) + { + if (reg_context->WriteRegisterValue(reg_info->reg, scalar)) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + return true; + } + } + else + { + result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s': %s\n", + reg_name, + value_str, + error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat ("Register not found for '%s'.\n", reg_name); + result.SetStatus (eReturnStatusFailed); + } + } + } + else + { + result.AppendError ("no current frame"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + + +//---------------------------------------------------------------------- +// CommandObjectRegister constructor +//---------------------------------------------------------------------- +CommandObjectRegister::CommandObjectRegister(CommandInterpreter *interpreter) : + CommandObjectMultiword ("register", + "Access thread registers.", + "register [read|write] ...") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectRegisterRead ()), "read", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectRegisterWrite ()), "write", interpreter); +} + + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CommandObjectRegister::~CommandObjectRegister() +{ +} diff --git a/lldb/source/Commands/CommandObjectRegister.h b/lldb/source/Commands/CommandObjectRegister.h new file mode 100644 index 00000000000..740bc5424e4 --- /dev/null +++ b/lldb/source/Commands/CommandObjectRegister.h @@ -0,0 +1,44 @@ +//===-- CommandObjectRegister.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectRegister_h_ +#define liblldb_CommandObjectRegister_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectRegister +//------------------------------------------------------------------------- + +class CommandObjectRegister : public CommandObjectMultiword +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CommandObjectRegister(CommandInterpreter *interpreter); + virtual + ~CommandObjectRegister(); + +private: + //------------------------------------------------------------------ + // For CommandObjectRegister only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN (CommandObjectRegister); +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectRegister_h_ diff --git a/lldb/source/Commands/CommandObjectRemove.cpp b/lldb/source/Commands/CommandObjectRemove.cpp new file mode 100644 index 00000000000..28736cd16ec --- /dev/null +++ b/lldb/source/Commands/CommandObjectRemove.cpp @@ -0,0 +1,89 @@ +//===-- CommandObjectRemove.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectRemove.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectRemove +//------------------------------------------------------------------------- + +CommandObjectRemove::CommandObjectRemove () : + CommandObject ("remove", + "Allows the user to remove/delete user-defined command functions (script functions).", + "remove <command-name-to-be-removed>") +{ +} + +CommandObjectRemove::~CommandObjectRemove() +{ +} + + +bool +CommandObjectRemove::Execute (Args& args, CommandContext *context, CommandInterpreter *interpreter, + CommandReturnObject &result) +{ + CommandObject::CommandMap::iterator pos; + CommandObject *cmd_obj; + + if (args.GetArgumentCount() != 0) + { + const char *command_name = args.GetArgumentAtIndex(0); + cmd_obj = interpreter->GetCommandObject(command_name); + if (cmd_obj) + { + if (interpreter->CommandExists (command_name)) + { + result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", + command_name); + result.SetStatus (eReturnStatusFailed); + } + else + { + + if (interpreter->RemoveUser (command_name) == false) + { + if (interpreter->UserCommandExists (command_name)) + result.AppendErrorWithFormat ("Unknown error occurred; unable to remove command '%s'.\n", + command_name); + else + result.AppendErrorWithFormat ("'%s' is not a user-defined command/function name.\n", + command_name); + result.SetStatus (eReturnStatusFailed); + } + else + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + else + { + result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n", + command_name); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("must call remove with a valid command"); + result.SetStatus (eReturnStatusFailed); + } + + return result.Succeeded(); +} + diff --git a/lldb/source/Commands/CommandObjectRemove.h b/lldb/source/Commands/CommandObjectRemove.h new file mode 100644 index 00000000000..4b017a4fbb1 --- /dev/null +++ b/lldb/source/Commands/CommandObjectRemove.h @@ -0,0 +1,44 @@ +//===-- CommandObjectRemove.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectRemove_h_ +#define liblldb_CommandObjectRemove_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectRemove +//------------------------------------------------------------------------- + +class CommandObjectRemove : public CommandObject +{ +public: + + CommandObjectRemove (); + + virtual + ~CommandObjectRemove (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectRemove_h_ diff --git a/lldb/source/Commands/CommandObjectScript.cpp b/lldb/source/Commands/CommandObjectScript.cpp new file mode 100644 index 00000000000..64864be8d09 --- /dev/null +++ b/lldb/source/Commands/CommandObjectScript.cpp @@ -0,0 +1,149 @@ +//===-- CommandObjectScript.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectScript.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" + +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" +#include "lldb/Interpreter/ScriptInterpreterNone.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectScript +//------------------------------------------------------------------------- + +CommandObjectScript::CommandObjectScript (ScriptLanguage script_lang) : + CommandObject ("script", + "Passes an expression to the script interpreter for evaluation and returns the results. Drops user into the interactive interpreter if no expressions are given.", + "script [<script-expressions-for-evaluation>]"), + m_script_lang (script_lang), + m_interpreter_ap () +{ +} + +CommandObjectScript::~CommandObjectScript () +{ +} + +bool +CommandObjectScript::ExecuteRawCommandString +( + const char *command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + std::string arg_str (command); + + ScriptInterpreter *script_interpreter = GetInterpreter (); + + if (script_interpreter == NULL) + { + result.AppendError("no script interpeter"); + result.SetStatus (eReturnStatusFailed); + } + + FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle(); + FILE *err_fh = Debugger::GetSharedInstance().GetOutputFileHandle(); + if (out_fh && err_fh) + { + if (arg_str.empty()) + script_interpreter->ExecuteInterpreterLoop (out_fh, err_fh); + else + script_interpreter->ExecuteOneLine (arg_str, out_fh, err_fh); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + if (out_fh == NULL) + result.AppendError("invalid output file handle"); + else + result.AppendError("invalid error file handle"); + } + return result.Succeeded(); +} + +bool +CommandObjectScript::WantsRawCommandString() +{ + return true; +} + +bool +CommandObjectScript::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + std::string arg_str; + ScriptInterpreter *script_interpreter = GetInterpreter (); + + if (script_interpreter == NULL) + { + result.AppendError("no script interpeter"); + result.SetStatus (eReturnStatusFailed); + } + + const int argc = command.GetArgumentCount(); + for (int i = 0; i < argc; ++i) + arg_str.append(command.GetArgumentAtIndex(i)); + + + FILE *out_fh = Debugger::GetSharedInstance().GetOutputFileHandle(); + FILE *err_fh = Debugger::GetSharedInstance().GetOutputFileHandle(); + if (out_fh && err_fh) + { + if (arg_str.empty()) + script_interpreter->ExecuteInterpreterLoop (out_fh, err_fh); + else + script_interpreter->ExecuteOneLine (arg_str, out_fh, err_fh); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + if (out_fh == NULL) + result.AppendError("invalid output file handle"); + else + result.AppendError("invalid error file handle"); + } + return result.Succeeded(); +} + + +ScriptInterpreter * +CommandObjectScript::GetInterpreter () +{ + if (m_interpreter_ap.get() == NULL) + { + switch (m_script_lang) + { + case eScriptLanguagePython: + m_interpreter_ap.reset (new ScriptInterpreterPython ()); + break; + + case eScriptLanguageNone: + m_interpreter_ap.reset (new ScriptInterpreterNone ()); + break; + } + } + return m_interpreter_ap.get(); +} diff --git a/lldb/source/Commands/CommandObjectScript.h b/lldb/source/Commands/CommandObjectScript.h new file mode 100644 index 00000000000..7cd57518ff7 --- /dev/null +++ b/lldb/source/Commands/CommandObjectScript.h @@ -0,0 +1,58 @@ +//===-- CommandObjectScript.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectScript_h_ +#define liblldb_CommandObjectScript_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectScript +//------------------------------------------------------------------------- + +class CommandObjectScript : public CommandObject +{ +public: + + CommandObjectScript (lldb::ScriptLanguage script_lang); + + virtual + ~CommandObjectScript (); + + bool WantsRawCommandString(); + + virtual bool + ExecuteRawCommandString (const char *command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + ScriptInterpreter * + GetInterpreter (); + +private: + lldb::ScriptLanguage m_script_lang; + std::auto_ptr<ScriptInterpreter> m_interpreter_ap; +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectScript_h_ diff --git a/lldb/source/Commands/CommandObjectSelect.cpp b/lldb/source/Commands/CommandObjectSelect.cpp new file mode 100644 index 00000000000..f357cd290a2 --- /dev/null +++ b/lldb/source/Commands/CommandObjectSelect.cpp @@ -0,0 +1,32 @@ +//===-- CommandObjectSelect.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectSelect.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectSelect +//------------------------------------------------------------------------- + +CommandObjectSelect::CommandObjectSelect () : + CommandObjectCrossref ("select", "Lists the kinds of objects you can select, and shows syntax for selecting them.", "select") +{ +} + +CommandObjectSelect::~CommandObjectSelect () +{ +} + + diff --git a/lldb/source/Commands/CommandObjectSelect.h b/lldb/source/Commands/CommandObjectSelect.h new file mode 100644 index 00000000000..18a64eba276 --- /dev/null +++ b/lldb/source/Commands/CommandObjectSelect.h @@ -0,0 +1,37 @@ +//===-- CommandObjectSelect.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectSelect_h_ +#define liblldb_CommandObjectSelect_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectCrossref.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectSelect +//------------------------------------------------------------------------- + +class CommandObjectSelect : public CommandObjectCrossref +{ +public: + CommandObjectSelect (); + + virtual + ~CommandObjectSelect (); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectSelect_h_ diff --git a/lldb/source/Commands/CommandObjectSet.cpp b/lldb/source/Commands/CommandObjectSet.cpp new file mode 100644 index 00000000000..46ad049fd1b --- /dev/null +++ b/lldb/source/Commands/CommandObjectSet.cpp @@ -0,0 +1,153 @@ +//===-- CommandObjectSet.cpp ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectSet.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectSet +//------------------------------------------------------------------------- + +CommandObjectSet::CommandObjectSet () : + CommandObject ("set", + "Allows the user to set or change the value of a single debugger setting variable.", + "set <setting_name> <value>") +{ +} + +CommandObjectSet::~CommandObjectSet() +{ +} + + +bool +CommandObjectSet::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + CommandInterpreter::VariableMap::iterator pos; + + const int argc = command.GetArgumentCount(); + + if (argc < 1) + { + result.AppendError ("'set' takes at least two arguments"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const char *var_name = command.GetArgumentAtIndex(0); + const char *var_value = command.GetArgumentAtIndex(1); + + if (var_name == NULL || var_name[0] == '\0') + { + result.AppendError ("'set' command requires a valid variable name; No value supplied"); + result.SetStatus (eReturnStatusFailed); + } + else if (var_value == NULL || var_value[0] == '\0') + { + // No value given: Check to see if we're trying to clear an array. + StateVariable *var = interpreter->GetStateVariable (var_name); + if (var != NULL + && var->GetType() == StateVariable::eTypeStringArray) + { + var->ArrayClearValues(); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendError ("'set' command requires a valid variable value; No value supplied"); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + StateVariable *var = interpreter->GetStateVariable(var_name); + if (var == NULL) + { + result.AppendErrorWithFormat ("'%s' is not a settable internal variable.\n", var_name); + result.SetStatus (eReturnStatusFailed); + } + else + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + if (var->GetType() == StateVariable::eTypeBoolean) + { + bool success = false; + bool new_value = Args::StringToBoolean (var_value, false, &success); + + if (success) + { + result.SetStatus(eReturnStatusSuccessFinishResult); + if (!var->HasVerifyFunction() || var->VerifyValue (interpreter, (void *) &new_value, result)) + var->SetBoolValue (new_value); + } + else + { + result.AppendErrorWithFormat ("Invalid boolean string '%s'.\n", var_value); + result.SetStatus (eReturnStatusFailed); + } + } + else if (var->GetType() == StateVariable::eTypeInteger) + { + bool success = false; + int new_value = Args::StringToSInt32(var_value, -1, 0, &success); + + if (success) + { + result.SetStatus(eReturnStatusSuccessFinishResult); + if (!var->HasVerifyFunction() || var->VerifyValue (interpreter, (void *) &new_value, result)) + var->SetIntValue (new_value); + } + else + { + result.AppendErrorWithFormat ("Invalid boolean string '%s'.\n", var_value); + result.SetStatus (eReturnStatusFailed); + } + } + else if (var->GetType() == StateVariable::eTypeString) + { + if (!var->HasVerifyFunction() || var->VerifyValue (interpreter, (void *) var_value, result)) + var->SetStringValue (var_value); + } + else if (var->GetType() == StateVariable::eTypeStringArray) + { + if (var_value == NULL || var_value[0] == '\0') + var->ArrayClearValues (); + else + { + command.Shift(); // shift off variable name + var->ArrayClearValues(); // clear the old values + var->GetArgs().AppendArguments (command); // set the new values. + } + } + else + { + result.AppendErrorWithFormat ("Variable '%s' has unrecognized type.\n", + var->GetName()); + result.SetStatus (eReturnStatusFailed); + } + } + } + return result.Succeeded(); +} + diff --git a/lldb/source/Commands/CommandObjectSet.h b/lldb/source/Commands/CommandObjectSet.h new file mode 100644 index 00000000000..1a3c3dfd1bc --- /dev/null +++ b/lldb/source/Commands/CommandObjectSet.h @@ -0,0 +1,44 @@ +//===-- CommandObjectSet.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectSet_h_ +#define liblldb_CommandObjectSet_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectSet +//------------------------------------------------------------------------- + +class CommandObjectSet : public CommandObject +{ +public: + + CommandObjectSet (); + + virtual + ~CommandObjectSet (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectSet_h_ diff --git a/lldb/source/Commands/CommandObjectSettings.cpp b/lldb/source/Commands/CommandObjectSettings.cpp new file mode 100644 index 00000000000..078b699ffdb --- /dev/null +++ b/lldb/source/Commands/CommandObjectSettings.cpp @@ -0,0 +1,62 @@ +//===-- CommandObjectSettings.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectSettings.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectSettings +//------------------------------------------------------------------------- + +CommandObjectSettings::CommandObjectSettings () : + CommandObject ("settings", + "Lists the debugger settings variables available to the user to 'set' or 'show'.", + "settings") +{ +} + +CommandObjectSettings::~CommandObjectSettings() +{ +} + + +bool +CommandObjectSettings::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + CommandInterpreter::VariableMap::iterator pos; + + if (command.GetArgumentCount() != 0) + { + result.AppendError ("'settings' does not take any arguments"); + result.SetStatus (eReturnStatusFailed); + } + else + { + interpreter->ShowVariableHelp (result); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + + return result.Succeeded(); +} + diff --git a/lldb/source/Commands/CommandObjectSettings.h b/lldb/source/Commands/CommandObjectSettings.h new file mode 100644 index 00000000000..674a98b8ca8 --- /dev/null +++ b/lldb/source/Commands/CommandObjectSettings.h @@ -0,0 +1,44 @@ +//===-- CommandObjectSettings.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectSettings_h_ +#define liblldb_CommandObjectSettings_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectSettings +//------------------------------------------------------------------------- + +class CommandObjectSettings : public CommandObject +{ +public: + + CommandObjectSettings (); + + virtual + ~CommandObjectSettings (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectSettings_h_ diff --git a/lldb/source/Commands/CommandObjectShow.cpp b/lldb/source/Commands/CommandObjectShow.cpp new file mode 100644 index 00000000000..be6f6888a99 --- /dev/null +++ b/lldb/source/Commands/CommandObjectShow.cpp @@ -0,0 +1,74 @@ +//===-- CommandObjectShow.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectShow.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectShow +//------------------------------------------------------------------------- + +CommandObjectShow::CommandObjectShow () : + CommandObject ("show", + "Allows the user to see a single debugger setting variable and its value, or lists them all.", + "show [<setting-variable-name>]") +{ +} + +CommandObjectShow::~CommandObjectShow() +{ +} + + +bool +CommandObjectShow::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + CommandInterpreter::VariableMap::iterator pos; + + if (command.GetArgumentCount()) + { + // The user requested to see the value of a particular variable. + + const char *var_name = command.GetArgumentAtIndex(0); + StateVariable *var = interpreter->GetStateVariable(var_name); + if (var) + { + var->AppendVariableInformation (result); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.AppendErrorWithFormat ("Unrecognized variable '%s'; cannot do 'show' command.\n", var_name); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + // The user didn't specify a particular variable, so show the values of all of them. + interpreter->ShowVariableValues(result); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + + return result.Succeeded(); +} diff --git a/lldb/source/Commands/CommandObjectShow.h b/lldb/source/Commands/CommandObjectShow.h new file mode 100644 index 00000000000..460280a3c55 --- /dev/null +++ b/lldb/source/Commands/CommandObjectShow.h @@ -0,0 +1,44 @@ +//===-- CommandObjectShow.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectShow_h_ +#define liblldb_CommandObjectShow_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectShow +//------------------------------------------------------------------------- + +class CommandObjectShow : public CommandObject +{ +public: + + CommandObjectShow (); + + virtual + ~CommandObjectShow (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectShow_h_ diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp new file mode 100644 index 00000000000..e2c3a0a143f --- /dev/null +++ b/lldb/source/Commands/CommandObjectSource.cpp @@ -0,0 +1,127 @@ +//===-- CommandObjectSource.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectSource.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/TargetList.h" + +using namespace lldb; +using namespace lldb_private; + +const char *k_space_characters = "\t\n\v\f\r "; + +//------------------------------------------------------------------------- +// CommandObjectSource +//------------------------------------------------------------------------- + +CommandObjectSource::CommandObjectSource() : + CommandObject ("source", + "Reads in debugger commands from the file <filename> and executes them.", + "source <filename>") +{ +} + +CommandObjectSource::~CommandObjectSource () +{ +} + +bool +CommandObjectSource::Execute +( + Args& args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + const int argc = args.GetArgumentCount(); + if (argc == 1) + { + const char *filename = args.GetArgumentAtIndex(0); + bool success = true; + + result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename); + + FileSpec cmd_file (filename); + if (cmd_file.Exists()) + { + STLStringArray commands; + success = cmd_file.ReadFileLines (commands); + + STLStringArray::iterator pos = commands.begin(); + + // Trim out any empty lines or lines that start with the comment + // char '#' + while (pos != commands.end()) + { + bool remove_string = false; + size_t non_space = pos->find_first_not_of (k_space_characters); + if (non_space == std::string::npos) + remove_string = true; // Empty line + else if ((*pos)[non_space] == '#') + remove_string = true; // Comment line that starts with '#' + + if (remove_string) + pos = commands.erase(pos); + else + ++pos; + } + + if (commands.size() > 0) + { + const size_t num_commands = commands.size(); + size_t i; + for (i = 0; i<num_commands; ++i) + { + result.GetOutputStream().Printf("%s %s\n", interpreter->GetPrompt(), commands[i].c_str()); + if (!interpreter->HandleCommand(commands[i].c_str(), false, result)) + break; + } + + if (i < num_commands) + { + result.AppendErrorWithFormat("Aborting source of '%s' after command '%s' failed.\n", filename, commands[i].c_str()); + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + success = true; + result.SetStatus (eReturnStatusFailed); + } + } + } + else + { + result.AppendErrorWithFormat ("File '%s' does not exist.\n", filename); + result.SetStatus (eReturnStatusFailed); + success = false; + } + + if (success) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + else + { + result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName()); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + +} diff --git a/lldb/source/Commands/CommandObjectSource.h b/lldb/source/Commands/CommandObjectSource.h new file mode 100644 index 00000000000..416e3c02b2c --- /dev/null +++ b/lldb/source/Commands/CommandObjectSource.h @@ -0,0 +1,48 @@ +//===-- CommandObjectSource.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectSource_h_ +#define liblldb_CommandObjectSource_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Core/STLUtils.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectSource +//------------------------------------------------------------------------- + +class CommandObjectSource : public CommandObject +{ +public: + + CommandObjectSource (); + + virtual + ~CommandObjectSource (); + + STLStringArray & + GetCommands (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectSource_h_ diff --git a/lldb/source/Commands/CommandObjectSourceFile.cpp b/lldb/source/Commands/CommandObjectSourceFile.cpp new file mode 100644 index 00000000000..df70bc9aea3 --- /dev/null +++ b/lldb/source/Commands/CommandObjectSourceFile.cpp @@ -0,0 +1,206 @@ +//===-- CommandObjectSourceFile.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectSourceFile.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" +#include "lldb/Core/SourceManager.h" +#include "lldb/Target/TargetList.h" +#include "lldb/Interpreter/CommandCompletions.h" + +using namespace lldb; +using namespace lldb_private; + +CommandObjectSourceFile::CommandOptions::CommandOptions () : + Options() +{ +} + +CommandObjectSourceFile::CommandOptions::~CommandOptions () +{ +} + +Error +CommandObjectSourceFile::CommandOptions::SetOptionValue (int option_idx, const char *option_arg) +{ + Error error; + const char short_option = g_option_table[option_idx].short_option; + switch (short_option) + { + case 'l': + start_line = Args::StringToUInt32 (option_arg, 0); + if (start_line == 0) + error.SetErrorStringWithFormat("Invalid line number: '%s'.\n", option_arg); + break; + + case 'n': + num_lines = Args::StringToUInt32 (option_arg, 0); + if (num_lines == 0) + error.SetErrorStringWithFormat("Invalid line count: '%s'.\n", option_arg); + break; + + case 'f': + file_name = option_arg; + break; + + default: + error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option); + break; + } + + return error; +} + +void +CommandObjectSourceFile::CommandOptions::ResetOptionValues () +{ + Options::ResetOptionValues(); + + file_spec.Clear(); + file_name.clear(); + start_line = 0; + num_lines = 10; +} + +const lldb::OptionDefinition* +CommandObjectSourceFile::CommandOptions::GetDefinitions () +{ + return g_option_table; +} + +lldb::OptionDefinition +CommandObjectSourceFile::CommandOptions::g_option_table[] = +{ +{ 0, false, "line", 'l', required_argument, NULL, 0, "<line>", "The line number at which to start the display source."}, +{ 0, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, "<file>", "The file from which to display source."}, +{ 0, false, "count", 'n', required_argument, NULL, 0, "<count>", "The number of source lines to display."}, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + + +//------------------------------------------------------------------------- +// CommandObjectSourceFile +//------------------------------------------------------------------------- + +CommandObjectSourceFile::CommandObjectSourceFile() : + CommandObject ("source-file", + "Display source files from the current executable's debug info.", + "source-file [<cmd-options>] [<filename>]") +{ +} + +CommandObjectSourceFile::~CommandObjectSourceFile () +{ +} + + +Options * +CommandObjectSourceFile::GetOptions () +{ + return &m_options; +} + + +bool +CommandObjectSourceFile::Execute +( + Args& args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + const int argc = args.GetArgumentCount(); + + if (argc != 0) + { + result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName()); + result.SetStatus (eReturnStatusFailed); + } + + ExecutionContext exe_ctx(context->GetExecutionContext()); + if (m_options.file_name.empty()) + { + // Last valid source manager context, or the current frame if no + // valid last context in source manager. + // One little trick here, if you type the exact same list command twice in a row, it is + // more likely because you typed it once, then typed it again + if (m_options.start_line == 0) + { + if (interpreter->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream())) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + } + } + else + { + if (interpreter->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile( + m_options.start_line, // Line to display + 0, // Lines before line to display + m_options.num_lines, // Lines after line to display + "", // Don't mark "line" + &result.GetOutputStream())) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + } + + } + } + else + { + const char *filename = m_options.file_name.c_str(); + Target *target = context->GetTarget(); + if (target == NULL) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + + bool check_inlines = false; + SymbolContextList sc_list; + size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename, + 0, + check_inlines, + eSymbolContextModule | eSymbolContextCompUnit, + sc_list); + if (num_matches > 0) + { + SymbolContext sc; + if (sc_list.GetContextAtIndex(0, sc)) + { + if (sc.comp_unit) + { + interpreter->GetSourceManager ().DisplaySourceLinesWithLineNumbers (sc.comp_unit, + m_options.start_line, // Line to display + 0, // Lines before line to display + m_options.num_lines, // Lines after line to display + "", // Don't mark "line" + &result.GetOutputStream()); + + result.SetStatus (eReturnStatusSuccessFinishResult); + + } + } + } + } + + return result.Succeeded(); +} + diff --git a/lldb/source/Commands/CommandObjectSourceFile.h b/lldb/source/Commands/CommandObjectSourceFile.h new file mode 100644 index 00000000000..ba12f0f753c --- /dev/null +++ b/lldb/source/Commands/CommandObjectSourceFile.h @@ -0,0 +1,80 @@ +//===-- CommandObjectSourceFile.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectSourceFile_h_ +#define liblldb_CommandObjectSourceFile_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Core/Options.h" +#include "lldb/Core/FileSpec.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectSourceFile +//------------------------------------------------------------------------- + +class CommandObjectSourceFile : public CommandObject +{ +public: + class CommandOptions : public Options + { + public: + + CommandOptions (); + + virtual + ~CommandOptions (); + + virtual Error + SetOptionValue (int option_idx, const char *option_arg); + + void + ResetOptionValues (); + + const lldb::OptionDefinition* + GetDefinitions (); + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + FileSpec file_spec; + std::string file_name; + uint32_t start_line; + uint32_t num_lines; + }; + + CommandObjectSourceFile (); + + virtual + ~CommandObjectSourceFile (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual + Options * + GetOptions (); + +protected: + CommandOptions m_options; +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectSourceFile_h_ diff --git a/lldb/source/Commands/CommandObjectStatus.cpp b/lldb/source/Commands/CommandObjectStatus.cpp new file mode 100644 index 00000000000..501e0b23c84 --- /dev/null +++ b/lldb/source/Commands/CommandObjectStatus.cpp @@ -0,0 +1,97 @@ +//===-- CommandObjectStatus.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectStatus.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "CommandObjectThread.h" + +#include "lldb/Core/State.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectStatus +//------------------------------------------------------------------------- + +CommandObjectStatus::CommandObjectStatus () : + CommandObject ("status", + "Shows the current status and location of executing process.", + "status", + 0) +{ +} + +CommandObjectStatus::~CommandObjectStatus() +{ +} + + +bool +CommandObjectStatus::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + StreamString &output_stream = result.GetOutputStream(); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + ExecutionContext exe_ctx(context->GetExecutionContext()); + if (exe_ctx.process) + { + const StateType state = exe_ctx.process->GetState(); + if (StateIsStoppedState(state)) + { + if (state == eStateExited) + { + int exit_status = exe_ctx.process->GetExitStatus(); + const char *exit_description = exe_ctx.process->GetExitDescription(); + output_stream.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n", + exe_ctx.process->GetID(), + exit_status, + exit_status, + exit_description ? exit_description : ""); + } + else + { + output_stream.Printf ("Process %d %s\n", exe_ctx.process->GetID(), StateAsCString (state)); + if (exe_ctx.thread == NULL) + exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get(); + if (exe_ctx.thread != NULL) + { + DisplayThreadsInfo (interpreter, &exe_ctx, result, true, true); + } + else + { + result.AppendError ("No valid thread found in current process."); + result.SetStatus (eReturnStatusFailed); + } + } + } + } + else + { + result.AppendError ("No current location or status available."); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); +} + diff --git a/lldb/source/Commands/CommandObjectStatus.h b/lldb/source/Commands/CommandObjectStatus.h new file mode 100644 index 00000000000..da5fa7b7097 --- /dev/null +++ b/lldb/source/Commands/CommandObjectStatus.h @@ -0,0 +1,44 @@ +//===-- CommandObjectStatus.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectStatus_h_ +#define liblldb_CommandObjectStatus_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectStatus +//------------------------------------------------------------------------- + +class CommandObjectStatus : public CommandObject +{ +public: + + CommandObjectStatus (); + + ~CommandObjectStatus (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectStatus_h_ diff --git a/lldb/source/Commands/CommandObjectSyntax.cpp b/lldb/source/Commands/CommandObjectSyntax.cpp new file mode 100644 index 00000000000..b1fc42f7637 --- /dev/null +++ b/lldb/source/Commands/CommandObjectSyntax.cpp @@ -0,0 +1,148 @@ +//===-- CommandObjectSyntax.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectSyntax.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Options.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectSyntax +//------------------------------------------------------------------------- + +CommandObjectSyntax::CommandObjectSyntax () : + CommandObject ("syntax", + "Shows the correct syntax for a given debugger command.", + "syntax <command>") +{ +} + +CommandObjectSyntax::~CommandObjectSyntax() +{ +} + + +bool +CommandObjectSyntax::OldExecute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + CommandObject *cmd_obj; + + if (command.GetArgumentCount() != 0) + { + cmd_obj = interpreter->GetCommandObject(command.GetArgumentAtIndex(0)); + if (cmd_obj) + { + Stream &output_strm = result.GetOutputStream(); + if (cmd_obj->GetOptions() != NULL) + { + output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax()); + //cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, cmd_obj); + output_strm.Printf ("(Try 'help %s' for more information on command options syntax.)\n", + cmd_obj->GetCommandName()); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax()); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + else + { + result.AppendErrorWithFormat ("'%s' is not a known command.\n", command.GetArgumentAtIndex(0)); + result.AppendError ("Try 'help' to see a current list of commands."); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("Must call 'syntax' with a valid command."); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); +} + +bool +CommandObjectSyntax::Execute (Args &command, CommandContext *context, CommandInterpreter *interpreter, + CommandReturnObject &result) +{ + CommandObject::CommandMap::iterator pos; + CommandObject *cmd_obj; + const int argc = command.GetArgumentCount(); + + if (argc > 0) + { + cmd_obj = interpreter->GetCommandObject (command.GetArgumentAtIndex(0)); + bool all_okay = true; + for (int i = 1; i < argc; ++i) + { + std::string sub_command = command.GetArgumentAtIndex (i); + if (! cmd_obj->IsMultiwordObject()) + all_okay = false; + else + { + pos = ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.find (sub_command); + if (pos != ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict.end()) + cmd_obj = pos->second.get(); + else + all_okay = false; + } + } + + if (all_okay && (cmd_obj != NULL)) + { + Stream &output_strm = result.GetOutputStream(); + if (cmd_obj->GetOptions() != NULL) + { + output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax()); + //cmd_obj->GetOptions()->GenerateOptionUsage (output_strm, cmd_obj); + output_strm.Printf ("(Try 'help %s' for more information on command options syntax.)\n", + cmd_obj->GetCommandName()); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax()); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + else + { + std::string cmd_string; + command.GetCommandString (cmd_string); + result.AppendErrorWithFormat ("'%s' is not a known command.\n", cmd_string.c_str()); + result.AppendError ("Try 'help' to see a current list of commands."); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("Must call 'syntax' with a valid command."); + result.SetStatus (eReturnStatusFailed); + } + + return result.Succeeded(); +} diff --git a/lldb/source/Commands/CommandObjectSyntax.h b/lldb/source/Commands/CommandObjectSyntax.h new file mode 100644 index 00000000000..e5f5f4e544d --- /dev/null +++ b/lldb/source/Commands/CommandObjectSyntax.h @@ -0,0 +1,51 @@ +//===-- CommandObjectSyntax.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectSyntax_h_ +#define liblldb_CommandObjectSyntax_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectSyntax +//------------------------------------------------------------------------- + +class CommandObjectSyntax : public CommandObject +{ +public: + + CommandObjectSyntax (); + + virtual + ~CommandObjectSyntax (); + + bool + OldExecute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectSyntax_h_ diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp new file mode 100644 index 00000000000..5ea240e301f --- /dev/null +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -0,0 +1,430 @@ +//===-- CommandObjectTarget.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectTarget.h" + +// C Includes +#include <errno.h> +#include <sys/errno.h> +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Timer.h" +#include "lldb/Interpreter/CommandContext.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; + +#pragma mark CommandObjectTargetImageSearchPaths + +class CommandObjectTargetImageSearchPathsAdd : public CommandObject +{ +public: + + CommandObjectTargetImageSearchPathsAdd () : + CommandObject ("target image-search-paths add", + "Add new image search paths substitution pairs to the current target.", + "target image-search-paths add <path-prefix> <new-path-prefix> [<path-prefix> <new-path-prefix>] ...") + { + } + + ~CommandObjectTargetImageSearchPathsAdd () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target * target = context->GetTarget(); + if (target) + { + uint32_t argc = command.GetArgumentCount(); + if (argc & 1) + { + result.AppendError ("add requires an even number of arguments"); + result.SetStatus (eReturnStatusFailed); + } + else + { + for (uint32_t i=0; i<argc; i+=2) + { + const char *from = command.GetArgumentAtIndex(i); + const char *to = command.GetArgumentAtIndex(i+1); + + if (from[0] && to[0]) + { + bool last_pair = ((argc - i) == 2); + target->GetImageSearchPathList().Append(ConstString(from), + ConstString(to), + last_pair); // Notify if this is the last pair + } + else + { + if (from[0]) + result.AppendError ("<path-prefix> can't be empty"); + else + result.AppendError ("<new-path-prefix> can't be empty"); + result.SetStatus (eReturnStatusFailed); + } + } + } + } + else + { + result.AppendError ("invalid target"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + +class CommandObjectTargetImageSearchPathsClear : public CommandObject +{ +public: + + CommandObjectTargetImageSearchPathsClear () : + CommandObject ("target image-search-paths clear", + "Clears all current image search paths substitution pairs from the current target.", + "target image-search-paths clear") + { + } + + ~CommandObjectTargetImageSearchPathsClear () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target * target = context->GetTarget(); + if (target) + { + bool notify = true; + target->GetImageSearchPathList().Clear(notify); + } + else + { + result.AppendError ("invalid target"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + +class CommandObjectTargetImageSearchPathsInsert : public CommandObject +{ +public: + + CommandObjectTargetImageSearchPathsInsert () : + CommandObject ("target image-search-paths insert", + "Inserts a new image search paths substitution pair to the current target at the specified index.", + "target image-search-paths insert <index> <path-prefix> <new-path-prefix> [<path-prefix> <new-path-prefix>] ...") + { + } + + ~CommandObjectTargetImageSearchPathsInsert () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target * target = context->GetTarget(); + if (target) + { + uint32_t argc = command.GetArgumentCount(); + // check for at least 3 arguments and an odd nubmer of parameters + if (argc >= 3 && argc & 1) + { + bool success = false; + + uint32_t insert_idx = Args::StringToUInt32(command.GetArgumentAtIndex(0), UINT32_MAX, 0, &success); + + if (!success) + { + result.AppendErrorWithFormat("<index> parameter is not an integer: '%s'.\n", command.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return result.Succeeded(); + } + + // shift off the index + command.Shift(); + argc = command.GetArgumentCount(); + + for (uint32_t i=0; i<argc; i+=2, ++insert_idx) + { + const char *from = command.GetArgumentAtIndex(i); + const char *to = command.GetArgumentAtIndex(i+1); + + if (from[0] && to[0]) + { + bool last_pair = ((argc - i) == 2); + target->GetImageSearchPathList().Insert (ConstString(from), + ConstString(to), + insert_idx, + last_pair); + } + else + { + if (from[0]) + result.AppendError ("<path-prefix> can't be empty"); + else + result.AppendError ("<new-path-prefix> can't be empty"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + } + else + { + result.AppendError ("insert requires at least three arguments"); + result.SetStatus (eReturnStatusFailed); + return result.Succeeded(); + } + + } + else + { + result.AppendError ("invalid target"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + +class CommandObjectTargetImageSearchPathsList : public CommandObject +{ +public: + + CommandObjectTargetImageSearchPathsList () : + CommandObject ("target image-search-paths list", + "Lists all current image search paths substitution pairs in the current target.", + "target image-search-paths list") + { + } + + ~CommandObjectTargetImageSearchPathsList () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target * target = context->GetTarget(); + if (target) + { + if (command.GetArgumentCount() != 0) + { + result.AppendError ("list takes no arguments"); + result.SetStatus (eReturnStatusFailed); + return result.Succeeded(); + } + + target->GetImageSearchPathList().Dump(&result.GetOutputStream()); + } + else + { + result.AppendError ("invalid target"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + +class CommandObjectTargetImageSearchPathsQuery : public CommandObject +{ +public: + + CommandObjectTargetImageSearchPathsQuery () : + CommandObject ("target image-search-paths query", + "Transforms a path using the first applicable image search path.", + "target image-search-paths query <path>") + { + } + + ~CommandObjectTargetImageSearchPathsQuery () + { + } + + bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Target * target = context->GetTarget(); + if (target) + { + if (command.GetArgumentCount() != 1) + { + result.AppendError ("query requires one argument"); + result.SetStatus (eReturnStatusFailed); + return result.Succeeded(); + } + + ConstString orig(command.GetArgumentAtIndex(0)); + ConstString transformed; + if (target->GetImageSearchPathList().RemapPath(orig, transformed)) + result.GetOutputStream().Printf("%s\n", transformed.GetCString()); + else + result.GetOutputStream().Printf("%s\n", orig.GetCString()); + } + else + { + result.AppendError ("invalid target"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +}; + +// TODO: implement the target select later when we start doing multiple targets +//#pragma mark CommandObjectTargetSelect +// +////------------------------------------------------------------------------- +//// CommandObjectTargetSelect +////------------------------------------------------------------------------- +// +//class CommandObjectTargetSelect : public CommandObject +//{ +//public: +// +// CommandObjectTargetSelect () : +// CommandObject ("frame select", +// "Select the current frame by index in the current thread.", +// "frame select <frame-index>") +// { +// } +// +// ~CommandObjectTargetSelect () +// { +// } +// +// bool +// Execute (Args& command, +// CommandContext *context, +// CommandInterpreter *interpreter, +// CommandReturnObject &result) +// { +// ExecutionContext exe_ctx (context->GetExecutionContext()); +// if (exe_ctx.thread) +// { +// if (command.GetArgumentCount() == 1) +// { +// const char *frame_idx_cstr = command.GetArgumentAtIndex(0); +// +// const uint32_t num_frames = exe_ctx.thread->GetStackFrameCount(); +// const uint32_t frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0); +// if (frame_idx < num_frames) +// { +// exe_ctx.thread->SetCurrentFrameByIndex (frame_idx); +// exe_ctx.frame = exe_ctx.thread->GetCurrentFrame ().get(); +// +// if (exe_ctx.frame) +// { +// if (DisplayFrameForExecutionContext (exe_ctx.thread, +// exe_ctx.frame, +// interpreter, +// result.GetOutputStream(), +// true, +// true, +// 3, +// 3)) +// { +// result.SetStatus (eReturnStatusSuccessFinishResult); +// return result.Succeeded(); +// } +// } +// } +// if (frame_idx == UINT32_MAX) +// result.AppendErrorWithFormat ("Invalid frame index: %s.\n", frame_idx_cstr); +// else +// result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx); +// } +// else +// { +// result.AppendError ("invalid arguments"); +// result.AppendErrorWithFormat ("Usage: %s\n", m_cmd_syntax.c_str()); +// } +// } +// else +// { +// result.AppendError ("no current thread"); +// } +// result.SetStatus (eReturnStatusFailed); +// return false; +// } +//}; + + +#pragma mark CommandObjectMultiwordTarget + +//------------------------------------------------------------------------- +// CommandObjectMultiwordImageSearchPaths +//------------------------------------------------------------------------- + +class CommandObjectMultiwordImageSearchPaths : public CommandObjectMultiword +{ +public: + + CommandObjectMultiwordImageSearchPaths (CommandInterpreter *interpreter) : + CommandObjectMultiword ("target image-search-paths", + "A set of commands for operating on debugger target image search paths.", + "target image-search-paths <subcommand> [<subcommand-options>]") + { + LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsAdd ()), "add", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsClear ()), "clear", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsInsert ()), "insert", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsList ()), "list", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectTargetImageSearchPathsQuery ()), "query", interpreter); + } + + ~CommandObjectMultiwordImageSearchPaths() + { + } +}; + + +#pragma mark CommandObjectMultiwordTarget + +//------------------------------------------------------------------------- +// CommandObjectMultiwordTarget +//------------------------------------------------------------------------- + +CommandObjectMultiwordTarget::CommandObjectMultiwordTarget (CommandInterpreter *interpreter) : + CommandObjectMultiword ("target", + "A set of commands for operating on debugger targets.", + "target <subcommand> [<subcommand-options>]") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectMultiwordImageSearchPaths (interpreter)), "image-search-paths", interpreter); +} + +CommandObjectMultiwordTarget::~CommandObjectMultiwordTarget () +{ +} + diff --git a/lldb/source/Commands/CommandObjectTarget.h b/lldb/source/Commands/CommandObjectTarget.h new file mode 100644 index 00000000000..cd569e1821d --- /dev/null +++ b/lldb/source/Commands/CommandObjectTarget.h @@ -0,0 +1,41 @@ +//===-- CommandObjectTarget.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectTarget_h_ +#define liblldb_CommandObjectTarget_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Options.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectMultiwordTarget +//------------------------------------------------------------------------- + +class CommandObjectMultiwordTarget : public CommandObjectMultiword +{ +public: + + CommandObjectMultiwordTarget (CommandInterpreter *interpreter); + + virtual + ~CommandObjectMultiwordTarget (); + + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectTarget_h_ diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp new file mode 100644 index 00000000000..07777a19cfe --- /dev/null +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -0,0 +1,1277 @@ +//===-- CommandObjectThread.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectThread.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Options.h" +#include "lldb/Core/State.h" +#include "lldb/Core/SourceManager.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Target/ThreadPlanContinue.h" +#include "lldb/Target/ThreadPlanStepInstruction.h" +#include "lldb/Target/ThreadPlanStepOut.h" +#include "lldb/Target/ThreadPlanStepRange.h" +#include "lldb/Target/ThreadPlanStepInRange.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/LineEntry.h" + +using namespace lldb; +using namespace lldb_private; + + +bool +lldb_private::DisplayThreadInfo +( + CommandInterpreter *interpreter, + Stream &strm, + Thread *thread, + bool only_threads_with_stop_reason, + bool show_source +) +{ + if (thread) + { + if (only_threads_with_stop_reason) + { + StopReason thread_stop_reason = eStopReasonNone; + Thread::StopInfo thread_stop_info; + if (thread->GetStopInfo(&thread_stop_info)) + { + thread_stop_reason = thread_stop_info.GetStopReason(); + if (thread_stop_reason == eStopReasonNone) + return false; + } + } + + strm.Indent(); + strm.Printf("%c ", thread->GetProcess().GetThreadList().GetCurrentThread().get() == thread ? '*' : ' '); + + // Show one frame with only the first showing source + if (show_source) + { + DisplayFramesForExecutionContext (thread, + interpreter, + strm, + true, + 0, // Start at first frame + 1, // Number of frames to show + false,// Don't show the frame info since we already displayed most of it above... + 1, // Show source for the first frame + 3, // lines of source context before + 3); // lines of source context after + } + else + { + thread->DumpInfo (strm, + true, // Dump the stop reason? + true, // Dump the thread name? + true, // Dump the queue name? + 0); // Display context info for stack frame zero + + strm.EOL(); + } + + return true; + } + return false; +} + +size_t +lldb_private::DisplayThreadsInfo +( + CommandInterpreter *interpreter, + ExecutionContext *exe_ctx, + CommandReturnObject &result, + bool only_threads_with_stop_reason, + bool show_source +) +{ + StreamString strm; + + size_t num_thread_infos_dumped = 0; + + if (!exe_ctx->process) + return 0; + + const size_t num_threads = exe_ctx->process->GetThreadList().GetSize(); + if (num_threads > 0) + { + + for (uint32_t i = 0; i < num_threads; i++) + { + Thread *thread = exe_ctx->process->GetThreadList().GetThreadAtIndex(i).get(); + if (thread) + { + if (DisplayThreadInfo (interpreter, + strm, + thread, + only_threads_with_stop_reason, + show_source)) + ++num_thread_infos_dumped; + } + } + } + + if (num_thread_infos_dumped > 0) + { + if (num_thread_infos_dumped < num_threads) + result.GetOutputStream().Printf("%u of %u threads stopped with reasons:\n", num_thread_infos_dumped, num_threads); + + result.GetOutputStream().GetString().append(strm.GetString()); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + return num_thread_infos_dumped; +} + + +size_t +lldb_private::DisplayFramesForExecutionContext +( + Thread *thread, + CommandInterpreter *interpreter, + Stream& strm, + bool ascending, + uint32_t first_frame, + uint32_t num_frames, + bool show_frame_info, + uint32_t num_frames_with_source, + uint32_t source_lines_before, + uint32_t source_lines_after +) +{ + if (thread == NULL) + return 0; + + size_t num_frames_displayed = 0; + + if (num_frames == 0) + return 0; + + thread->DumpInfo (strm, + true, // Dump the stop reason? + true, // Dump the thread name? + true, // Dump the queue name? + 0); // Dump info for stack frame zero + strm.EOL(); + strm.IndentMore(); + + StackFrameSP frame_sp; + int frame_idx = 0; + + if (ascending) + { + for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx) + { + frame_sp = thread->GetStackFrameAtIndex (frame_idx); + if (frame_sp.get() == NULL) + break; + + if (DisplayFrameForExecutionContext (thread, + frame_sp.get(), + interpreter, + strm, + show_frame_info, + num_frames_with_source > first_frame - frame_idx, + source_lines_before, + source_lines_after) == false) + break; + + ++num_frames_displayed; + } + } + else + { + for (frame_idx = first_frame + num_frames - 1; frame_idx >= first_frame; --frame_idx) + { + frame_sp = thread->GetStackFrameAtIndex (frame_idx); + if (frame_sp == NULL) + break; + + if (DisplayFrameForExecutionContext (thread, + frame_sp.get(), + interpreter, + strm, + show_frame_info, + num_frames_with_source > first_frame - frame_idx, + source_lines_before, + source_lines_after) == false) + break; + + ++num_frames_displayed; + } + } + strm.IndentLess(); + return num_frames_displayed; +} + +bool +lldb_private::DisplayFrameForExecutionContext +( + Thread *thread, + StackFrame *frame, + CommandInterpreter *interpreter, + Stream& strm, + bool show_frame_info, + bool show_source, + uint32_t source_lines_before, + uint32_t source_lines_after +) +{ + // thread and frame must be filled in prior to calling this function + if (thread && frame) + { + if (show_frame_info) + { + strm.Indent(); + frame->Dump (&strm, true); + strm.EOL(); + } + + SymbolContext sc (frame->GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry)); + + if (show_source && sc.comp_unit && sc.line_entry.IsValid()) + { + interpreter->GetSourceManager().DisplaySourceLinesWithLineNumbers ( + sc.line_entry.file, + sc.line_entry.line, + 3, + 3, + "->", + &strm); + + } + return true; + } + return false; +} + + +//------------------------------------------------------------------------- +// CommandObjectThreadBacktrace +//------------------------------------------------------------------------- + +class CommandObjectThreadBacktrace : public CommandObject +{ +public: + + CommandObjectThreadBacktrace () : + CommandObject ("thread backtrace", + "Shows the stack for one or more threads.", + "thread backtrace [<thread-idx>] ...", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused), + m_ascending (true) + { + } + + ~CommandObjectThreadBacktrace() + { + } + + + bool + Execute + ( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result + ) + { + if (command.GetArgumentCount() == 0) + { + ExecutionContext exe_ctx(context->GetExecutionContext()); + if (exe_ctx.thread) + { + bool show_frame_info = true; + uint32_t num_frames_with_source = 0; // Don't show any frasmes with source when backtracing + if (DisplayFramesForExecutionContext (exe_ctx.thread, + interpreter, + result.GetOutputStream(), + m_ascending, + 0, + UINT32_MAX, + show_frame_info, + num_frames_with_source, + 3, + 3)) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + } + } + else + { + result.AppendError ("invalid thread"); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("backtrace doesn't take arguments (for now)"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); + } +protected: + bool m_ascending; +}; + + +typedef enum StepScope +{ + eStepScopeSource, + eStepScopeInstruction +}; + +class CommandObjectThreadStepWithTypeAndScope : public CommandObject +{ +public: + + class CommandOptions : public Options + { + public: + + CommandOptions () : + Options() + { + // Keep default values of all options in one place: ResetOptionValues () + ResetOptionValues (); + } + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (int option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'a': + { + bool success; + m_avoid_no_debug = Args::StringToBoolean (option_arg, true, &success); + if (!success) + error.SetErrorStringWithFormat("Invalid boolean value for option '%c'.\n", short_option); + } + break; + case 'm': + { + bool found_one = false; + OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; + m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one); + if (!found_one) + error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option); + } + break; + default: + error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); + break; + + } + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + m_avoid_no_debug = true; + m_run_mode = eOnlyDuringStepping; + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + bool m_avoid_no_debug; + RunMode m_run_mode; + }; + + CommandObjectThreadStepWithTypeAndScope (const char *name, + const char *help, + const char *syntax, + uint32_t flags, + StepType step_type, + StepScope step_scope) : + CommandObject (name, help, syntax, flags), + m_step_type (step_type), + m_step_scope (step_scope), + m_options () + { + } + + virtual + ~CommandObjectThreadStepWithTypeAndScope () + { + } + + virtual + Options * + GetOptions () + { + return &m_options; + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Process *process = context->GetExecutionContext().process; + bool synchronous_execution = interpreter->GetSynchronous(); + + if (process == NULL) + { + result.AppendError ("need a valid process to step"); + result.SetStatus (eReturnStatusFailed); + + } + else + { + const uint32_t num_threads = process->GetThreadList().GetSize(); + Thread *thread = NULL; + + if (command.GetArgumentCount() == 0) + { + thread = process->GetThreadList().GetCurrentThread().get(); + if (thread == NULL) + { + result.AppendError ("no current thread in process"); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + else + { + const char *thread_idx_cstr = command.GetArgumentAtIndex(0); + uint32_t step_thread_idx = Args::StringToUInt32 (thread_idx_cstr, LLDB_INVALID_INDEX32); + if (step_thread_idx == LLDB_INVALID_INDEX32) + { + result.AppendErrorWithFormat ("Invalid thread index '%s'.\n", thread_idx_cstr); + result.SetStatus (eReturnStatusFailed); + return false; + } + thread = process->GetThreadList().FindThreadByIndexID(step_thread_idx).get(); + if (thread == NULL) + { + result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n", + step_thread_idx, 0, num_threads); + result.SetStatus (eReturnStatusFailed); + return false; + } + } + + const bool abort_other_plans = false; + const lldb::RunMode stop_other_threads = m_options.m_run_mode; + + // This is a bit unfortunate, but not all the commands in this command object support + // only while stepping, so I use the bool for them. + bool bool_stop_other_threads; + if (m_options.m_run_mode == eAllThreads) + bool_stop_other_threads = false; + else + bool_stop_other_threads = true; + + if (m_step_type == eStepTypeInto) + { + StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); + ThreadPlan *new_plan; + + if (frame->HasDebugInformation ()) + { + new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, m_step_type, + frame->GetSymbolContext(eSymbolContextEverything).line_entry.range, + frame->GetSymbolContext(eSymbolContextEverything), + stop_other_threads); + if (new_plan) + { + ThreadPlanStepInRange *real_plan = dynamic_cast<ThreadPlanStepInRange *> (new_plan); + if (real_plan) + { + if (m_options.m_avoid_no_debug) + { + real_plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug); + } + else + { + real_plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug); + } + } + } + } + else + new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads); + + process->GetThreadList().SetCurrentThreadByID (thread->GetID()); + process->Resume (); + } + else if (m_step_type == eStepTypeOver) + { + StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); + ThreadPlan *new_plan; + + if (frame->HasDebugInformation()) + new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, + m_step_type, + frame->GetSymbolContext(eSymbolContextEverything).line_entry.range, + frame->GetSymbolContext(eSymbolContextEverything), + stop_other_threads); + else + new_plan = thread->QueueThreadPlanForStepSingleInstruction (true, + abort_other_plans, + bool_stop_other_threads); + + // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over. + // Maybe there should be a parameter to control this. + new_plan->SetOkayToDiscard(false); + + process->GetThreadList().SetCurrentThreadByID (thread->GetID()); + process->Resume (); + } + else if (m_step_type == eStepTypeTrace) + { + thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads); + process->GetThreadList().SetCurrentThreadByID (thread->GetID()); + process->Resume (); + } + else if (m_step_type == eStepTypeTraceOver) + { + thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads); + process->GetThreadList().SetCurrentThreadByID (thread->GetID()); + process->Resume (); + } + else if (m_step_type == eStepTypeOut) + { + ThreadPlan *new_plan; + + new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, bool_stop_other_threads, eVoteYes, eVoteNoOpinion); + // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over. + // Maybe there should be a parameter to control this. + new_plan->SetOkayToDiscard(false); + + process->GetThreadList().SetCurrentThreadByID (thread->GetID()); + process->Resume (); + } + else + { + result.AppendError ("step type is not supported"); + result.SetStatus (eReturnStatusFailed); + } + if (synchronous_execution) + { + StateType state = process->WaitForProcessToStop (NULL); + + //EventSP event_sp; + //StateType state = process->WaitForStateChangedEvents (NULL, event_sp); + //while (! StateIsStoppedState (state)) + // { + // state = process->WaitForStateChangedEvents (NULL, event_sp); + // } + process->GetThreadList().SetCurrentThreadByID (thread->GetID()); + result.SetDidChangeProcessState (true); + result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + return result.Succeeded(); + } + +protected: + StepType m_step_type; + StepScope m_step_scope; + CommandOptions m_options; +}; + +static lldb::OptionEnumValueElement +g_tri_running_mode[] = +{ +{ eOnlyThisThread, "thisThread", "Run only this thread"}, +{ eAllThreads, "allThreads", "Run all threads"}, +{ eOnlyDuringStepping, "whileStepping", "Run only this thread while stepping"}, +{ 0, NULL, NULL } +}; + +static lldb::OptionEnumValueElement +g_duo_running_mode[] = +{ +{ eOnlyThisThread, "thisThread", "Run only this thread"}, +{ eAllThreads, "allThreads", "Run all threads"}, +{ 0, NULL, NULL } +}; + +lldb::OptionDefinition +CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] = +{ +{ 0, true, "avoid_no_debug", 'a', required_argument, NULL, 0, "<avoid_no_debug>", "Should step-in step over functions with no debug information"}, +{ 0, true, "run_mode", 'm', required_argument, g_tri_running_mode, 0, "<run_mode>", "Determine how to run other threads while stepping this one"}, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + +//------------------------------------------------------------------------- +// CommandObjectThreadContinue +//------------------------------------------------------------------------- + +class CommandObjectThreadContinue : public CommandObject +{ +public: + + CommandObjectThreadContinue () : + CommandObject ("thread continue", + "Continues execution of one or more threads in an active process.", + "thread continue <thread-index> [<thread-index> ...]", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) + { + } + + + virtual + ~CommandObjectThreadContinue () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + bool synchronous_execution = interpreter->GetSynchronous (); + + if (!context->GetTarget()) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + result.AppendError ("no process exists. Cannot continue"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + StateType state = process->GetState(); + if ((state == eStateCrashed) || (state == eStateStopped) || (state == eStateSuspended)) + { + const uint32_t num_threads = process->GetThreadList().GetSize(); + uint32_t idx; + const size_t argc = command.GetArgumentCount(); + if (argc > 0) + { + std::vector<uint32_t> resume_thread_indexes; + for (uint32_t i=0; i<argc; ++i) + { + idx = Args::StringToUInt32 (command.GetArgumentAtIndex(0), LLDB_INVALID_INDEX32); + if (idx < num_threads) + resume_thread_indexes.push_back(idx); + else + result.AppendWarningWithFormat("Thread index %u out of range.\n", idx); + } + + if (resume_thread_indexes.empty()) + { + result.AppendError ("no valid thread indexes were specified"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + result.AppendMessage ("Resuming thread "); + for (idx=0; idx<num_threads; ++idx) + { + Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); + if (find(resume_thread_indexes.begin(), resume_thread_indexes.end(), idx) != resume_thread_indexes.end()) + { + result.AppendMessageWithFormat ("%u ", idx); + thread->SetResumeState (eStateRunning); + } + else + { + thread->SetResumeState (eStateSuspended); + } + } + result.AppendMessageWithFormat ("in process %i\n", process->GetID()); + } + } + else + { + Thread *current_thread = process->GetThreadList().GetCurrentThread().get(); + if (current_thread == NULL) + { + result.AppendError ("the process doesn't have a current thread"); + result.SetStatus (eReturnStatusFailed); + return false; + } + // Set the actions that the threads should each take when resuming + for (idx=0; idx<num_threads; ++idx) + { + Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); + if (thread == current_thread) + { + result.AppendMessageWithFormat ("Resuming thread 0x%4.4x in process %i\n", thread->GetID(), process->GetID()); + thread->SetResumeState (eStateRunning); + } + else + { + thread->SetResumeState (eStateSuspended); + } + } + } + + Error error (process->Resume()); + if (error.Success()) + { + result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID()); + if (synchronous_execution) + { + StateType state = process->WaitForProcessToStop (NULL); + + result.SetDidChangeProcessState (true); + result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.SetStatus (eReturnStatusSuccessContinuingNoResult); + } + } + else + { + result.AppendErrorWithFormat("Failed to resume process: %s\n", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n", + StateAsCString(state)); + result.SetStatus (eReturnStatusFailed); + } + + return result.Succeeded(); + } + +}; + +//------------------------------------------------------------------------- +// CommandObjectThreadUntil +//------------------------------------------------------------------------- + +class CommandObjectThreadUntil : public CommandObject +{ +public: + + class CommandOptions : public Options + { + public: + uint32_t m_thread_idx; + uint32_t m_frame_idx; + + CommandOptions () : + Options(), + m_thread_idx(LLDB_INVALID_THREAD_ID), + m_frame_idx(LLDB_INVALID_FRAME_ID) + { + // Keep default values of all options in one place: ResetOptionValues () + ResetOptionValues (); + } + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (int option_idx, const char *option_arg) + { + Error error; + char short_option = (char) m_getopt_table[option_idx].val; + + switch (short_option) + { + case 't': + { + uint32_t m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32); + if (m_thread_idx == LLDB_INVALID_INDEX32) + { + error.SetErrorStringWithFormat ("Invalid thread index '%s'.\n", option_arg); + } + } + break; + case 'f': + { + m_frame_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_FRAME_ID); + if (m_frame_idx == LLDB_INVALID_FRAME_ID) + { + error.SetErrorStringWithFormat ("Invalid frame index '%s'.\n", option_arg); + } + } + break; + case 'm': + { + bool found_one = false; + OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; + lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one); + + if (!found_one) + error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option); + else if (run_mode == eAllThreads) + m_stop_others = false; + else + m_stop_others = true; + + } + break; + default: + error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); + break; + + } + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + m_thread_idx = LLDB_INVALID_THREAD_ID; + m_frame_idx = 0; + m_stop_others = false; + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + uint32_t m_step_thread_idx; + bool m_stop_others; + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + }; + + CommandObjectThreadUntil () : + CommandObject ("thread until", + "Runs the current or specified thread until it reaches a given line number or leaves the current function.", + "thread until [<cmd-options>] <line-number>", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused), + m_options () + { + } + + + virtual + ~CommandObjectThreadUntil () + { + } + + virtual + Options * + GetOptions () + { + return &m_options; + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + bool synchronous_execution = interpreter->GetSynchronous (); + + if (!context->GetTarget()) + { + result.AppendError ("invalid target, set executable file using 'file' command"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + result.AppendError ("need a valid process to step"); + result.SetStatus (eReturnStatusFailed); + + } + else + { + Thread *thread = NULL; + uint32_t line_number; + + if (command.GetArgumentCount() != 1) + { + result.AppendErrorWithFormat ("No line number provided:\n%s", GetSyntax()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + line_number = Args::StringToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX); + if (line_number == UINT32_MAX) + { + result.AppendErrorWithFormat ("Invalid line number: '%s'.\n", command.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) + { + thread = process->GetThreadList().GetCurrentThread().get(); + } + else + { + thread = process->GetThreadList().GetThreadAtIndex(m_options.m_thread_idx).get(); + } + + if (thread == NULL) + { + const uint32_t num_threads = process->GetThreadList().GetSize(); + result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n", m_options.m_thread_idx, 0, num_threads); + result.SetStatus (eReturnStatusFailed); + return false; + } + + const bool abort_other_plans = true; + + StackFrame *frame = thread->GetStackFrameAtIndex(m_options.m_frame_idx).get(); + if (frame == NULL) + { + + result.AppendErrorWithFormat ("Frame index %u is out of range for thread %u.\n", m_options.m_frame_idx, m_options.m_thread_idx); + result.SetStatus (eReturnStatusFailed); + return false; + } + + ThreadPlan *new_plan; + + if (frame->HasDebugInformation ()) + { + // Finally we got here... Translate the given line number to a bunch of addresses: + SymbolContext sc(frame->GetSymbolContext (eSymbolContextCompUnit)); + LineTable *line_table = NULL; + if (sc.comp_unit) + line_table = sc.comp_unit->GetLineTable(); + + if (line_table == NULL) + { + result.AppendErrorWithFormat ("Failed to resolve the line table for frame %u of thread index %u.\n", + m_options.m_frame_idx, m_options.m_thread_idx); + result.SetStatus (eReturnStatusFailed); + return false; + } + + LineEntry function_start; + uint32_t index_ptr = 0, end_ptr; + std::vector<addr_t> address_list; + + // Find the beginning & end index of the + AddressRange fun_addr_range = sc.function->GetAddressRange(); + Address fun_start_addr = fun_addr_range.GetBaseAddress(); + line_table->FindLineEntryByAddress (fun_start_addr, function_start, &index_ptr); + + Address fun_end_addr(fun_start_addr.GetSection(), fun_start_addr.GetOffset() + fun_addr_range.GetByteSize()); + line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr); + + while (index_ptr <= end_ptr) + { + LineEntry line_entry; + index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, &line_entry); + if (index_ptr == UINT32_MAX) + break; + + addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(process); + if (address != LLDB_INVALID_ADDRESS) + address_list.push_back (address); + index_ptr++; + } + + new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, address_list.data(), address_list.size(), m_options.m_stop_others); + new_plan->SetOkayToDiscard(false); + } + else + { + result.AppendErrorWithFormat ("Frame index %u of thread %u has no debug information.\n", m_options.m_frame_idx, m_options.m_thread_idx); + result.SetStatus (eReturnStatusFailed); + return false; + + } + + process->GetThreadList().SetCurrentThreadByID (m_options.m_thread_idx); + Error error (process->Resume ()); + if (error.Success()) + { + result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID()); + if (synchronous_execution) + { + StateType state = process->WaitForProcessToStop (NULL); + + result.SetDidChangeProcessState (true); + result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + else + { + result.SetStatus (eReturnStatusSuccessContinuingNoResult); + } + } + else + { + result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + + } + return result.Succeeded(); + } +protected: + CommandOptions m_options; + +}; + +lldb::OptionDefinition +CommandObjectThreadUntil::CommandOptions::g_option_table[] = +{ +{ 0, true, "frame", 'f', required_argument, NULL, 0, "<frame>", "Frame index for until operation - defaults to 0"}, +{ 0, true, "thread", 't', required_argument, NULL, 0, "<thread>", "Thread index for the thread for until operation"}, +{ 0, true, "run_mode", 'm', required_argument, g_duo_running_mode, 0, "<run_mode>", "Determine how to run other threads while stepping this one"}, +{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } +}; + + +//------------------------------------------------------------------------- +// CommandObjectThreadSelect +//------------------------------------------------------------------------- + +class CommandObjectThreadSelect : public CommandObject +{ +public: + + CommandObjectThreadSelect () : + CommandObject ("thread select", + "Selects a threads as the currently active thread.", + "thread select <thread-index>", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) + { + } + + + virtual + ~CommandObjectThreadSelect () + { + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + Process *process = context->GetExecutionContext().process; + if (process == NULL) + { + result.AppendError ("no process"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else if (command.GetArgumentCount() != 1) + { + result.AppendErrorWithFormat("'%s' takes exactly one thread index argument:\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + uint32_t index_id = Args::StringToUInt32(command.GetArgumentAtIndex(0), 0, 0); + + Thread *new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get(); + if (new_thread == NULL) + { + result.AppendErrorWithFormat ("Invalid thread #%s.\n", command.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + process->GetThreadList().SetCurrentThreadByID(new_thread->GetID()); + + DisplayThreadInfo (interpreter, + result.GetOutputStream(), + new_thread, + false, + true); + + return result.Succeeded(); + } + +}; + + +//------------------------------------------------------------------------- +// CommandObjectThreadList +//------------------------------------------------------------------------- + +CommandObjectThreadList::CommandObjectThreadList (): + CommandObject ("thread list", + "Shows a summary of all current threads in a process.", + "thread list", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) +{ +} + +CommandObjectThreadList::~CommandObjectThreadList() +{ +} + +bool +CommandObjectThreadList::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + StreamString &strm = result.GetOutputStream(); + result.SetStatus (eReturnStatusSuccessFinishNoResult); + ExecutionContext exe_ctx(context->GetExecutionContext()); + if (exe_ctx.process) + { + const StateType state = exe_ctx.process->GetState(); + + if (StateIsStoppedState(state)) + { + if (state == eStateExited) + { + int exit_status = exe_ctx.process->GetExitStatus(); + const char *exit_description = exe_ctx.process->GetExitDescription(); + strm.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n", + exe_ctx.process->GetID(), + exit_status, + exit_status, + exit_description ? exit_description : ""); + } + else + { + strm.Printf ("Process %d state is %s\n", exe_ctx.process->GetID(), StateAsCString (state)); + if (exe_ctx.thread == NULL) + exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get(); + if (exe_ctx.thread != NULL) + { + DisplayThreadsInfo (interpreter, &exe_ctx, result, false, false); + } + else + { + result.AppendError ("no valid thread found in current process"); + result.SetStatus (eReturnStatusFailed); + } + } + } + else + { + result.AppendError ("process is currently running"); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("no current location or status available"); + result.SetStatus (eReturnStatusFailed); + } + return result.Succeeded(); +} + +//------------------------------------------------------------------------- +// CommandObjectMultiwordThread +//------------------------------------------------------------------------- + +CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter *interpreter) : + CommandObjectMultiword ("thread", + "A set of commands for operating on one or more thread within a running process.", + "thread <subcommand> [<subcommand-options>]") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectThreadBacktrace ()), "backtrace", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectThreadContinue ()), "continue", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectThreadList ()), "list", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectThreadSelect ()), "select", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectThreadUntil ()), "until", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-in", + "Source level single step in in specified thread (current thread, if none specified).", + "thread step-in [<thread-id>]", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, + eStepTypeInto, + eStepScopeSource)), + "step-in", interpreter); + + LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-out", + "Source level single step out in specified thread (current thread, if none specified).", + "thread step-out [<thread-id>]", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, + eStepTypeOut, + eStepScopeSource)), + "step-out", interpreter); + + LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-over", + "Source level single step over in specified thread (current thread, if none specified).", + "thread step-over [<thread-id>]", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, + eStepTypeOver, + eStepScopeSource)), + "step-over", interpreter); + + LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst", + "Single step one instruction in specified thread (current thread, if none specified).", + "thread step-inst [<thread-id>]", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, + eStepTypeTrace, + eStepScopeInstruction)), + "step-inst", interpreter); + LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst-over", + "Single step one instruction in specified thread (current thread, if none specified), stepping over calls.", + "thread step-inst-over [<thread-id>]", + eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, + eStepTypeTraceOver, + eStepScopeInstruction)), + "step-inst-over", interpreter); +} + +CommandObjectMultiwordThread::~CommandObjectMultiwordThread () +{ +} + + diff --git a/lldb/source/Commands/CommandObjectThread.h b/lldb/source/Commands/CommandObjectThread.h new file mode 100644 index 00000000000..21bba714626 --- /dev/null +++ b/lldb/source/Commands/CommandObjectThread.h @@ -0,0 +1,87 @@ +//===-- CommandObjectThread.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectThread_h_ +#define liblldb_CommandObjectThread_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectThreadList : public CommandObject +{ +public: + + CommandObjectThreadList (); + + ~CommandObjectThreadList (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); +}; + + +class CommandObjectMultiwordThread : public CommandObjectMultiword +{ +public: + + CommandObjectMultiwordThread (CommandInterpreter *interpreter); + + virtual + ~CommandObjectMultiwordThread (); + +}; + + +bool +DisplayThreadInfo (CommandInterpreter *interpreter, + Stream &strm, + Thread *thread, + bool only_threads_with_stop_reason, + bool show_source); + +size_t +DisplayThreadsInfo (CommandInterpreter *interpreter, + ExecutionContext *exe_ctx, + CommandReturnObject &result, + bool only_threads_with_stop_reason, + bool show_source); + +size_t +DisplayFramesForExecutionContext (Thread *thread, + CommandInterpreter *interpreter, + Stream& strm, + bool ascending, + uint32_t first_frame, + uint32_t num_frames, + bool show_frame_info, + uint32_t num_frames_with_source, + uint32_t source_lines_before, + uint32_t source_lines_after); + +bool +DisplayFrameForExecutionContext (Thread *thread, + StackFrame *frame, + CommandInterpreter *interpreter, + Stream& strm, + bool show_frame_info, + bool show_source, + uint32_t source_lines_before, + uint32_t source_lines_after); + +} // namespace lldb_private + +#endif // liblldb_CommandObjectThread_h_ diff --git a/lldb/source/Commands/CommandObjectTranslate.cpp b/lldb/source/Commands/CommandObjectTranslate.cpp new file mode 100644 index 00000000000..48a10626c8d --- /dev/null +++ b/lldb/source/Commands/CommandObjectTranslate.cpp @@ -0,0 +1,75 @@ +//===-- CommandObjectTranslate.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectTranslate.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Args.h" +#include "lldb/Core/Options.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectTranslate +//------------------------------------------------------------------------- + +CommandObjectTranslate::CommandObjectTranslate () : + CommandObject ("translate", + "Shows the actual function called for a given debugger command.", + "translate <command>") +{ +} + +CommandObjectTranslate::~CommandObjectTranslate() +{ +} + + +bool +CommandObjectTranslate::Execute +( + Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result +) +{ + CommandObject *cmd_obj; + + if (command.GetArgumentCount() != 0) + { + cmd_obj = interpreter->GetCommandObject(command.GetArgumentAtIndex(0)); + if (cmd_obj) + { + result.SetStatus (eReturnStatusSuccessFinishNoResult); + result.AppendMessageWithFormat ("%s\n", cmd_obj->Translate()); + } + else + { + result.AppendErrroWithFormat + ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n", + command.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("must call translate with a valid command"); + result.SetStatus (eReturnStatusFailed); + } + + return result.Succeeded(); +} diff --git a/lldb/source/Commands/CommandObjectTranslate.h b/lldb/source/Commands/CommandObjectTranslate.h new file mode 100644 index 00000000000..efc3c8b4092 --- /dev/null +++ b/lldb/source/Commands/CommandObjectTranslate.h @@ -0,0 +1,44 @@ +//===-- CommandObjectTranslate.h --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectTranslate_h_ +#define liblldb_CommandObjectTranslate_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectTranslate +//------------------------------------------------------------------------- + +class CommandObjectTranslate : public CommandObject +{ +public: + + CommandObjectTranslate (); + + virtual + ~CommandObjectTranslate (); + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectTranslate_h_ diff --git a/lldb/source/Commands/CommandObjectUnalias.cpp b/lldb/source/Commands/CommandObjectUnalias.cpp new file mode 100644 index 00000000000..6c2f5085cf8 --- /dev/null +++ b/lldb/source/Commands/CommandObjectUnalias.cpp @@ -0,0 +1,87 @@ +//===-- CommandObjectUnalias.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectUnalias.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +//------------------------------------------------------------------------- +// CommandObjectUnalias +//------------------------------------------------------------------------- + +CommandObjectUnalias::CommandObjectUnalias () : + CommandObject ("unalias", + "Allows the user to remove/delete a user-defined command abbreviation.", + "unalias <alias-name-to-be-removed>") +{ +} + +CommandObjectUnalias::~CommandObjectUnalias() +{ +} + + +bool +CommandObjectUnalias::Execute (Args& args, CommandContext *context, CommandInterpreter *interpreter, + CommandReturnObject &result) +{ + CommandObject::CommandMap::iterator pos; + CommandObject *cmd_obj; + + if (args.GetArgumentCount() != 0) + { + const char *command_name = args.GetArgumentAtIndex(0); + cmd_obj = interpreter->GetCommandObject(command_name); + if (cmd_obj) + { + if (interpreter->CommandExists (command_name)) + { + result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n", + command_name); + result.SetStatus (eReturnStatusFailed); + } + else + { + + if (interpreter->RemoveAlias (command_name) == false) + { + if (interpreter->AliasExists (command_name)) + result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n", command_name); + else + result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name); + result.SetStatus (eReturnStatusFailed); + } + else + result.SetStatus (eReturnStatusSuccessFinishNoResult); + } + } + else + { + result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n", + command_name); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("must call 'unalias' with a valid alias"); + result.SetStatus (eReturnStatusFailed); + } + + return result.Succeeded(); +} + diff --git a/lldb/source/Commands/CommandObjectUnalias.h b/lldb/source/Commands/CommandObjectUnalias.h new file mode 100644 index 00000000000..5d1cafbcc71 --- /dev/null +++ b/lldb/source/Commands/CommandObjectUnalias.h @@ -0,0 +1,44 @@ +//===-- CommandObjectUnalias.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectUnalias_h_ +#define liblldb_CommandObjectUnalias_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectUnalias +//------------------------------------------------------------------------- + +class CommandObjectUnalias : public CommandObject +{ +public: + + CommandObjectUnalias (); + + virtual + ~CommandObjectUnalias (); + + virtual bool + Execute (Args& args, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result); + +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectUnalias_h_ diff --git a/lldb/source/Commands/CommandObjectVariable.cpp b/lldb/source/Commands/CommandObjectVariable.cpp new file mode 100644 index 00000000000..6bde4829be0 --- /dev/null +++ b/lldb/source/Commands/CommandObjectVariable.cpp @@ -0,0 +1,801 @@ +//===-- CommandObjectVariable.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectVariable.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Options.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectVariable.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Symbol/VariableList.h" + +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +//void +//DumpValueObjectValues (Stream *sout, const char *root_valobj_name, ValueObjectSP& valobj_sp, bool follow_ptrs_and_refs, uint32_t curr_depth, uint32_t max_depth) +//{ +// ValueObject *valobj = valobj_sp.get(); +// if (valobj) +// { +// const char *name_cstr = valobj->GetName().AsCString(NULL); +// const char *val_cstr = valobj->GetValueAsCString(); +// const char *loc_cstr = valobj->GetLocationAsCString(); +// const char *type_cstr = valobj->GetTypeName().AsCString(); +// const char *sum_cstr = valobj->GetSummaryAsCString(); +// const char *err_cstr = valobj->GetError().AsCString(); +// // Indent +// sout->Indent(); +// if (root_valobj_name) +// { +// sout->Printf ("%s = ", root_valobj_name); +// } +// +// if (name_cstr) +// sout->Printf ("%s => ", name_cstr); +// +// sout->Printf ("ValueObject{%u}", valobj->GetID()); +// const uint32_t num_children = valobj->GetNumChildren(); +// +// if (type_cstr) +// sout->Printf (", type = '%s'", type_cstr); +// +// if (loc_cstr) +// sout->Printf (", location = %s", loc_cstr); +// +// sout->Printf (", num_children = %u", num_children); +// +// if (val_cstr) +// sout->Printf (", value = %s", val_cstr); +// +// if (err_cstr) +// sout->Printf (", error = %s", err_cstr); +// +// if (sum_cstr) +// sout->Printf (", summary = %s", sum_cstr); +// +// sout->EOL(); +// bool is_ptr_or_ref = ClangASTContext::IsPointerOrReferenceType (valobj->GetOpaqueClangQualType()); +// if (!follow_ptrs_and_refs && is_ptr_or_ref) +// return; +// +// if (curr_depth < max_depth) +// { +// for (uint32_t idx=0; idx<num_children; ++idx) +// { +// ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true)); +// if (child_sp.get()) +// { +// sout->IndentMore(); +// DumpValueObjectValues (sout, NULL, child_sp, follow_ptrs_and_refs, curr_depth + 1, max_depth); +// sout->IndentLess(); +// } +// } +// } +// } +//} + +//---------------------------------------------------------------------- +// List images with associated information +//---------------------------------------------------------------------- +class CommandObjectVariableList : public CommandObject +{ +public: + + class CommandOptions : public Options + { + public: + + CommandOptions () : + Options() + { + ResetOptionValues (); + } + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (int option_idx, const char *option_arg) + { + Error error; + bool success; + char short_option = (char) m_getopt_table[option_idx].val; + switch (short_option) + { + case 'o': use_objc = true; break; + case 'n': name = option_arg; break; + case 'r': use_regex = true; break; + case 'a': show_args = false; break; + case 'l': show_locals = false; break; + case 'g': show_globals = false; break; + case 't': show_types = false; break; + case 'y': show_summary = false; break; + case 'L': show_location= true; break; + case 'D': debug = true; break; + case 'd': + max_depth = Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success); + if (!success) + error.SetErrorStringWithFormat("Invalid max depth '%s'.\n", option_arg); + break; + + case 'p': + ptr_depth = Args::StringToUInt32 (option_arg, 0, 0, &success); + if (!success) + error.SetErrorStringWithFormat("Invalid pointer depth '%s'.\n", option_arg); + break; + + case 'G': + { + ConstString const_string (option_arg); + globals.push_back(const_string); + } + break; + + case 's': + show_scope = true; + break; + + default: + error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); + break; + } + + return error; + } + + void + ResetOptionValues () + { + Options::ResetOptionValues(); + + name.clear(); + use_objc = false; + use_regex = false; + show_args = true; + show_locals = true; + show_globals = true; + show_types = true; + show_scope = false; + show_summary = true; + show_location = false; + debug = false; + max_depth = UINT32_MAX; + ptr_depth = 0; + globals.clear(); + } + + const lldb::OptionDefinition* + GetDefinitions () + { + return g_option_table; + } + + // Options table: Required for subclasses of Options. + + static lldb::OptionDefinition g_option_table[]; + std::string name; + bool use_objc; + bool use_regex; + bool show_args; + bool show_locals; + bool show_globals; + bool show_types; + bool show_scope; // local/arg/global/static + bool show_summary; + bool show_location; + bool debug; + uint32_t max_depth; // The depth to print when dumping concrete (not pointers) aggreate values + uint32_t ptr_depth; // The default depth that is dumped when we find pointers + std::vector<ConstString> globals; + // Instance variables to hold the values for command options. + }; + + CommandObjectVariableList () : + CommandObject ( + "variable list", + "Show specified argument, local variable, static variable or global variable. If none specified, list them all.", + "variable list [<cmd-options>] [<var-name1> [<var-name2>...]]") + { + } + + virtual + ~CommandObjectVariableList () + { + } + + virtual + Options * + GetOptions () + { + return &m_options; + } + + void + DumpVariable (CommandReturnObject &result, ExecutionContext *exe_ctx, Variable *variable) + { + if (variable) + { + Stream &s = result.GetOutputStream(); + DWARFExpression &expr = variable->LocationExpression(); + Value expr_result; + Error expr_error; + Type *variable_type = variable->GetType(); + bool expr_success = expr.Evaluate(exe_ctx, NULL, NULL, expr_result, &expr_error); + + if (m_options.debug) + s.Printf ("Variable{0x%8.8x}: ", variable->GetID()); + + if (!expr_success) + s.Printf ("%s = ERROR (%s)", variable->GetName().AsCString(NULL), expr_error.AsCString()); + else + { + Value::ValueType expr_value_type = expr_result.GetValueType(); + switch (expr_value_type) + { + case Value::eValueTypeScalar: + s.Printf ("%s = ", variable->GetName().AsCString(NULL)); + if (variable_type) + { + DataExtractor data; + if (expr_result.ResolveValue (exe_ctx, NULL).GetData (data)) + variable_type->DumpValue (exe_ctx, &s, data, 0, m_options.show_types, m_options.show_summary, m_options.debug); + } + break; + + case Value::eValueTypeFileAddress: + case Value::eValueTypeLoadAddress: + case Value::eValueTypeHostAddress: + { + s.Printf ("%s = ", variable->GetName().AsCString(NULL)); + lldb::addr_t addr = LLDB_INVALID_ADDRESS; + lldb::AddressType addr_type = eAddressTypeLoad; + + if (expr_value_type == Value::eValueTypeFileAddress) + { + lldb::addr_t file_addr = expr_result.ResolveValue (exe_ctx, NULL).ULongLong(LLDB_INVALID_ADDRESS); + SymbolContext var_sc; + variable->CalculateSymbolContext(&var_sc); + if (var_sc.module_sp) + { + ObjectFile *objfile = var_sc.module_sp->GetObjectFile(); + if (objfile) + { + Address so_addr(file_addr, objfile->GetSectionList()); + addr = so_addr.GetLoadAddress(exe_ctx->process); + } + if (addr == LLDB_INVALID_ADDRESS) + { + result.GetErrorStream().Printf ("error: %s is not loaded", var_sc.module_sp->GetFileSpec().GetFilename().AsCString()); + } + } + else + { + result.GetErrorStream().Printf ("error: unable to resolve the variable address 0x%llx", file_addr); + } + } + else + { + if (expr_value_type == Value::eValueTypeHostAddress) + addr_type = eAddressTypeHost; + addr = expr_result.ResolveValue (exe_ctx, NULL).ULongLong(LLDB_INVALID_ADDRESS); + } + + if (addr != LLDB_INVALID_ADDRESS) + { + if (m_options.debug) + s.Printf("@ 0x%8.8llx, value = ", addr); + variable_type->DumpValueInMemory (exe_ctx, &s, addr, addr_type, m_options.show_types, m_options.show_summary, m_options.debug); + } + } + break; + } + } + s.EOL(); + } + } + + void + DumpValueObject (CommandReturnObject &result, + ExecutionContextScope *exe_scope, + ValueObject *valobj, + const char *root_valobj_name, + uint32_t ptr_depth, + uint32_t curr_depth, + uint32_t max_depth, + bool use_objc) + { + if (valobj) + { + Stream &s = result.GetOutputStream(); + + //const char *loc_cstr = valobj->GetLocationAsCString(); + if (m_options.show_location) + { + s.Printf("@ %s: ", valobj->GetLocationAsCString(exe_scope)); + } + if (m_options.debug) + s.Printf ("%p ValueObject{%u} ", valobj, valobj->GetID()); + + s.Indent(); + + if (m_options.show_types) + s.Printf("(%s) ", valobj->GetTypeName().AsCString()); + + const char *name_cstr = root_valobj_name ? root_valobj_name : valobj->GetName().AsCString(""); + s.Printf ("%s = ", name_cstr); + + const char *val_cstr = valobj->GetValueAsCString(exe_scope); + const char *err_cstr = valobj->GetError().AsCString(); + + if (err_cstr) + { + s.Printf ("error: %s\n", err_cstr); + } + else + { + const char *sum_cstr = valobj->GetSummaryAsCString(exe_scope); + + const bool is_aggregate = ClangASTContext::IsAggregateType (valobj->GetOpaqueClangQualType()); + + if (val_cstr) + s.PutCString(val_cstr); + + if (sum_cstr) + s.Printf(" %s", sum_cstr); + + if (use_objc) + { + if (!ClangASTContext::IsPointerType (valobj->GetOpaqueClangQualType())) + return; + + if (!valobj->GetValueIsValid()) + return; + + Process *process = exe_scope->CalculateProcess(); + + if (!process) + return; + + Scalar scalar; + + if (!Type::GetValueAsScalar (valobj->GetClangAST(), + valobj->GetOpaqueClangQualType(), + valobj->GetDataExtractor(), + 0, + valobj->GetByteSize(), + scalar)) + return; + + ConstString po_output; + + ExecutionContext exe_ctx; + exe_scope->Calculate(exe_ctx); + + Value val(scalar); + val.SetContext(Value::eContextTypeOpaqueClangQualType, + ClangASTContext::GetVoidPtrType(valobj->GetClangAST(), false)); + + if (!process->GetObjCObjectPrinter().PrintObject(po_output, val, exe_ctx)) + return; + + s.Printf("\n%s\n", po_output.GetCString()); + + return; + } + + + if (curr_depth < max_depth) + { + if (is_aggregate) + s.PutChar('{'); + + bool is_ptr_or_ref = ClangASTContext::IsPointerOrReferenceType (valobj->GetOpaqueClangQualType()); + + if (is_ptr_or_ref && ptr_depth == 0) + return; + + const uint32_t num_children = valobj->GetNumChildren(); + if (num_children) + { + s.IndentMore(); + for (uint32_t idx=0; idx<num_children; ++idx) + { + ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true)); + if (child_sp.get()) + { + s.EOL(); + DumpValueObject (result, + exe_scope, + child_sp.get(), + NULL, + is_ptr_or_ref ? ptr_depth - 1 : ptr_depth, + curr_depth + 1, + max_depth, + false); + if (idx + 1 < num_children) + s.PutChar(','); + } + } + s.IndentLess(); + } + if (is_aggregate) + { + s.EOL(); + s.Indent("}"); + } + } + else + { + if (is_aggregate) + { + s.PutCString("{...}"); + } + } + + } + } + } + + virtual bool + Execute (Args& command, + CommandContext *context, + CommandInterpreter *interpreter, + CommandReturnObject &result) + { + ExecutionContext exe_ctx(context->GetExecutionContext()); + if (exe_ctx.frame == NULL) + { + result.AppendError ("invalid frame"); + result.SetStatus (eReturnStatusFailed); + return false; + } + else + { + VariableList variable_list; + + SymbolContext frame_sc = exe_ctx.frame->GetSymbolContext (eSymbolContextEverything); + if (exe_ctx.frame && frame_sc.block) + frame_sc.block->AppendVariables(true, true, &variable_list); + VariableSP var_sp; + ValueObjectSP valobj_sp; + //ValueObjectList &valobj_list = exe_ctx.frame->GetValueObjectList(); + const char *name_cstr = NULL; + size_t idx; + if (!m_options.globals.empty()) + { + uint32_t fail_count = 0; + Target *target = context->GetTarget(); + if (target) + { + const size_t num_globals = m_options.globals.size(); + for (idx = 0; idx < num_globals; ++idx) + { + VariableList global_var_list; + const uint32_t num_matching_globals = target->GetImages().FindGlobalVariables (m_options.globals[idx], true, UINT32_MAX, global_var_list); + + if (num_matching_globals == 0) + { + ++fail_count; + result.GetErrorStream().Printf ("error: can't find global variable '%s'\n", m_options.globals[idx].AsCString()); + } + else + { + for (uint32_t global_idx=0; global_idx<num_matching_globals; ++global_idx) + { + var_sp = global_var_list.GetVariableAtIndex(global_idx); + if (var_sp) + { + valobj_sp = exe_ctx.frame->GetValueObjectList().FindValueObjectByValueName (m_options.globals[idx].AsCString()); + if (!valobj_sp) + valobj_sp.reset (new ValueObjectVariable (var_sp)); + + if (valobj_sp) + { + exe_ctx.frame->GetValueObjectList().Append (valobj_sp); + DumpValueObject (result, exe_ctx.frame, valobj_sp.get(), name_cstr, m_options.ptr_depth, 0, m_options.max_depth, false); + result.GetOutputStream().EOL(); + } + } + } + } + } + } + if (fail_count) + { + result.SetStatus (eReturnStatusFailed); + } + } + + if (command.GetArgumentCount() > 0) + { + // If we have any args to the variable command, we will make + // variable objects from them... + for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx) + { + uint32_t ptr_depth = m_options.ptr_depth; + // If first character is a '*', then show pointer contents + if (name_cstr[0] == '*') + { + ++ptr_depth; + name_cstr++; // Skip the '*' + } + + std::string var_path (name_cstr); + size_t separator_idx = var_path.find_first_of(".-["); + + ConstString name_const_string; + if (separator_idx == std::string::npos) + name_const_string.SetCString (var_path.c_str()); + else + name_const_string.SetCStringWithLength (var_path.c_str(), separator_idx); + + var_sp = variable_list.FindVariable(name_const_string); + if (var_sp) + { + //DumpVariable (result, &exe_ctx, var_sp.get()); + // TODO: redo history variables using a different map +// if (var_path[0] == '$') +// valobj_sp = valobj_list.FindValueObjectByValueObjectName (name_const_string.GetCString()); +// else + valobj_sp = exe_ctx.frame->GetValueObjectList().FindValueObjectByValueName (name_const_string.GetCString()); + + if (!valobj_sp) + { + valobj_sp.reset (new ValueObjectVariable (var_sp)); + exe_ctx.frame->GetValueObjectList().Append (valobj_sp); + } + + var_path.erase (0, name_const_string.GetLength ()); + // We are dumping at least one child + while (separator_idx != std::string::npos) + { + // Calculate the next separator index ahead of time + ValueObjectSP child_valobj_sp; + const char separator_type = var_path[0]; + switch (separator_type) + { + + case '-': + if (var_path.size() >= 2 && var_path[1] != '>') + { + result.GetErrorStream().Printf ("error: invalid character in variable path starting at '%s'\n", + var_path.c_str()); + var_path.clear(); + valobj_sp.reset(); + break; + } + var_path.erase (0, 1); // Remove the '-' + // Fall through + case '.': + { + var_path.erase (0, 1); // Remove the '.' or '>' + separator_idx = var_path.find_first_of(".-["); + ConstString child_name; + if (separator_idx == std::string::npos) + child_name.SetCString (var_path.c_str()); + else + child_name.SetCStringWithLength(var_path.c_str(), separator_idx); + + child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true); + if (!child_valobj_sp) + { + result.GetErrorStream().Printf ("error: can't find child of '%s' named '%s'\n", + valobj_sp->GetName().AsCString(), + child_name.GetCString()); + var_path.clear(); + valobj_sp.reset(); + break; + } + // Remove the child name from the path + var_path.erase(0, child_name.GetLength()); + } + break; + + case '[': + // Array member access, or treating pointer as an array + if (var_path.size() > 2) // Need at least two brackets and a number + { + char *end = NULL; + int32_t child_index = ::strtol (&var_path[1], &end, 0); + if (end && *end == ']') + { + + if (valobj_sp->IsPointerType ()) + { + child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true); + } + else + { + child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true); + } + + if (!child_valobj_sp) + { + result.GetErrorStream().Printf ("error: invalid array index %u in '%s'\n", + child_index, + valobj_sp->GetName().AsCString()); + var_path.clear(); + valobj_sp.reset(); + break; + } + + // Erase the array member specification '[%i]' where %i is the array index + var_path.erase(0, (end - var_path.c_str()) + 1); + separator_idx = var_path.find_first_of(".-["); + + // Break out early from the switch since we were able to find the child member + break; + } + } + result.GetErrorStream().Printf ("error: invalid array member specification for '%s' starting at '%s'\n", + valobj_sp->GetName().AsCString(), + var_path.c_str()); + var_path.clear(); + valobj_sp.reset(); + break; + + break; + + default: + result.GetErrorStream().Printf ("error: invalid character in variable path starting at '%s'\n", + var_path.c_str()); + var_path.clear(); + valobj_sp.reset(); + separator_idx = std::string::npos; + break; + } + + if (child_valobj_sp) + valobj_sp = child_valobj_sp; + + if (var_path.empty()) + break; + + } + + if (valobj_sp) + { + DumpValueObject (result, exe_ctx.frame, valobj_sp.get(), name_cstr, ptr_depth, 0, m_options.max_depth, m_options.use_objc); + result.GetOutputStream().EOL(); + } + } + else + { + result.GetErrorStream().Printf ("error: unable to find any variables named '%s'\n", name_cstr); + var_path.clear(); + } + } + } + else + { + + if (m_options.show_globals) + { + if (frame_sc.comp_unit) + { + variable_list.AddVariables (frame_sc.comp_unit->GetVariableList(true).get()); + } + } + + const uint32_t num_variables = variable_list.GetSize(); + + if (num_variables > 0) + { + for (uint32_t i=0; i<num_variables; i++) + { + Variable *variable = variable_list.GetVariableAtIndex(i).get(); + bool dump_variable = true; + + switch (variable->GetScope()) + { + case eValueTypeVariableGlobal: + dump_variable = m_options.show_globals; + if (dump_variable && m_options.show_scope) + result.GetOutputStream().PutCString("GLOBAL: "); + break; + + case eValueTypeVariableStatic: + dump_variable = m_options.show_globals; + if (dump_variable && m_options.show_scope) + result.GetOutputStream().PutCString("STATIC: "); + break; + + case eValueTypeVariableArgument: + dump_variable = m_options.show_args; + if (dump_variable && m_options.show_scope) + result.GetOutputStream().PutCString(" ARG: "); + break; + + case eValueTypeVariableLocal: + dump_variable = m_options.show_locals; + if (dump_variable && m_options.show_scope) + result.GetOutputStream().PutCString(" LOCAL: "); + break; + + default: + break; + } + + if (dump_variable) + DumpVariable (result, &exe_ctx, variable); + } + } + } + result.SetStatus (eReturnStatusSuccessFinishResult); + } + return result.Succeeded(); + } +protected: + + CommandOptions m_options; +}; + +lldb::OptionDefinition +CommandObjectVariableList::CommandOptions::g_option_table[] = +{ +{ 0, false, "debug", 'D', no_argument, NULL, 0, NULL, "Show verbose debug information."}, +{ 0, false, "depth", 'd', required_argument, NULL, 0, "<count>", "Set the max recurse depth when dumping aggregate types (default is infinity)."}, +{ 0, false, "globals", 'g', no_argument, NULL, 0, NULL, "List global and static variables for the current stack frame source file."}, +{ 0, false, "global", 'G', required_argument, NULL, 0, NULL, "Find a global variable by name (which might not be in the current stack frame source file)."}, +{ 0, false, "location", 'L', no_argument, NULL, 0, NULL, "Show variable location information."}, +{ 0, false, "name", 'n', required_argument, NULL, 0, "<name>", "Lookup a variable by name or regex (--regex) for the current execution context."}, +{ 0, false, "no-args", 'a', no_argument, NULL, 0, NULL, "Omit function arguments."}, +{ 0, false, "no-locals", 'l', no_argument, NULL, 0, NULL, "Omit local variables."}, +{ 0, false, "no-types", 't', no_argument, NULL, 0, NULL, "Omit variable type names."}, +{ 0, false, "no-summary", 'y', no_argument, NULL, 0, NULL, "Omit summary information."}, +{ 0, false, "scope", 's', no_argument, NULL, 0, NULL, "Show variable scope (argument, local, global, static)."}, +{ 0, false, "objc", 'o', no_argument, NULL, 0, NULL, "When looking up a variable by name (--name), print as an Objective-C object."}, +{ 0, false, "ptr-depth", 'p', required_argument, NULL, 0, "<count>", "The number of pointers to be traversed when dumping values (default is zero)."}, +{ 0, false, "regex", 'r', no_argument, NULL, 0, NULL, "The <name> argument for name lookups are regular expressions."}, +{ 0, false, NULL, 0, 0, NULL, NULL, NULL, NULL } +}; + +//---------------------------------------------------------------------- +// CommandObjectVariable constructor +//---------------------------------------------------------------------- +CommandObjectVariable::CommandObjectVariable(CommandInterpreter *interpreter) : + CommandObjectMultiword ("variable", + "Access program arguments, locals, static and global variables.", + "variable [list] ...") +{ + LoadSubCommand (CommandObjectSP (new CommandObjectVariableList ()), "list", interpreter); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CommandObjectVariable::~CommandObjectVariable() +{ +} + + + + diff --git a/lldb/source/Commands/CommandObjectVariable.h b/lldb/source/Commands/CommandObjectVariable.h new file mode 100644 index 00000000000..65869c73d72 --- /dev/null +++ b/lldb/source/Commands/CommandObjectVariable.h @@ -0,0 +1,43 @@ +//===-- CommandObjectVariable.h ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandObjectVariable_h_ +#define liblldb_CommandObjectVariable_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +//------------------------------------------------------------------------- +// CommandObjectImage +//------------------------------------------------------------------------- + +class CommandObjectVariable : public CommandObjectMultiword +{ +public: + + CommandObjectVariable (CommandInterpreter *iterpreter); + + virtual + ~CommandObjectVariable (); + +private: + //------------------------------------------------------------------ + // For CommandObjectVariable only + //------------------------------------------------------------------ + DISALLOW_COPY_AND_ASSIGN (CommandObjectVariable); +}; + +} // namespace lldb_private + +#endif // liblldb_CommandObjectVariable_h_ |