blob: 89cc161993a9fb4a27c3a9656bdd42aad828b7ab [file] [log] [blame]
//===-- CommandObject.h -----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_INTERPRETER_COMMANDOBJECT_H
#define LLDB_INTERPRETER_COMMANDOBJECT_H
#include <map>
#include <string>
#include <vector>
#include "lldb/Utility/Flags.h"
#include "lldb/Interpreter/CommandCompletions.h"
#include "lldb/Interpreter/Options.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Utility/Args.h"
#include "lldb/Utility/CompletionRequest.h"
#include "lldb/Utility/StringList.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
// This function really deals with CommandObjectLists, but we didn't make a
// CommandObjectList class, so I'm sticking it here. But we really should have
// such a class. Anyway, it looks up the commands in the map that match the
// partial string cmd_str, inserts the matches into matches, and returns the
// number added.
template <typename ValueType>
int AddNamesMatchingPartialString(
const std::map<std::string, ValueType> &in_map, llvm::StringRef cmd_str,
StringList &matches, StringList *descriptions = nullptr) {
int number_added = 0;
const bool add_all = cmd_str.empty();
for (auto iter = in_map.begin(), end = in_map.end(); iter != end; iter++) {
if (add_all || (iter->first.find(std::string(cmd_str), 0) == 0)) {
++number_added;
matches.AppendString(iter->first.c_str());
if (descriptions)
descriptions->AppendString(iter->second->GetHelp());
}
}
return number_added;
}
template <typename ValueType>
size_t FindLongestCommandWord(std::map<std::string, ValueType> &dict) {
auto end = dict.end();
size_t max_len = 0;
for (auto pos = dict.begin(); pos != end; ++pos) {
size_t len = pos->first.size();
if (max_len < len)
max_len = len;
}
return max_len;
}
class CommandObject {
public:
typedef llvm::StringRef(ArgumentHelpCallbackFunction)();
struct ArgumentHelpCallback {
ArgumentHelpCallbackFunction *help_callback;
bool self_formatting;
llvm::StringRef operator()() const { return (*help_callback)(); }
explicit operator bool() const { return (help_callback != nullptr); }
};
struct ArgumentTableEntry // Entries in the main argument information table
{
lldb::CommandArgumentType arg_type;
const char *arg_name;
CommandCompletions::CommonCompletionTypes completion_type;
ArgumentHelpCallback help_function;
const char *help_text;
};
struct CommandArgumentData // Used to build individual command argument lists
{
lldb::CommandArgumentType arg_type;
ArgumentRepetitionType arg_repetition;
/// This arg might be associated only with some particular option set(s). By
/// default the arg associates to all option sets.
uint32_t arg_opt_set_association;
CommandArgumentData(lldb::CommandArgumentType type = lldb::eArgTypeNone,
ArgumentRepetitionType repetition = eArgRepeatPlain,
uint32_t opt_set = LLDB_OPT_SET_ALL)
: arg_type(type), arg_repetition(repetition),
arg_opt_set_association(opt_set) {}
};
typedef std::vector<CommandArgumentData>
CommandArgumentEntry; // Used to build individual command argument lists
static ArgumentTableEntry g_arguments_data
[lldb::eArgTypeLastArg]; // Main argument information table
typedef std::map<std::string, lldb::CommandObjectSP> CommandMap;
CommandObject(CommandInterpreter &interpreter, llvm::StringRef name,
llvm::StringRef help = "", llvm::StringRef syntax = "",
uint32_t flags = 0);
virtual ~CommandObject() = default;
static const char *
GetArgumentTypeAsCString(const lldb::CommandArgumentType arg_type);
static const char *
GetArgumentDescriptionAsCString(const lldb::CommandArgumentType arg_type);
CommandInterpreter &GetCommandInterpreter() { return m_interpreter; }
Debugger &GetDebugger();
virtual llvm::StringRef GetHelp();
virtual llvm::StringRef GetHelpLong();
virtual llvm::StringRef GetSyntax();
llvm::StringRef GetCommandName() const;
virtual void SetHelp(llvm::StringRef str);
virtual void SetHelpLong(llvm::StringRef str);
void SetSyntax(llvm::StringRef str);
// override this to return true if you want to enable the user to delete the
// Command object from the Command dictionary (aliases have their own
// deletion scheme, so they do not need to care about this)
virtual bool IsRemovable() const { return false; }
virtual bool IsMultiwordObject() { return false; }
bool IsUserCommand() { return m_is_user_command; }
void SetIsUserCommand(bool is_user) { m_is_user_command = is_user; }
virtual CommandObjectMultiword *GetAsMultiwordCommand() { return nullptr; }
virtual bool IsAlias() { return false; }
// override this to return true if your command is somehow a "dash-dash" form
// of some other command (e.g. po is expr -O --); this is a powerful hint to
// the help system that one cannot pass options to this command
virtual bool IsDashDashCommand() { return false; }
virtual lldb::CommandObjectSP GetSubcommandSP(llvm::StringRef sub_cmd,
StringList *matches = nullptr) {
return lldb::CommandObjectSP();
}
virtual lldb::CommandObjectSP GetSubcommandSPExact(llvm::StringRef sub_cmd) {
return lldb::CommandObjectSP();
}
virtual CommandObject *GetSubcommandObject(llvm::StringRef sub_cmd,
StringList *matches = nullptr) {
return nullptr;
}
virtual void AproposAllSubCommands(llvm::StringRef prefix,
llvm::StringRef search_word,
StringList &commands_found,
StringList &commands_help) {}
void FormatLongHelpText(Stream &output_strm, llvm::StringRef long_help);
void GenerateHelpText(CommandReturnObject &result);
virtual void GenerateHelpText(Stream &result);
// this is needed in order to allow the SBCommand class to transparently try
// and load subcommands - it will fail on anything but a multiword command,
// but it avoids us doing type checkings and casts
virtual bool LoadSubCommand(llvm::StringRef cmd_name,
const lldb::CommandObjectSP &command_obj) {
return false;
}
virtual llvm::Error LoadUserSubcommand(llvm::StringRef cmd_name,
const lldb::CommandObjectSP &command_obj,
bool can_replace) {
return llvm::createStringError(llvm::inconvertibleErrorCode(),
"can only add commands to container commands");
}
virtual bool WantsRawCommandString() = 0;
// By default, WantsCompletion = !WantsRawCommandString. Subclasses who want
// raw command string but desire, for example, argument completion should
// override this method to return true.
virtual bool WantsCompletion() { return !WantsRawCommandString(); }
virtual Options *GetOptions();
static const ArgumentTableEntry *GetArgumentTable();
static lldb::CommandArgumentType LookupArgumentName(llvm::StringRef arg_name);
static const ArgumentTableEntry *
FindArgumentDataByType(lldb::CommandArgumentType arg_type);
int GetNumArgumentEntries();
CommandArgumentEntry *GetArgumentEntryAtIndex(int idx);
static void GetArgumentHelp(Stream &str, lldb::CommandArgumentType arg_type,
CommandInterpreter &interpreter);
static const char *GetArgumentName(lldb::CommandArgumentType arg_type);
// Generates a nicely formatted command args string for help command output.
// By default, all possible args are taken into account, for example, '<expr
// | variable-name>'. This can be refined by passing a second arg specifying
// which option set(s) we are interested, which could then, for example,
// produce either '<expr>' or '<variable-name>'.
void GetFormattedCommandArguments(Stream &str,
uint32_t opt_set_mask = LLDB_OPT_SET_ALL);
bool IsPairType(ArgumentRepetitionType arg_repeat_type);
bool ParseOptions(Args &args, CommandReturnObject &result);
void SetCommandName(llvm::StringRef name);
/// This default version handles calling option argument completions and then
/// calls HandleArgumentCompletion if the cursor is on an argument, not an
/// option. Don't override this method, override HandleArgumentCompletion
/// instead unless you have special reasons.
///
/// \param[in,out] request
/// The completion request that needs to be answered.
virtual void HandleCompletion(CompletionRequest &request);
/// The input array contains a parsed version of the line.
///
/// We've constructed the map of options and their arguments as well if that
/// is helpful for the completion.
///
/// \param[in,out] request
/// The completion request that needs to be answered.
virtual void
HandleArgumentCompletion(CompletionRequest &request,
OptionElementVector &opt_element_vector) {}
bool HelpTextContainsWord(llvm::StringRef search_word,
bool search_short_help = true,
bool search_long_help = true,
bool search_syntax = true,
bool search_options = true);
/// The flags accessor.
///
/// \return
/// A reference to the Flags member variable.
Flags &GetFlags() { return m_flags; }
/// The flags const accessor.
///
/// \return
/// A const reference to the Flags member variable.
const Flags &GetFlags() const { return m_flags; }
/// Get the command that appropriate for a "repeat" of the current command.
///
/// \param[in] current_command_args
/// The command arguments.
///
/// \return
/// nullptr if there is no special repeat command - it will use the
/// current command line.
/// Otherwise a pointer to the command to be repeated.
/// If the returned string is the empty string, the command won't be
/// repeated.
virtual const char *GetRepeatCommand(Args &current_command_args,
uint32_t index) {
return nullptr;
}
bool HasOverrideCallback() const {
return m_command_override_callback ||
m_deprecated_command_override_callback;
}
void SetOverrideCallback(lldb::CommandOverrideCallback callback,
void *baton) {
m_deprecated_command_override_callback = callback;
m_command_override_baton = baton;
}
void SetOverrideCallback(lldb::CommandOverrideCallbackWithResult callback,
void *baton) {
m_command_override_callback = callback;
m_command_override_baton = baton;
}
bool InvokeOverrideCallback(const char **argv, CommandReturnObject &result) {
if (m_command_override_callback)
return m_command_override_callback(m_command_override_baton, argv,
result);
else if (m_deprecated_command_override_callback)
return m_deprecated_command_override_callback(m_command_override_baton,
argv);
else
return false;
}
virtual bool Execute(const char *args_string,
CommandReturnObject &result) = 0;
protected:
bool ParseOptionsAndNotify(Args &args, CommandReturnObject &result,
OptionGroupOptions &group_options,
ExecutionContext &exe_ctx);
virtual const char *GetInvalidTargetDescription() {
return "invalid target, create a target using the 'target create' command";
}
virtual const char *GetInvalidProcessDescription() {
return "invalid process";
}
virtual const char *GetInvalidThreadDescription() { return "invalid thread"; }
virtual const char *GetInvalidFrameDescription() { return "invalid frame"; }
virtual const char *GetInvalidRegContextDescription() {
return "invalid frame, no registers";
}
// This is for use in the command interpreter, when you either want the
// selected target, or if no target is present you want to prime the dummy
// target with entities that will be copied over to new targets.
Target &GetSelectedOrDummyTarget(bool prefer_dummy = false);
Target &GetSelectedTarget();
Target &GetDummyTarget();
// If a command needs to use the "current" thread, use this call. Command
// objects will have an ExecutionContext to use, and that may or may not have
// a thread in it. If it does, you should use that by default, if not, then
// use the ExecutionContext's target's selected thread, etc... This call
// insulates you from the details of this calculation.
Thread *GetDefaultThread();
/// Check the command to make sure anything required by this
/// command is available.
///
/// \param[out] result
/// A command result object, if it is not okay to run the command
/// this will be filled in with a suitable error.
///
/// \return
/// \b true if it is okay to run this command, \b false otherwise.
bool CheckRequirements(CommandReturnObject &result);
void Cleanup();
CommandInterpreter &m_interpreter;
ExecutionContext m_exe_ctx;
std::unique_lock<std::recursive_mutex> m_api_locker;
std::string m_cmd_name;
std::string m_cmd_help_short;
std::string m_cmd_help_long;
std::string m_cmd_syntax;
Flags m_flags;
std::vector<CommandArgumentEntry> m_arguments;
lldb::CommandOverrideCallback m_deprecated_command_override_callback;
lldb::CommandOverrideCallbackWithResult m_command_override_callback;
void *m_command_override_baton;
bool m_is_user_command = false;
// Helper function to populate IDs or ID ranges as the command argument data
// to the specified command argument entry.
static void AddIDsArgumentData(CommandArgumentEntry &arg,
lldb::CommandArgumentType ID,
lldb::CommandArgumentType IDRange);
};
class CommandObjectParsed : public CommandObject {
public:
CommandObjectParsed(CommandInterpreter &interpreter, const char *name,
const char *help = nullptr, const char *syntax = nullptr,
uint32_t flags = 0)
: CommandObject(interpreter, name, help, syntax, flags) {}
~CommandObjectParsed() override = default;
bool Execute(const char *args_string, CommandReturnObject &result) override;
protected:
virtual bool DoExecute(Args &command, CommandReturnObject &result) = 0;
bool WantsRawCommandString() override { return false; }
};
class CommandObjectRaw : public CommandObject {
public:
CommandObjectRaw(CommandInterpreter &interpreter, llvm::StringRef name,
llvm::StringRef help = "", llvm::StringRef syntax = "",
uint32_t flags = 0)
: CommandObject(interpreter, name, help, syntax, flags) {}
~CommandObjectRaw() override = default;
bool Execute(const char *args_string, CommandReturnObject &result) override;
protected:
virtual bool DoExecute(llvm::StringRef command,
CommandReturnObject &result) = 0;
bool WantsRawCommandString() override { return true; }
};
} // namespace lldb_private
#endif // LLDB_INTERPRETER_COMMANDOBJECT_H