mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
301 lines
12 KiB
C++
301 lines
12 KiB
C++
/* ###
|
|
* IP: GHIDRA
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/// \file interface.hh
|
|
/// \brief Classes and utilities for a \e generic command-line interface
|
|
|
|
#ifndef __INTERFACE_HH__
|
|
#define __INTERFACE_HH__
|
|
|
|
#include "capability.hh"
|
|
#include <map>
|
|
#include <algorithm>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <cstdio>
|
|
|
|
namespace ghidra {
|
|
|
|
using std::map;
|
|
using std::istream;
|
|
using std::ostream;
|
|
using std::ifstream;
|
|
using std::ofstream;
|
|
using std::istringstream;
|
|
using std::endl;
|
|
using std::ws;
|
|
using std::ios_base;
|
|
|
|
#ifdef __REMOTE_SOCKET__
|
|
|
|
/// \brief A wrapper around a UNIX domain socket
|
|
///
|
|
/// The open() command attempts to connect to given socket name,
|
|
/// which must have been previously established by an external process.
|
|
/// The socket is bound to a C++ istream and ostream.
|
|
class RemoteSocket {
|
|
int fileDescriptor; ///< Descriptor for the socket
|
|
basic_filebuf<char> *inbuf; ///< Input buffer associated with the socket
|
|
basic_filebuf<char> *outbuf; ///< Output buffer for the socket
|
|
istream *inStream; ///< The C++ input stream
|
|
ostream *outStream; ///< The C++ output stream
|
|
bool isOpen; ///< Has the socket been opened
|
|
public:
|
|
RemoteSocket(void); ///< Constructor
|
|
~RemoteSocket(void) { close(); } ///< Destructor
|
|
bool open(const string &filename); ///< Connect to the given socket
|
|
bool isSocketOpen(void); ///< Return \b true if the socket is ready to transfer data
|
|
istream *getInputStream(void) { return inStream; } ///< Get the input stream
|
|
ostream *getOutputStream(void) { return outStream; } ///< Get the output stream
|
|
void close(void); ///< Close the streams and socket
|
|
};
|
|
|
|
#endif
|
|
|
|
/// \brief An exception specific to the command line interface
|
|
struct IfaceError {
|
|
string explain; ///< Explanatory string
|
|
IfaceError(const string &s) { explain = s; } ///< Constructor
|
|
};
|
|
|
|
/// \brief An exception describing a parsing error in a command line
|
|
///
|
|
/// Thrown when attempting to parse a command line. Options are missing or are in
|
|
/// the wrong form etc.
|
|
struct IfaceParseError : public IfaceError {
|
|
IfaceParseError(const string &s) : IfaceError(s) {} ///< Constructor
|
|
};
|
|
|
|
/// \brief An exception throw during the execution of a command
|
|
///
|
|
/// Processing of a specific command has started but has reached an error state
|
|
struct IfaceExecutionError : public IfaceError {
|
|
IfaceExecutionError(const string &s) : IfaceError(s) {} ///< Constructor
|
|
};
|
|
|
|
class IfaceStatus; // Forward declaration
|
|
|
|
/// \brief Data specialized for a particular command module
|
|
///
|
|
/// IfaceCommands can have specialized data that is shared with other commands in
|
|
/// the same module. This is the root object for all such data.
|
|
class IfaceData {
|
|
public:
|
|
virtual ~IfaceData(void) {} ///< Destructor
|
|
};
|
|
|
|
/// \brief A command that can be executed from the command line
|
|
///
|
|
/// The command has data associated with it (via setData()) and is executed
|
|
/// via the execute() method. The command can get additional parameters from
|
|
/// the command line by reading the input stream passed to it.
|
|
/// The command is associated with a specific sequence of words (tokens)
|
|
/// that should appear at the start of the command line.
|
|
class IfaceCommand {
|
|
vector<string> com; ///< The token sequence associated with the command
|
|
public:
|
|
virtual ~IfaceCommand(void) {} ///< Destructor
|
|
|
|
/// \brief Associate a specific data object with this command.
|
|
///
|
|
/// \param root is the interface object this command is registered with
|
|
/// \param data is the data object the command should use
|
|
virtual void setData(IfaceStatus *root,IfaceData *data)=0;
|
|
|
|
/// Execute this command. Additional state can be read from the given command line stream.
|
|
/// Otherwise, the command gets its data from its registered IfaceData object
|
|
/// \param s is the input stream from the command line
|
|
virtual void execute(istream &s)=0;
|
|
|
|
/// \brief Get the formal module name to which this command belongs
|
|
///
|
|
/// Commands in the same module share data through their registered IfaceData object
|
|
/// \return the formal module name
|
|
virtual string getModule(void) const=0;
|
|
|
|
/// \brief Create a specialized data object for \b this command (and its module)
|
|
///
|
|
/// This method is only called once per module
|
|
/// \return the newly created data object for the module
|
|
virtual IfaceData *createData(void)=0;
|
|
|
|
/// \brief Add a token to the command line string associated with this command
|
|
///
|
|
/// \param temp is the new token to add
|
|
void addWord(const string &temp) { com.push_back(temp); }
|
|
|
|
void removeWord(void) { com.pop_back(); } ///< Remove the last token from the associated command line string
|
|
const string &getCommandWord(int4 i) const { return com[i]; } ///< Get the i-th command token
|
|
void addWords(const vector<string> &wordlist); ///< Add words to the associated command line string
|
|
int4 numWords(void) const { return com.size(); } ///< Return the number of tokens in the command line string
|
|
void commandString(string &res) const; ///< Get the complete command line string
|
|
int4 compare(const IfaceCommand &op2) const; ///< Order two commands by their command line strings
|
|
};
|
|
|
|
/// \brief A dummy command used during parsing
|
|
class IfaceCommandDummy : public IfaceCommand {
|
|
public:
|
|
virtual void setData(IfaceStatus *root,IfaceData *data) {}
|
|
virtual void execute(istream &s) {}
|
|
virtual string getModule(void) const { return "dummy"; }
|
|
virtual IfaceData *createData(void) { return (IfaceData *)0; }
|
|
};
|
|
|
|
/// \brief Compare to commands as pointers
|
|
///
|
|
/// \param a is a pointer to the first command
|
|
/// \param b is a pointer to the second command
|
|
/// \return \b true if the first pointer is ordered before the second
|
|
inline bool compare_ifacecommand(const IfaceCommand *a,const IfaceCommand *b) {
|
|
return (0>a->compare(*b));
|
|
}
|
|
|
|
/// \brief Groups of console commands that are \e discovered by the loader
|
|
///
|
|
/// Any IfaceCommand that is registered with a grouping derived from this class
|
|
/// is automatically made available to any IfaceStatus object just by calling
|
|
/// the static registerAllCommands()
|
|
class IfaceCapability : public CapabilityPoint {
|
|
static vector<IfaceCapability *> thelist; ///< The global list of discovered command groupings
|
|
protected:
|
|
string name; ///< Identifying name for the capability
|
|
public:
|
|
const string &getName(void) const { return name; } ///< Get the name of the capability
|
|
virtual void initialize(void);
|
|
virtual void registerCommands(IfaceStatus *status)=0; ///< Register commands for \b this grouping
|
|
|
|
static void registerAllCommands(IfaceStatus *status); ///< Register all discovered commands with the interface
|
|
};
|
|
|
|
/// \brief A generic console mode interface and command executor
|
|
///
|
|
/// Input is provided one command line at a time by providing calling readLine().
|
|
/// Output goes to a provided ostream, \e optr. Output to a separate bulk stream
|
|
/// can be enabled by setting \e fileoptr.
|
|
///
|
|
/// A derived IfaceCommand is attached to a command string via registerCom()
|
|
/// i.e.
|
|
/// stat.registerCom(new IfcQuit(),"quit");
|
|
/// stat.registerCom(new IfcOpenfileAppend(),"openfile","append");
|
|
/// stat.mainloop();
|
|
|
|
/// Command line processing is started with mainloop(), which prints a command prompt,
|
|
/// allows command line editing, including command completion and history, and executes
|
|
/// the corresponding IfaceComman::execute() callback.
|
|
/// Command words only have to match enough to disambiguate it from other commands.
|
|
|
|
/// A Custom history size and command prompt can be passed to the constructor.
|
|
/// Applications should inherit from base class IfaceStatus in order to
|
|
/// - Override the readLine() method
|
|
/// - Override pushScript() and popScript() to allow command scripts
|
|
/// - Get custom data into IfaceCommand callbacks
|
|
class IfaceStatus {
|
|
vector<string> promptstack; ///< Stack of command prompts corresponding to script nesting level
|
|
vector<uint4> flagstack; ///< Stack of flag state corresponding to script nesting level
|
|
string prompt; ///< The current command prompt
|
|
int4 maxhistory; ///< Maximum number of command lines to store in history
|
|
int4 curhistory; ///< Most recent history
|
|
vector<string> history; ///< History of commands executed through this interface
|
|
bool sorted; ///< Set to \b true if commands are sorted
|
|
bool errorisdone; ///< Set to \b true if any error terminates the process
|
|
void restrictCom(vector<IfaceCommand *>::const_iterator &first,
|
|
vector<IfaceCommand *>::const_iterator &last,vector<string> &input);
|
|
|
|
/// \brief Read the next command line
|
|
///
|
|
/// \param line is filled in with the next command to execute
|
|
virtual void readLine(string &line)=0;
|
|
void saveHistory(const string &line); ///< Store the given command line into \e history
|
|
protected:
|
|
bool inerror; ///< Set to \b true if last command did not succeed
|
|
vector<IfaceCommand *> comlist; ///< List of registered commands
|
|
map<string,IfaceData *> datamap; ///< Data associated with particular modules
|
|
int4 expandCom(vector<string> &expand,istream &s,
|
|
vector<IfaceCommand *>::const_iterator &first,
|
|
vector<IfaceCommand *>::const_iterator &last);
|
|
public:
|
|
bool done; ///< Set to \b true (by a command) to indicate processing is finished
|
|
ostream *optr; ///< Where to put command line output
|
|
ostream *fileoptr; ///< Where to put bulk output
|
|
|
|
IfaceStatus(const string &prmpt,ostream &os,int4 mxhist=10); ///< Constructor
|
|
virtual ~IfaceStatus(void); ///< Destructor
|
|
void setErrorIsDone(bool val) { errorisdone = val; } ///< Set if processing should terminate on an error
|
|
void pushScript(const string &filename,const string &newprompt);
|
|
virtual void pushScript(istream *iptr,const string &newprompt);
|
|
virtual void popScript(void);
|
|
virtual void reset(void); ///< Pop any existing script streams and return to processing from the base stream
|
|
int4 getNumInputStreamSize(void) const { return promptstack.size(); } ///< Get depth of script nesting
|
|
void writePrompt(void) { *optr << prompt; } ///< Write the current command prompt to the current output stream
|
|
void registerCom(IfaceCommand *fptr, const char *nm1,
|
|
const char *nm2 = (const char *)0,
|
|
const char *nm3 = (const char *)0,
|
|
const char *nm4 = (const char *)0,
|
|
const char *nm5 = (const char *)0);
|
|
IfaceData *getData(const string &nm) const; ///< Get data associated with a IfaceCommand module
|
|
bool runCommand(void); ///< Run the next command
|
|
void getHistory(string &line,int4 i) const; ///< Get the i-th command line from history
|
|
int4 getHistorySize(void) const { return history.size(); } ///< Get the number of command lines in history
|
|
virtual bool isStreamFinished(void) const=0; ///< Return \b true if the current stream is finished
|
|
bool isInError(void) const { return inerror; } ///< Return \b true if the last command failed
|
|
void evaluateError(void); ///< Adjust which stream to process based on last error
|
|
static void wordsToString(string &res,const vector<string> &list); ///< Concatenate tokens
|
|
};
|
|
|
|
/// \brief A root class for a basic set of commands
|
|
///
|
|
/// Commands derived from this class are in the "base" module.
|
|
/// They are useful as part of any interface
|
|
class IfaceBaseCommand : public IfaceCommand {
|
|
protected:
|
|
IfaceStatus *status; ///< The interface owning this command instance
|
|
public:
|
|
virtual void setData(IfaceStatus *root,IfaceData *data) { status = root; }
|
|
virtual string getModule(void) const { return "base"; }
|
|
virtual IfaceData *createData(void) { return (IfaceData *)0; }
|
|
};
|
|
|
|
class IfcQuit : public IfaceBaseCommand {
|
|
public:
|
|
virtual void execute(istream &s);
|
|
};
|
|
|
|
class IfcHistory : public IfaceBaseCommand {
|
|
public:
|
|
virtual void execute(istream &s);
|
|
};
|
|
|
|
class IfcOpenfile : public IfaceBaseCommand {
|
|
public:
|
|
virtual void execute(istream &s);
|
|
};
|
|
|
|
class IfcOpenfileAppend : public IfaceBaseCommand {
|
|
public:
|
|
virtual void execute(istream &s);
|
|
};
|
|
|
|
class IfcClosefile : public IfaceBaseCommand {
|
|
public:
|
|
virtual void execute(istream &s);
|
|
};
|
|
|
|
class IfcEcho : public IfaceBaseCommand {
|
|
public:
|
|
virtual void execute(istream &s);
|
|
};
|
|
|
|
} // End namespace ghidra
|
|
#endif
|