blob: a1a3b244f756583b91cb812dc45afa210de9ab7f [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_CONSOLE_COMMAND_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_CONSOLE_COMMAND_H_
#include <lib/syslog/cpp/macros.h>
#include <initializer_list>
#include <map>
#include <string>
#include <vector>
#include "lib/fit/function.h"
#include "src/developer/debug/zxdb/common/err.h"
#include "src/developer/debug/zxdb/console/nouns.h"
#include "src/developer/debug/zxdb/console/verbs.h"
namespace zxdb {
class Breakpoint;
struct CommandReport;
class ConsoleContext;
class Filter;
class Frame;
class Target;
class Thread;
class SymbolServer;
// Command ---------------------------------------------------------------------
class Command {
public:
// This valid indicates that there was a noun specified but no index.
// For example the command "process step" specifies the process noun but
// not an index.
static constexpr int kNoIndex = -1;
// This indicates the operation should be done for all instances of this noun. Typically, this is
// used to remove all filters or breakpoints, or detach from all processes. Typical use is like:
// filter * rm
static constexpr int kWildcard = -2;
Command();
~Command();
// Returns true if the noun was specified by the user.
bool HasNoun(Noun noun) const;
// Returns the index specified for the given noun. If the noun was not
// specified or the index was not specified, returns kNoIndex (use HasNoun to
// disambiguate).
int GetNounIndex(Noun noun) const;
// Sets that the given noun was present. index may be kNoIndex.
void SetNoun(Noun noun, int index);
const std::map<Noun, int>& nouns() const { return nouns_; }
// Checks the specified nouns against the parameter listing the allowed ones.
// If any nouns are specified that are not in the list, generates an error and
// returns it. If |allow_wildcard| is false, and a wildcard specifier is
// present, will generate an appropriate error message. Otherwise it will
// return an empty error.
Err ValidateNouns(std::initializer_list<Noun> allowed_nouns, bool allow_wildcard = false) const;
Verb verb() const { return verb_; }
void set_verb(Verb v) { verb_ = v; }
// Returns whether a given switch was specified.
bool HasSwitch(int id) const;
// Returns the value corresponding to the given switch, or the empty string
// if not specified.
std::string GetSwitchValue(int id) const;
void SetSwitch(int id, std::string str);
const std::map<int, std::string>& switches() const { return switches_; }
const std::vector<std::string>& args() const { return args_; }
void set_args(std::vector<std::string> a) { args_ = std::move(a); }
// The computed environment for the command. This is filled in with the
// objects corresponding to the indices given on the command line, and
// default to the current one for the current command line.
//
// If |HasNoun()| returns true, the corresponding getter here is guaranteed to
// be non-null or have size() > 0. Most commands are interacting with a single
// noun, so there are convenience getters for when only a single object is
// needed/expected. These will only work when there is exactly one instance of
// that noun associated with this command.
Frame* frame() const { return frames_.size() == 1 ? frames_[0] : nullptr; }
const std::vector<Frame*>& all_frames() const { return frames_; }
void add_frame(Frame* f) { frames_.push_back(f); }
Target* target() const {
// Enforce at least one target exists.
FX_DCHECK(!targets_.empty());
return targets_[0];
}
const std::vector<Target*>& all_targets() const { return targets_; }
void add_target(Target* t) { targets_.push_back(t); }
Thread* thread() const { return threads_.size() == 1 ? threads_[0] : nullptr; }
const std::vector<Thread*>& all_threads() const { return threads_; }
void add_thread(Thread* t) { threads_.push_back(t); }
Breakpoint* breakpoint() const { return breakpoints_.size() == 1 ? breakpoints_[0] : nullptr; }
const std::vector<Breakpoint*>& all_breakpoints() const { return breakpoints_; }
void add_breakpoint(Breakpoint* b) { breakpoints_.push_back(b); }
Filter* filter() const { return filters_.size() == 1 ? filters_[0] : nullptr; }
const std::vector<Filter*>& all_filters() const { return filters_; }
void add_filter(Filter* f) { filters_.push_back(f); }
SymbolServer* sym_server() const {
return symbol_servers_.size() == 1 ? symbol_servers_[0] : nullptr;
}
const std::vector<SymbolServer*>& all_sym_servers() const { return symbol_servers_; }
void add_sym_server(SymbolServer* s) { symbol_servers_.push_back(s); }
CommandReport BuildReport() const;
private:
void AddNounsToCommandReport(CommandReport& report) const;
void AddArgsToCommandReport(CommandReport& report) const;
void AddSwitchesToCommandReport(CommandReport& report) const;
// The nouns specified for this command. If not present here, the noun was not
// written on the command line. If present but there was no index given for
// it, the mapped value will be kNoIndex. Wildcards are represented as
// |kWildcard|. Otherwise the mapped value will be the index specified.
std::map<Noun, int> nouns_;
// The effective context for the command. The explicitly specified process(es)/
// thread(s)/etc. will be reflected here, and anything that wasn't explicit
// will inherit the default.
std::vector<Target*> targets_; // Guaranteed non-empty for valid commands.
std::vector<Thread*> threads_; // Will be empty if not running.
std::vector<Frame*> frames_; // Will be empty if no valid thread stopped.
std::vector<Breakpoint*> breakpoints_; // May be empty.
std::vector<Filter*> filters_; // May be empty.
std::vector<SymbolServer*> symbol_servers_; // May be empty.
Verb verb_ = Verb::kNone;
std::map<int, std::string> switches_;
std::vector<std::string> args_;
};
// Command dispatch ------------------------------------------------------------
// Type for a callback that a CommandExecutor will receive
using CommandCallback = fit::callback<void(Err)>;
// Runs the given command.
void DispatchCommand(const Command& cmd, fxl::RefPtr<CommandContext> cmd_context);
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_CONSOLE_COMMAND_H_