A bunch of doxygen fixes

This commit is contained in:
caheckman 2021-01-27 12:03:48 -05:00
parent 8d2b737a72
commit 5d7a7c5291
27 changed files with 514 additions and 195 deletions

View file

@ -457,7 +457,7 @@ RECURSIVE = NO
# excluded from the INPUT source files. This way you can easily exclude a # excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag. # subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE = unify.hh unify.cc rulecompile.hh rulecompile.cc slgh_compile.hh slgh_compile.hh slghpattern.hh slghpattern.cc slghpatexpress.hh slghpatexpress.cc slghsymbol.hh slghsymbol.cc ifacedecomp.hh ifacedecomp.cc ifaceterm.hh ifaceterm.cc codedata.hh codedata.cc semantics.hh semantics.cc grammar.hh grammar.cc callgraph.hh callgraph.cc filemanage.hh filemanage.cc graph.hh graph.cc interface.hh interface.cc loadimage_bfd.hh loadimage_bfd.cc pcodecompile.cc pcodecompile.hh pcodeparse.hh pcodeparse.cc inject_sleigh.hh inject_sleigh.cc context.hh context.cc consolemain.cc sleighexample.cc xml.cc EXCLUDE = unify.hh unify.cc rulecompile.hh rulecompile.cc slgh_compile.hh slgh_compile.cc slghparse.cc slghparse.hh slghscan.cc slghpattern.hh slghpattern.cc slghpatexpress.hh slghpatexpress.cc slghsymbol.hh slghsymbol.cc ifacedecomp.hh ifacedecomp.cc codedata.hh codedata.cc semantics.hh semantics.cc grammar.hh grammar.cc callgraph.hh callgraph.cc filemanage.hh filemanage.cc graph.hh graph.cc loadimage_bfd.hh loadimage_bfd.cc pcodecompile.cc pcodecompile.hh pcodeparse.hh pcodeparse.cc inject_sleigh.hh inject_sleigh.cc context.hh context.cc consolemain.cc sleighexample.cc xml.cc double.hh double.cc paramid.hh paramid.cc prefersplit.hh prefersplit.cc
# The EXCLUDE_SYMLINKS tag can be used select whether or not files or # The EXCLUDE_SYMLINKS tag can be used select whether or not files or
# directories that are symbolic links (a Unix filesystem feature) are excluded # directories that are symbolic links (a Unix filesystem feature) are excluded

View file

@ -597,8 +597,8 @@ class BlockWhileDo : public BlockGraph {
bool testIterateForm(void) const; ///< Return \b false if the iterate statement is of an unacceptable form bool testIterateForm(void) const; ///< Return \b false if the iterate statement is of an unacceptable form
public: public:
BlockWhileDo(void) { initializeOp = (PcodeOp *)0; iterateOp = (PcodeOp *)0; loopDef = (PcodeOp *)0; } ///< Constructor BlockWhileDo(void) { initializeOp = (PcodeOp *)0; iterateOp = (PcodeOp *)0; loopDef = (PcodeOp *)0; } ///< Constructor
PcodeOp *getInitializeOp(void) const { return initializeOp; } PcodeOp *getInitializeOp(void) const { return initializeOp; } ///< Get root of initialize statement or null
PcodeOp *getIterateOp(void) const { return iterateOp; } PcodeOp *getIterateOp(void) const { return iterateOp; } ///< Get root of iterate statement or null
bool hasOverflowSyntax(void) const { return ((getFlags() & f_whiledo_overflow)!=0); } ///< Does \b this require overflow syntax bool hasOverflowSyntax(void) const { return ((getFlags() & f_whiledo_overflow)!=0); } ///< Does \b this require overflow syntax
void setOverflowSyntax(void) { setFlag(f_whiledo_overflow); } ///< Set that \b this requires overflow syntax void setOverflowSyntax(void) { setFlag(f_whiledo_overflow); } ///< Set that \b this requires overflow syntax
virtual block_type getType(void) const { return t_whiledo; } virtual block_type getType(void) const { return t_whiledo; }

View file

@ -3477,9 +3477,10 @@ bool ActionDeadCode::isEventualConstant(Varnode *vn,int4 addCount,int4 loadCount
/// \brief Check if there are any unconsumed LOADs that may be from volatile addresses. /// \brief Check if there are any unconsumed LOADs that may be from volatile addresses.
/// ///
/// It may be too early to remove certain LOAD operations even though their result isn't /// It may be too early to remove certain LOAD operations even though their result isn't
/// consumed because it be of a volatile address with side effects. If a LOAD meets this /// consumed because it may be of a volatile address with side effects. If a LOAD meets this
/// criteria, it is added to the worklist and \b true is returned. /// criteria, it is added to the worklist and \b true is returned.
/// \param data is the function being analyzed /// \param data is the function being analyzed
/// \param worklist is the container of consumed Varnodes to further process
/// \return \b true if there was at least one LOAD added to the worklist /// \return \b true if there was at least one LOAD added to the worklist
bool ActionDeadCode::lastChanceLoad(Funcdata &data,vector<Varnode *> &worklist) bool ActionDeadCode::lastChanceLoad(Funcdata &data,vector<Varnode *> &worklist)

View file

@ -2817,7 +2817,7 @@ void Database::fillResolve(Scope *scope)
/// Initialize a new symbol table, with no initial scopes or symbols. /// Initialize a new symbol table, with no initial scopes or symbols.
/// \param g is the Architecture that owns the symbol table /// \param g is the Architecture that owns the symbol table
/// \param isByName is \b true if scope ids are calculated as a hash of the scope name. /// \param idByName is \b true if scope ids are calculated as a hash of the scope name.
Database::Database(Architecture *g,bool idByName) Database::Database(Architecture *g,bool idByName)
{ {

View file

@ -19,6 +19,7 @@
/// \param nm is the (base) name of the function /// \param nm is the (base) name of the function
/// \param scope is Symbol scope associated with the function /// \param scope is Symbol scope associated with the function
/// \param addr is the entry address for the function /// \param addr is the entry address for the function
/// \param sym is the symbol representing the function
/// \param sz is the number of bytes (of code) in the function body /// \param sz is the number of bytes (of code) in the function body
Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSymbol *sym,int4 sz) Funcdata::Funcdata(const string &nm,Scope *scope,const Address &addr,FunctionSymbol *sym,int4 sz)
: baseaddr(addr), : baseaddr(addr),

View file

@ -249,7 +249,6 @@ public:
int4 numCalls(void) const { return qlst.size(); } ///< Get the number of calls made by \b this function int4 numCalls(void) const { return qlst.size(); } ///< Get the number of calls made by \b this function
FuncCallSpecs *getCallSpecs(int4 i) const { return qlst[i]; } ///< Get the i-th call specification FuncCallSpecs *getCallSpecs(int4 i) const { return qlst[i]; } ///< Get the i-th call specification
FuncCallSpecs *getCallSpecs(const PcodeOp *op) const; ///< Get the call specification associated with a CALL op FuncCallSpecs *getCallSpecs(const PcodeOp *op) const; ///< Get the call specification associated with a CALL op
void updateOpFromSpec(FuncCallSpecs *fc);
int4 fillinExtrapop(void); ///< Recover and return the \e extrapop for this function int4 fillinExtrapop(void); ///< Recover and return the \e extrapop for this function
// Varnode routines // Varnode routines

View file

@ -291,7 +291,7 @@ void Funcdata::destroyVarnode(Varnode *vn)
/// Check if the given storage range is a potential laned register. /// Check if the given storage range is a potential laned register.
/// If so, record the storage with the matching laned register record. /// If so, record the storage with the matching laned register record.
/// \param s is the size of the storage range in bytes /// \param size is the size of the storage range in bytes
/// \param addr is the starting address of the storage range /// \param addr is the starting address of the storage range
void Funcdata::checkForLanedRegister(int4 size,const Address &addr) void Funcdata::checkForLanedRegister(int4 size,const Address &addr)

View file

@ -690,6 +690,18 @@ void ArchitectureGhidra::getBytes(uint1 *buf,int4 size,const Address &inaddr)
readResponseEnd(sin); readResponseEnd(sin);
} }
/// \brief Get string data at a specific address
///
/// The data is always returned as a sequence of bytes in UTF-8 format. The in-memory form of
/// the string may be different than UTF-8 but is always translated into UTF-8 by this method.
/// The caller can inform the in-memory format of the string by specifying a specific string
/// data-type. A maximum number of bytes to return is specified. If this is exceeded, a boolean
/// reference is set to \b true.
/// \param buffer will hold the string bytes in UTF-8 format
/// \param addr is program Address that holds the string data in memory
/// \param ct is string data-type expected
/// \param maxBytes is the maximum number of bytes to return
/// \param isTrunc is the boolean reference indicating whether the data is truncated
void ArchitectureGhidra::getStringData(vector<uint1> &buffer,const Address &addr,Datatype *ct,int4 maxBytes,bool &isTrunc) void ArchitectureGhidra::getStringData(vector<uint1> &buffer,const Address &addr,Datatype *ct,int4 maxBytes,bool &isTrunc)
{ {

View file

@ -127,7 +127,7 @@ public:
bool getSendParamMeasures(void) const { return sendParamMeasures; } ///< Get the current setting for emitting parameter info bool getSendParamMeasures(void) const { return sendParamMeasures; } ///< Get the current setting for emitting parameter info
virtual void getStringData(vector<uint1> &buffer,const Address &addr,Datatype *ct,int4 maxBytes,bool &isTrunc); void getStringData(vector<uint1> &buffer,const Address &addr,Datatype *ct,int4 maxBytes,bool &isTrunc);
virtual void printMessage(const string &message) const; virtual void printMessage(const string &message) const;
static void segvHandler(int4 sig); ///< Handler for a segment violation (SIGSEGV) signal static void segvHandler(int4 sig); ///< Handler for a segment violation (SIGSEGV) signal

View file

@ -58,9 +58,16 @@ IfaceTerm::~IfaceTerm(void)
#endif #endif
} }
/// Respond to a TAB key press and try to 'complete' any existing tokens.
/// The method is handed the current state of the command-line in a string, and
/// it updates the command-line in place.
///
/// \param line is current command-line and will hold the final completion
/// \param cursor is the current position of the cursor
/// \return the (possibly new) position of the cursor, after completion
int4 IfaceTerm::doCompletion(string &line,int4 cursor) int4 IfaceTerm::doCompletion(string &line,int4 cursor)
{ // Try to complete the current command {
vector<string> fullcommand; vector<string> fullcommand;
istringstream s(line); istringstream s(line);
string tok; string tok;

View file

@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
// Add some terminal capabilities to the command-line interface
/// \file ifaceterm.hh
/// \brief Add some terminal capabilities to the command-line interface (IfaceStatus)
#include "interface.hh" #include "interface.hh"
#ifdef __TERMINAL__ #ifdef __TERMINAL__
@ -23,18 +26,24 @@ extern "C" {
} }
#endif #endif
/// \brief Implement the command-line interface on top of a specific input stream
///
/// An initial input stream is provided as the base stream to parse for commands.
/// Additional input streams can be stacked by invoking scripts.
/// If the stream supports it, the stream parser recognizes special command-line editing
/// and completion keys.
class IfaceTerm : public IfaceStatus { class IfaceTerm : public IfaceStatus {
#ifdef __TERMINAL__ #ifdef __TERMINAL__
bool is_terminal; // True if the input stream is a terminal bool is_terminal; ///< True if the input stream is a terminal
int4 ifd; // Underlying file descriptor int4 ifd; ///< Underlying file descriptor
struct termios itty; // Original terminal settings struct termios itty; ///< Original terminal settings
#endif #endif
istream *sptr; // Where to get input istream *sptr; ///< The base input stream for the interface
vector<istream *> inputstack; vector<istream *> inputstack; ///< Stack of nested input streams
int4 doCompletion(string &line,int4 cursor); int4 doCompletion(string &line,int4 cursor); ///< 'Complete' the current command line
virtual void readLine(string &line); virtual void readLine(string &line);
public: public:
IfaceTerm(const string &prmpt,istream &is,ostream &os); IfaceTerm(const string &prmpt,istream &is,ostream &os); ///< Constructor
virtual ~IfaceTerm(void); virtual ~IfaceTerm(void);
virtual void pushScript(const string &filename,const string &newprompt); virtual void pushScript(const string &filename,const string &newprompt);
virtual void popScript(void); virtual void popScript(void);

View file

@ -29,9 +29,12 @@ void IfaceCapability::initialize(void)
thelist.push_back(this); thelist.push_back(this);
} }
/// Allow each capability to register its own commands
///
/// \param status is the command line interface to register commands with
void IfaceCapability::registerAllCommands(IfaceStatus *status) void IfaceCapability::registerAllCommands(IfaceStatus *status)
{ // Allow each capability to register its own commands {
for(uint4 i=0;i<thelist.size();++i) for(uint4 i=0;i<thelist.size();++i)
thelist[i]->registerCommands(status); thelist[i]->registerCommands(status);
} }
@ -114,6 +117,9 @@ bool RemoteSocket::isSocketOpen(void)
#endif #endif
/// \param prmpt is the base command line prompt
/// \param os is the base stream to write output to
/// \param mxhist is the maximum number of lines to store in history
IfaceStatus::IfaceStatus(const string &prmpt,ostream &os,int4 mxhist) IfaceStatus::IfaceStatus(const string &prmpt,ostream &os,int4 mxhist)
{ {
@ -128,9 +134,15 @@ IfaceStatus::IfaceStatus(const string &prmpt,ostream &os,int4 mxhist)
curhistory = 0; curhistory = 0;
} }
/// \brief Provide a new script file to execute, with an associated command prompt
///
/// The script provides a subsidiary input stream to the current stream.
/// Once commands from the script are complete, processing will resume on this stream.
/// \param filename is the name of the file containing the script
/// \param newprompt is the command line prompt
void IfaceStatus::pushScript(const string &filename,const string &newprompt) void IfaceStatus::pushScript(const string &filename,const string &newprompt)
{ // Push new input stream on stack (with new prompt) {
promptstack.push_back(prompt); promptstack.push_back(prompt);
uint4 flags = 0; uint4 flags = 0;
if (errorisdone) if (errorisdone)
@ -139,9 +151,13 @@ void IfaceStatus::pushScript(const string &filename,const string &newprompt)
prompt = newprompt; prompt = newprompt;
} }
/// \brief Return to processing the parent stream
///
/// The current input stream, as established by a script, is popped from the stack,
/// along with its command prompt, and processing continues with the previous stream.
void IfaceStatus::popScript(void) void IfaceStatus::popScript(void)
{ // Pop the current input stream (and current prompt) {
prompt = promptstack.back(); prompt = promptstack.back();
promptstack.pop_back(); promptstack.pop_back();
uint4 flags = flagstack.back(); uint4 flags = flagstack.back();
@ -159,9 +175,11 @@ void IfaceStatus::reset(void)
done = false; done = false;
} }
/// The line is saved in a circular history buffer
/// \param line is the command line to save
void IfaceStatus::saveHistory(const string &line) void IfaceStatus::saveHistory(const string &line)
{ // Save line in circular history buffer {
if (history.size() < maxhistory) if (history.size() < maxhistory)
history.push_back(line); history.push_back(line);
else else
@ -171,6 +189,10 @@ void IfaceStatus::saveHistory(const string &line)
curhistory = 0; curhistory = 0;
} }
/// A command line is selected by specifying how many steps in time
/// to go back through the list of successful command lines.
/// \param line will hold the selected command line from history
/// \param i is the number of steps back to go
void IfaceStatus::getHistory(string &line,int4 i) const void IfaceStatus::getHistory(string &line,int4 i) const
{ {
@ -182,9 +204,10 @@ void IfaceStatus::getHistory(string &line,int4 i) const
line = history[i]; line = history[i];
} }
// The last command has failed, decide if we are completely abandoning this stream
void IfaceStatus::evaluateError(void) void IfaceStatus::evaluateError(void)
{ // The last command has failed, decide if we are completely abandoning this stream {
if (errorisdone) { if (errorisdone) {
*optr << "Aborting process" << endl; *optr << "Aborting process" << endl;
inerror = true; inerror = true;
@ -199,6 +222,7 @@ void IfaceStatus::evaluateError(void)
inerror = false; inerror = false;
} }
/// Concatenate a list of tokens into a single string, separated by a space character
void IfaceStatus::wordsToString(string &res,const vector<string> &list) void IfaceStatus::wordsToString(string &res,const vector<string> &list)
{ {
@ -229,13 +253,24 @@ IfaceStatus::~IfaceStatus(void)
delete (*iter).second; delete (*iter).second;
} }
/// \brief Register a command with this interface
///
/// A command object is associated with one or more tokens on the command line.
/// A string containing up to 5 tokens can be associated with the command.
///
/// \param fptr is the IfaceCommand object
/// \param nm1 is the first token representing the command
/// \param nm2 is the second token (or null)
/// \param nm3 is the third token (or null)
/// \param nm4 is the fourth token (or null)
/// \param nm5 is the fifth token (or null)
void IfaceStatus::registerCom(IfaceCommand *fptr,const char *nm1, void IfaceStatus::registerCom(IfaceCommand *fptr,const char *nm1,
const char *nm2, const char *nm2,
const char *nm3, const char *nm3,
const char *nm4, const char *nm4,
const char *nm5) const char *nm5)
{ // Register an interface command {
fptr->addWord(nm1); fptr->addWord(nm1);
if (nm2 != (const char *)0) if (nm2 != (const char *)0)
fptr->addWord(nm2); fptr->addWord(nm2);
@ -261,15 +296,24 @@ void IfaceStatus::registerCom(IfaceCommand *fptr,const char *nm1,
fptr->setData(this,data); // Inform command of its data fptr->setData(this,data); // Inform command of its data
} }
/// Commands (IfaceCommand) are associated with a particular module that has
/// a formal name and a data object associated with it. This method
/// retrieves the module specific data object by name.
/// \param nm is the name of the module
/// \return the IfaceData object or null
IfaceData *IfaceStatus::getData(const string &nm) const IfaceData *IfaceStatus::getData(const string &nm) const
{ // Get data corresponding to the named module {
map<string,IfaceData *>::const_iterator iter = datamap.find(nm); map<string,IfaceData *>::const_iterator iter = datamap.find(nm);
if (iter == datamap.end()) if (iter == datamap.end())
return (IfaceData *)0; return (IfaceData *)0;
return (*iter).second; return (*iter).second;
} }
/// A single command line is read (via readLine) and executed.
/// If the command is successfully executed, the command line is
/// committed to history and \b true is returned.
/// \return \b true if a command successfully executes
bool IfaceStatus::runCommand(void) bool IfaceStatus::runCommand(void)
{ {
@ -309,7 +353,14 @@ bool IfaceStatus::runCommand(void)
return true; // Indicate a command was executed return true; // Indicate a command was executed
} }
void IfaceStatus::restrict(vector<IfaceCommand *>::const_iterator &first, /// \brief Restrict range of possible commands given a list of command line tokens
///
/// Given a set of tokens partially describing a command, provide the most narrow
/// range of IfaceCommand objects that could be referred to.
/// \param first will hold an iterator to the first command in the range
/// \param last will hold an iterator (one after) the last command in the range
/// \param input is the list of command tokens to match on
void IfaceStatus::restrictCom(vector<IfaceCommand *>::const_iterator &first,
vector<IfaceCommand *>::const_iterator &last, vector<IfaceCommand *>::const_iterator &last,
vector<string> &input) vector<string> &input)
@ -347,16 +398,22 @@ static bool maxmatch(string &res,const string &op1,const string &op2)
return true; return true;
} }
/// \brief Expand tokens from the given input stream to a full command
///
/// A range of possible commands is returned. Processing of the stream
/// stops as soon as at least one complete command is recognized.
/// Tokens partially matching a command are expanded to the full command
/// and passed back.
/// \param expand will hold the list of expanded tokens
/// \param s is the input stream tokens are read from
/// \param first will hold the beginning of the matching range of commands
/// \param last will hold the end of the matching range of commands
/// \return the number of matching commands
int4 IfaceStatus::expandCom(vector<string> &expand,istream &s, int4 IfaceStatus::expandCom(vector<string> &expand,istream &s,
vector<IfaceCommand *>::const_iterator &first, vector<IfaceCommand *>::const_iterator &first,
vector<IfaceCommand *>::const_iterator &last) vector<IfaceCommand *>::const_iterator &last)
{ // Expand tokens on stream to full command {
// Return range of possible commands
// If command is complete with extra arguments
// return (dont process) remaining args
// Return number of matching commands
int4 pos; // Which word are we currently expanding int4 pos; // Which word are we currently expanding
string tok; string tok;
bool res; bool res;
@ -386,7 +443,7 @@ int4 IfaceStatus::expandCom(vector<string> &expand,istream &s,
} }
s >> tok; // Get next token s >> tok; // Get next token
expand.push_back(tok); expand.push_back(tok);
restrict(first,last,expand); restrictCom(first,last,expand);
if (first == last) // If subrange is empty, return 0 if (first == last) // If subrange is empty, return 0
return 0; return 0;
res = maxmatch(tok, (*first)->getCommandWord(pos), (*(last-1))->getCommandWord(pos)); res = maxmatch(tok, (*first)->getCommandWord(pos), (*(last-1))->getCommandWord(pos));
@ -403,9 +460,13 @@ void IfaceCommand::addWords(const vector<string> &wordlist)
com.push_back( *iter ); com.push_back( *iter );
} }
/// The commands are ordered lexicographically and alphabetically by
/// the comparing tokens in their respective command line strings
/// \param op2 is the other command to compare with \b this
/// \return -1, 0, 1 if \b this is earlier, equal to, or after to the other command
int4 IfaceCommand::compare(const IfaceCommand &op2) const int4 IfaceCommand::compare(const IfaceCommand &op2) const
{ // Sort command based on names {
int4 res; int4 res;
vector<string>::const_iterator iter1,iter2; vector<string>::const_iterator iter1,iter2;
@ -424,12 +485,15 @@ int4 IfaceCommand::compare(const IfaceCommand &op2) const
return 0; // Never reaches here return 0; // Never reaches here
} }
/// \param res is overwritten with the full command line string
void IfaceCommand::commandString(string &res) const void IfaceCommand::commandString(string &res) const
{ {
IfaceStatus::wordsToString(res,com); IfaceStatus::wordsToString(res,com);
} }
/// \class IfcQuit
/// \brief Quit command to terminate processing from the given interface
void IfcQuit::execute(istream &s) void IfcQuit::execute(istream &s)
{ // Generic quit call back { // Generic quit call back
@ -439,6 +503,8 @@ void IfcQuit::execute(istream &s)
status->done = true; // Set flag to drop out of mainloop status->done = true; // Set flag to drop out of mainloop
} }
/// \class IfcHistory
/// \brief History command to list the most recent successful commands
void IfcHistory::execute(istream &s) void IfcHistory::execute(istream &s)
{ // List most recent command lines { // List most recent command lines
@ -462,6 +528,8 @@ void IfcHistory::execute(istream &s)
} }
} }
/// \class IfcOpenfile
/// \brief Open file command to redirect bulk output to a specific file stream
void IfcOpenfile::execute(istream &s) void IfcOpenfile::execute(istream &s)
{ {
@ -482,6 +550,8 @@ void IfcOpenfile::execute(istream &s)
} }
} }
/// \class IfcOpenfileAppend
/// \brief Open file command directing bulk output to be appended to a specific file
void IfcOpenfileAppend::execute(istream &s) void IfcOpenfileAppend::execute(istream &s)
{ {
@ -502,6 +572,10 @@ void IfcOpenfileAppend::execute(istream &s)
} }
} }
/// \class IfcClosefile
/// \brief Close command, closing the current bulk output file.
///
/// Subsequent bulk output is redirected to the basic interface output stream
void IfcClosefile::execute(istream &s) void IfcClosefile::execute(istream &s)
{ {
@ -512,6 +586,8 @@ void IfcClosefile::execute(istream &s)
status->fileoptr = status->optr; status->fileoptr = status->optr;
} }
/// \class IfcEcho
/// \brief Echo command to echo the current command line to the bulk output stream
void IfcEcho::execute(istream &s) void IfcEcho::execute(istream &s)
{ // Echo command line to fileoptr { // Echo command line to fileoptr

View file

@ -13,23 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
// Very generic command line executor class: IfaceStatus
// A new class instance derived from IfaceCommand is attached to a command line via registerCom
// i.e.
// IfaceStatus stat(cin,cout);
// stat.registerCom(new IfcQuit(),"quit");
// stat.registerCom(new IfcOpenfileAppend(),"openfile","append");
// stat.mainloop();
// Command line processing is started with mainloop, which prints a /// \file interface.hh
// prompt set with setprompt, allows bash style command line editing, including /// \brief Classes and utilities for a \e generic command-line interface
// command completion and history, and executes the corresponding IfaceCommand.execute callback.
// Command words only have to match enough to disambiguate it from other commands.
// Custom history size can be passed in constructor to IfaceStatus.
// Applications should inherit from base class IfaceStatus in order
// to get custom data into IfaceCommand callbacks and to redefine
// the virtual function execute for custom error handling.
#ifndef __INTERFACE__ #ifndef __INTERFACE__
#define __INTERFACE__ #define __INTERFACE__
@ -70,43 +56,87 @@ public:
#endif #endif
/// \brief An exception specific to the command line interface
struct IfaceError { struct IfaceError {
string explain; // Explanatory string string explain; ///< Explanatory string
IfaceError(const string &s) { explain = s; } 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 { struct IfaceParseError : public IfaceError {
IfaceParseError(const string &s) : IfaceError(s) {} 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 { struct IfaceExecutionError : public IfaceError {
IfaceExecutionError(const string &s) : IfaceError(s) {} IfaceExecutionError(const string &s) : IfaceError(s) {} ///< Constructor
}; };
class IfaceStatus; // Forward declaration class IfaceStatus; // Forward declaration
class IfaceData { // Data specialized for a particular command /// \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: public:
virtual ~IfaceData(void) {} 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 { class IfaceCommand {
vector<string> com; // The command vector<string> com; ///< The token sequence associated with the command
public: public:
virtual ~IfaceCommand(void) {} 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; 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; 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; 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; 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 addWord(const string &temp) { com.push_back(temp); }
void removeWord(void) { com.pop_back(); }
const string &getCommandWord(int4 i) const { return com[i]; } void removeWord(void) { com.pop_back(); } ///< Remove the last token from the associated command line string
void addWords(const vector<string> &wordlist); const string &getCommandWord(int4 i) const { return com[i]; } ///< Get the i-th command token
int4 numWords(void) const { return com.size(); } void addWords(const vector<string> &wordlist); ///< Add words to the associated command line string
void commandString(string &res) const; int4 numWords(void) const { return com.size(); } ///< Return the number of tokens in the command line string
int4 compare(const IfaceCommand &op2) const; 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 { class IfaceCommandDummy : public IfaceCommand {
public: public:
virtual void setData(IfaceStatus *root,IfaceData *data) {} virtual void setData(IfaceStatus *root,IfaceData *data) {}
@ -115,73 +145,113 @@ public:
virtual IfaceData *createData(void) { return (IfaceData *)0; } 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) { inline bool compare_ifacecommand(const IfaceCommand *a,const IfaceCommand *b) {
return (0>a->compare(*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 { class IfaceCapability : public CapabilityPoint {
static vector<IfaceCapability *> thelist; static vector<IfaceCapability *> thelist; ///< The global list of discovered command groupings
protected: protected:
string name; // Identifying name for the capability string name; ///< Identifying name for the capability
public: public:
const string &getName(void) const { return name; } const string &getName(void) const { return name; } ///< Get the name of the capability
virtual void initialize(void); virtual void initialize(void);
virtual void registerCommands(IfaceStatus *status)=0; virtual void registerCommands(IfaceStatus *status)=0; ///< Register commands for \b this grouping
static void registerAllCommands(IfaceStatus *status); static void registerAllCommands(IfaceStatus *status); ///< Register all discovered commands with the interface
}; };
/// \brief Current state of the console mode 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 { class IfaceStatus {
vector<string> promptstack; vector<string> promptstack; ///< Stack of command prompts corresponding to script nesting level
vector<uint4> flagstack; vector<uint4> flagstack; ///< Stack of flag state corresponding to script nesting level
string prompt; string prompt; ///< The current command prompt
int4 maxhistory; int4 maxhistory; ///< Maximum number of command lines to store in history
int4 curhistory; // most recent history int4 curhistory; ///< Most recent history
vector<string> history; vector<string> history; ///< History of commands executed through this interface
bool sorted; // Are commands sorted bool sorted; ///< Set to \b true if commands are sorted
bool errorisdone; // -true- if any error terminates the process bool errorisdone; ///< Set to \b true if any error terminates the process
void restrict(vector<IfaceCommand *>::const_iterator &first,vector<IfaceCommand *>::const_iterator &last,vector<string> &input); 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; virtual void readLine(string &line)=0;
void saveHistory(const string &line); void saveHistory(const string &line); ///< Store the given command line into \e history
protected: protected:
bool inerror; // -true- if last command did not succeed bool inerror; ///< Set to \b true if last command did not succeed
vector<IfaceCommand *> comlist; // List of commands vector<IfaceCommand *> comlist; ///< List of registered commands
map<string,IfaceData *> datamap; // Data associated with particular modules map<string,IfaceData *> datamap; ///< Data associated with particular modules
int4 expandCom(vector<string> &expand,istream &s, int4 expandCom(vector<string> &expand,istream &s,
vector<IfaceCommand *>::const_iterator &first, vector<IfaceCommand *>::const_iterator &first,
vector<IfaceCommand *>::const_iterator &last); vector<IfaceCommand *>::const_iterator &last);
public: public:
bool done; bool done; ///< Set to \b true (by a command) to indicate processing is finished
ostream *optr; // Where to put command line output ostream *optr; ///< Where to put command line output
ostream *fileoptr; // Where to put bulk output ostream *fileoptr; ///< Where to put bulk output
IfaceStatus(const string &prmpt,ostream &os,int4 mxhist=10); IfaceStatus(const string &prmpt,ostream &os,int4 mxhist=10); ///< Constructor
virtual ~IfaceStatus(void); virtual ~IfaceStatus(void); ///< Destructor
void setErrorIsDone(bool val) { errorisdone = val; } void setErrorIsDone(bool val) { errorisdone = val; } ///< Set if processing should terminate on an error
virtual void pushScript(const string &filename,const string &newprompt); virtual void pushScript(const string &filename,const string &newprompt);
virtual void popScript(void); virtual void popScript(void);
void reset(void); void reset(void); ///< Pop any existing script streams and return to processing from the base stream
int4 getNumInputStreamSize(void) const { return promptstack.size(); } int4 getNumInputStreamSize(void) const { return promptstack.size(); } ///< Get depth of script nesting
void writePrompt(void) { *optr << prompt; } void writePrompt(void) { *optr << prompt; } ///< Write the current command prompt to the current output stream
void registerCom(IfaceCommand *fptr, const char *nm1, void registerCom(IfaceCommand *fptr, const char *nm1,
const char *nm2 = (const char *)0, const char *nm2 = (const char *)0,
const char *nm3 = (const char *)0, const char *nm3 = (const char *)0,
const char *nm4 = (const char *)0, const char *nm4 = (const char *)0,
const char *nm5 = (const char *)0); const char *nm5 = (const char *)0);
IfaceData *getData(const string &nm) const; IfaceData *getData(const string &nm) const; ///< Get data associated with a IfaceCommand module
bool runCommand(void); bool runCommand(void); ///< Run the next command
void getHistory(string &line,int4 i) const; void getHistory(string &line,int4 i) const; ///< Get the i-th command line from history
int4 getHistorySize(void) const { return history.size(); } int4 getHistorySize(void) const { return history.size(); } ///< Get the number of command lines in history
virtual bool isStreamFinished(void) const=0; virtual bool isStreamFinished(void) const=0; ///< Return \b true if the current stream is finished
bool isInError(void) const { return inerror; } bool isInError(void) const { return inerror; } ///< Return \b true if the last command failed
void evaluateError(void); void evaluateError(void); ///< Adjust which stream to process based on last error
static void wordsToString(string &res,const vector<string> &list); 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 { class IfaceBaseCommand : public IfaceCommand {
protected: protected:
IfaceStatus *status; IfaceStatus *status; ///< The interface owning this command instance
public: public:
virtual void setData(IfaceStatus *root,IfaceData *data) { status = root; } virtual void setData(IfaceStatus *root,IfaceData *data) { status = root; }
virtual string getModule(void) const { return "base"; } virtual string getModule(void) const { return "base"; }

View file

@ -500,7 +500,7 @@ class JumpTable {
/// \brief An address table index and its corresponding out-edge /// \brief An address table index and its corresponding out-edge
struct IndexPair { struct IndexPair {
int4 blockPosition; ///< Out-edge index for the basic-block int4 blockPosition; ///< Out-edge index for the basic-block
int4 addressIndex; /// Index of address targetting the basic-block int4 addressIndex; ///< Index of address targeting the basic-block
IndexPair(int4 pos,int4 index) { blockPosition = pos; addressIndex = index; } ///< Constructor IndexPair(int4 pos,int4 index) { blockPosition = pos; addressIndex = index; } ///< Constructor
bool operator<(const IndexPair &op2) const; ///< Compare by position then by index bool operator<(const IndexPair &op2) const; ///< Compare by position then by index
static bool compareByPosition(const IndexPair &op1,const IndexPair &op2); ///< Compare just by position static bool compareByPosition(const IndexPair &op1,const IndexPair &op2); ///< Compare just by position

View file

@ -838,6 +838,10 @@ string OptionAliasBlock::apply(Architecture *glb,const string &p1,const string &
return "Alias block level set to " + p1; return "Alias block level set to " + p1;
} }
/// \class OptionMaxInstruction
/// \brief Maximum number of instructions that can be processed in a single function
///
/// The first parameter is an integer specifying the maximum.
string OptionMaxInstruction::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const string OptionMaxInstruction::apply(Architecture *glb,const string &p1,const string &p2,const string &p3) const
{ {

View file

@ -727,7 +727,7 @@ class EmitPrettyPrint : public EmitXml {
void print(const TokenSplit &tok); ///< Output the given token to the low-level emitter void print(const TokenSplit &tok); ///< Output the given token to the low-level emitter
void advanceleft(void); ///< Emit tokens that have been fully committed void advanceleft(void); ///< Emit tokens that have been fully committed
void scan(void); ///< Process a new token void scan(void); ///< Process a new token
void resetDefaultsPrettyPrint(void) { setMaxLineSize(100); } void resetDefaultsPrettyPrint(void) { setMaxLineSize(100); } ///< Reset the defaults
public: public:
EmitPrettyPrint(void); ///< Construct with an initial maximum line size EmitPrettyPrint(void); ///< Construct with an initial maximum line size
virtual ~EmitPrettyPrint(void); virtual ~EmitPrettyPrint(void);

View file

@ -199,9 +199,9 @@ void PrintC::pushSymbolScope(const Symbol *symbol)
} }
} }
/// Emit the elements of the given function's namespace path that distinguish it within /// Emit the elements of the given symbol's namespace path that distinguish it within
/// the current scope. /// the current scope.
/// \param fd is the given function /// \param symbol is the given Symbol
void PrintC::emitSymbolScope(const Symbol *symbol) void PrintC::emitSymbolScope(const Symbol *symbol)
{ {

View file

@ -9085,6 +9085,11 @@ int4 RulePiecePathology::applyOp(PcodeOp *op,Funcdata &data)
return tracePathologyForward(op, data); return tracePathologyForward(op, data);
} }
/// \class RuleXorSwap
/// \brief Simplify limited chains of XOR operations
///
/// `V = (a ^ b) ^ a => V = b`
/// `V = a ^ (b ^ a) => V = b`
void RuleXorSwap::getOpList(vector<uint4> &oplist) const void RuleXorSwap::getOpList(vector<uint4> &oplist) const
{ {

View file

@ -32,10 +32,13 @@ PcodeCacher::~PcodeCacher(void)
delete [] poolstart; delete [] poolstart;
} }
/// Expand the VarnodeData pool so that \e size more elements fit, and return
/// a pointer to first available element.
/// \param size is the number of elements to expand the pool by
/// \return the first available VarnodeData
VarnodeData *PcodeCacher::expandPool(uint4 size) VarnodeData *PcodeCacher::expandPool(uint4 size)
{ // Expand the pool so that -size- more elements fit {
// Return pointer to first available element
uint4 curmax = endpool - poolstart; uint4 curmax = endpool - poolstart;
uint4 cursize = curpool - poolstart; uint4 cursize = curpool - poolstart;
if (cursize + size <= curmax) if (cursize + size <= curmax)
@ -75,18 +78,26 @@ VarnodeData *PcodeCacher::expandPool(uint4 size)
return newpool + cursize; return newpool + cursize;
} }
/// Store off a reference to the Varnode and the absolute index of the next
/// instruction. The Varnode must be an operand of the current instruction.
/// \param ptr is the Varnode reference
void PcodeCacher::addLabelRef(VarnodeData *ptr) void PcodeCacher::addLabelRef(VarnodeData *ptr)
{ // Store off a reference to a label and the next instruction {
// address
label_refs.emplace_back(); label_refs.emplace_back();
label_refs.back().dataptr = ptr; label_refs.back().dataptr = ptr;
label_refs.back().calling_index = issued.size(); label_refs.back().calling_index = issued.size();
} }
/// The label has an id that is referred to by Varnodes holding
/// intra-instruction branch targets, prior to converting
/// them to a \e relative \e branch offset. The label is associated with
/// the absolute index of the next PcodeData object to be issued,
/// facilitating this conversion.
/// \param id is the given id of the label
void PcodeCacher::addLabel(uint4 id) void PcodeCacher::addLabel(uint4 id)
{ // Attach a label to the address of the next instruction {
while(labels.size() <= id) while(labels.size() <= id)
labels.push_back(0xbadbeef); labels.push_back(0xbadbeef);
labels[ id ] = issued.size(); labels[ id ] = issued.size();
@ -101,11 +112,12 @@ void PcodeCacher::clear(void)
labels.clear(); labels.clear();
} }
/// Assuming all the PcodeData has been generated for an
/// instruction, go resolve any relative offsets and back
/// patch their value(s) into the PcodeData
void PcodeCacher::resolveRelatives(void) void PcodeCacher::resolveRelatives(void)
{ // Assuming all the PcodeData has been generated for an {
// instruction, go resolve any relative offsets and back
// patch their value(s) into the PcodeData
list<RelativeRecord>::const_iterator iter; list<RelativeRecord>::const_iterator iter;
for(iter=label_refs.begin();iter!=label_refs.end();++iter) { for(iter=label_refs.begin();iter!=label_refs.end();++iter) {
VarnodeData *ptr = (*iter).dataptr; VarnodeData *ptr = (*iter).dataptr;
@ -119,18 +131,25 @@ void PcodeCacher::resolveRelatives(void)
} }
} }
/// Each p-code operation is presented to the emitter via its dump() method.
/// \param addr is the Address associated with the p-code operation
/// \param emt is the emitter
void PcodeCacher::emit(const Address &addr,PcodeEmit *emt) const void PcodeCacher::emit(const Address &addr,PcodeEmit *emt) const
{ // Emit any cached pcode {
vector<PcodeData>::const_iterator iter; vector<PcodeData>::const_iterator iter;
for(iter=issued.begin();iter!=issued.end();++iter) for(iter=issued.begin();iter!=issued.end();++iter)
emt->dump(addr,(*iter).opc,(*iter).outvar,(*iter).invar,(*iter).isize); emt->dump(addr,(*iter).opc,(*iter).outvar,(*iter).invar,(*iter).isize);
} }
/// \brief Generate a concrete VarnodeData object from the given template (VarnodeTpl)
///
/// \param vntpl is the template to reference
/// \param vn is the object to fill in with concrete values
void SleighBuilder::generateLocation(const VarnodeTpl *vntpl,VarnodeData &vn) void SleighBuilder::generateLocation(const VarnodeTpl *vntpl,VarnodeData &vn)
{ // Generate a concrete varnode -vn- from the template -vntpl- {
vn.space = vntpl->getSpace().fixSpace(*walker); vn.space = vntpl->getSpace().fixSpace(*walker);
vn.size = vntpl->getSize().fix(*walker); vn.size = vntpl->getSize().fix(*walker);
if (vn.space == const_space) if (vn.space == const_space)
@ -143,9 +162,18 @@ void SleighBuilder::generateLocation(const VarnodeTpl *vntpl,VarnodeData &vn)
vn.offset = vn.space->wrapOffset(vntpl->getOffset().fix(*walker)); vn.offset = vn.space->wrapOffset(vntpl->getOffset().fix(*walker));
} }
/// \brief Generate a pointer VarnodeData from a dynamic template (VarnodeTpl)
///
/// The symbol represents a value referenced through a dynamic pointer.
/// This method generates the varnode representing the pointer itself and also
/// returns the address space in anticipation of generating the LOAD or STORE
/// that actually manipulates the value.
/// \param vntpl is the dynamic template to reference
/// \param vn is the object to fill with concrete values
/// \return the address space being pointed to
AddrSpace *SleighBuilder::generatePointer(const VarnodeTpl *vntpl,VarnodeData &vn) AddrSpace *SleighBuilder::generatePointer(const VarnodeTpl *vntpl,VarnodeData &vn)
{ // Generate the pointer varnode -vn- from a dynamic template -vntpl- {
const FixedHandle &hand(walker->getFixedHandle(vntpl->getOffset().getHandleIndex())); const FixedHandle &hand(walker->getFixedHandle(vntpl->getOffset().getHandleIndex()));
vn.space = hand.offset_space; vn.space = hand.offset_space;
vn.size = hand.offset_size; vn.size = hand.offset_size;
@ -218,9 +246,17 @@ void SleighBuilder::dump(OpTpl *op)
} }
} }
/// \brief Build a named p-code section of a constructor that contains only implied BUILD directives
///
/// If a named section of a constructor is empty, we still need to walk
/// through any subtables that might contain p-code in their named sections.
/// This method treats each subtable operand as an implied \e build directive,
/// in the otherwise empty section.
/// \param ct is the matching currently Constructor being built
/// \param secnum is the particular \e named section number to build
void SleighBuilder::buildEmpty(Constructor *ct,int4 secnum) void SleighBuilder::buildEmpty(Constructor *ct,int4 secnum)
{ // Build a named p-code section of a constructor that contains only implied BUILD directives {
int4 numops = ct->getNumOperands(); int4 numops = ct->getNumOperands();
for(int4 i=0;i<numops;++i) { for(int4 i=0;i<numops;++i) {
@ -238,12 +274,23 @@ void SleighBuilder::buildEmpty(Constructor *ct,int4 secnum)
} }
} }
/// Bits used to make temporary registers unique across multiple instructions
/// are generated based on the given address.
/// \param addr is the given Address
void SleighBuilder::setUniqueOffset(const Address &addr) void SleighBuilder::setUniqueOffset(const Address &addr)
{ {
uniqueoffset = (addr.getOffset() & uniquemask)<<4; uniqueoffset = (addr.getOffset() & uniquemask)<<4;
} }
/// \brief Constructor
///
/// \param w is the parsed instruction
/// \param dcache is a cache of nearby instruction parses
/// \param pc will hold the PcodeData and VarnodeData objects produced by \b this builder
/// \param cspc is the constant address space
/// \param uspc is the unique address space
/// \param umask is the mask to use to find unique bits within an Address
SleighBuilder::SleighBuilder(ParserWalker *w,DisassemblyCache *dcache,PcodeCacher *pc,AddrSpace *cspc, SleighBuilder::SleighBuilder(ParserWalker *w,DisassemblyCache *dcache,PcodeCacher *pc,AddrSpace *cspc,
AddrSpace *uspc,uint4 umask) AddrSpace *uspc,uint4 umask)
: PcodeBuilder(0) : PcodeBuilder(0)
@ -259,7 +306,8 @@ SleighBuilder::SleighBuilder(ParserWalker *w,DisassemblyCache *dcache,PcodeCache
void SleighBuilder::appendBuild(OpTpl *bld,int4 secnum) void SleighBuilder::appendBuild(OpTpl *bld,int4 secnum)
{ // Append pcode for a particular build statement {
// Append p-code for a particular build statement
int4 index = bld->getIn(0)->getOffset().getReal(); // Recover operand index from build statement int4 index = bld->getIn(0)->getOffset().getReal(); // Recover operand index from build statement
// Check if operand is a subtable // Check if operand is a subtable
SubtableSymbol *sym = (SubtableSymbol *)walker->getConstructor()->getOperand(index)->getDefiningSymbol(); SubtableSymbol *sym = (SubtableSymbol *)walker->getConstructor()->getOperand(index)->getDefiningSymbol();
@ -283,7 +331,8 @@ void SleighBuilder::appendBuild(OpTpl *bld,int4 secnum)
void SleighBuilder::delaySlot(OpTpl *op) void SleighBuilder::delaySlot(OpTpl *op)
{ // Append pcode for an entire instruction (delay slot) {
// Append pcode for an entire instruction (delay slot)
// in the middle of the current instruction // in the middle of the current instruction
ParserWalker *tmp = walker; ParserWalker *tmp = walker;
uintb olduniqueoffset = uniqueoffset; uintb olduniqueoffset = uniqueoffset;
@ -319,7 +368,8 @@ void SleighBuilder::setLabel(OpTpl *op)
void SleighBuilder::appendCrossBuild(OpTpl *bld,int4 secnum) void SleighBuilder::appendCrossBuild(OpTpl *bld,int4 secnum)
{ // Weave in the p-code section from an instruction at another address {
// Weave in the p-code section from an instruction at another address
// bld-param(0) contains the address of the instruction // bld-param(0) contains the address of the instruction
// bld-param(1) contains the section number // bld-param(1) contains the section number
if (secnum>=0) if (secnum>=0)
@ -352,6 +402,8 @@ void SleighBuilder::appendCrossBuild(OpTpl *bld,int4 secnum)
uniqueoffset = olduniqueoffset; uniqueoffset = olduniqueoffset;
} }
/// \param min is the minimum number of allocations before a reuse is expected
/// \param hashsize is the number of elements in the hash-table
void DisassemblyCache::initialize(int4 min,int4 hashsize) void DisassemblyCache::initialize(int4 min,int4 hashsize)
{ {
@ -382,6 +434,10 @@ void DisassemblyCache::free(void)
delete [] hashtable; delete [] hashtable;
} }
/// \param ccache is the ContextCache front-end shared across all the parser contexts
/// \param cspace is the constant address space used for minting constant Varnodes
/// \param cachesize is the number of distinct ParserContext objects in this cache
/// \param windowsize is the size of the ParserContext hash-table
DisassemblyCache::DisassemblyCache(ContextCache *ccache,AddrSpace *cspace,int4 cachesize,int4 windowsize) DisassemblyCache::DisassemblyCache(ContextCache *ccache,AddrSpace *cspace,int4 cachesize,int4 windowsize)
{ {
@ -390,13 +446,17 @@ DisassemblyCache::DisassemblyCache(ContextCache *ccache,AddrSpace *cspace,int4 c
initialize(cachesize,windowsize); // Set default settings for the cache initialize(cachesize,windowsize); // Set default settings for the cache
} }
/// Return a (possibly cached) ParserContext that is associated with \e addr
/// If n different calls to this interface are made with n different Addresses, if
/// - n <= minimumreuse AND
/// - all the addresses are within the windowsize (=mask+1)
///
/// then the cacher guarantees that you get all different ParserContext objects
/// \param addr is the Address to disassemble at
/// \return the ParserContext associated with the address
ParserContext *DisassemblyCache::getParserContext(const Address &addr) ParserContext *DisassemblyCache::getParserContext(const Address &addr)
{ // Return a (possibly cached) ParserContext that is associated with -addr- {
// If n different calls to this interface are made with n different Addresses, if
// n <= minimumreuse AND
// all the addresses are within the windowsize (=mask+1)
// then the cacher guarantees that you get all different ParserContext objects
int4 hashindex = ((int4) addr.getOffset()) & mask; int4 hashindex = ((int4) addr.getOffset()) & mask;
ParserContext *res = hashtable[ hashindex ]; ParserContext *res = hashtable[ hashindex ];
if (res->getAddr() == addr) if (res->getAddr() == addr)
@ -411,6 +471,8 @@ ParserContext *DisassemblyCache::getParserContext(const Address &addr)
return res; return res;
} }
/// \param ld is the LoadImage to draw program bytes from
/// \param c_db is the context database
Sleigh::Sleigh(LoadImage *ld,ContextDatabase *c_db) Sleigh::Sleigh(LoadImage *ld,ContextDatabase *c_db)
: SleighBase() : SleighBase()
@ -435,10 +497,13 @@ Sleigh::~Sleigh(void)
clearForDelete(); clearForDelete();
} }
/// Completely clear everything except the base and reconstruct
/// with a new LoadImage and ContextDatabase
/// \param ld is the new LoadImage
/// \param c_db is the new ContextDatabase
void Sleigh::reset(LoadImage *ld,ContextDatabase *c_db) void Sleigh::reset(LoadImage *ld,ContextDatabase *c_db)
{ // Completely clear everything except the base and reconstruct {
// with a new loader and context
clearForDelete(); clearForDelete();
pcode_cache.clear(); pcode_cache.clear();
loader = ld; loader = ld;
@ -447,6 +512,8 @@ void Sleigh::reset(LoadImage *ld,ContextDatabase *c_db)
discache = (DisassemblyCache *)0; discache = (DisassemblyCache *)0;
} }
/// The .sla file from the document store is loaded and cache objects are prepared
/// \param store is the document store containing the main \<sleigh> tag.
void Sleigh::initialize(DocumentStorage &store) void Sleigh::initialize(DocumentStorage &store)
{ {
@ -467,10 +534,18 @@ void Sleigh::initialize(DocumentStorage &store)
discache = new DisassemblyCache(cache,getConstantSpace(),parser_cachesize,parser_windowsize); discache = new DisassemblyCache(cache,getConstantSpace(),parser_cachesize,parser_windowsize);
} }
/// \brief Obtain a parse tree for the instruction at the given address
///
/// The tree may be cached from a previous access. If the address
/// has not been parsed, disassembly is performed, and a new parse tree
/// is prepared. Depending on the desired \e state, the parse tree
/// can be prepared either for disassembly or for p-code generation.
/// \param addr is the given address of the instruction
/// \param state is the desired parse state.
/// \return the parse tree object (ParseContext)
ParserContext *Sleigh::obtainContext(const Address &addr,int4 state) const ParserContext *Sleigh::obtainContext(const Address &addr,int4 state) const
{ // Obtain a ParserContext for the instruction at the given -addr-. This may be cached. {
// Make sure parsing has proceeded to at least the given -state.
ParserContext *pos = discache->getParserContext(addr); ParserContext *pos = discache->getParserContext(addr);
int4 curstate = pos->getParserState(); int4 curstate = pos->getParserState();
if (curstate >= state) if (curstate >= state)
@ -485,10 +560,11 @@ ParserContext *Sleigh::obtainContext(const Address &addr,int4 state) const
return pos; return pos;
} }
/// Resolve \e all the constructors involved in the instruction at the indicated address
/// \param pos is the parse object that will hold the resulting tree
void Sleigh::resolve(ParserContext &pos) const void Sleigh::resolve(ParserContext &pos) const
{ // Resolve ALL the constructors involved in the {
// instruction at this address
loader->loadFill(pos.getBuffer(),16,pos.getAddr()); loader->loadFill(pos.getBuffer(),16,pos.getAddr());
ParserWalkerChange walker(&pos); ParserWalkerChange walker(&pos);
pos.deallocateState(walker); // Clear the previous resolve and initialize the walker pos.deallocateState(walker); // Clear the previous resolve and initialize the walker
@ -538,9 +614,12 @@ void Sleigh::resolve(ParserContext &pos) const
pos.setParserState(ParserContext::disassembly); pos.setParserState(ParserContext::disassembly);
} }
/// Resolve handle templates for the given parse tree, assuming Constructors
/// are already resolved.
/// \param pos is the given parse tree
void Sleigh::resolveHandles(ParserContext &pos) const void Sleigh::resolveHandles(ParserContext &pos) const
{ // Resolve handles (assuming Constructors already resolved) {
TripleSymbol *triple; TripleSymbol *triple;
Constructor *ct; Constructor *ct;
int4 oper,numoper; int4 oper,numoper;
@ -671,7 +750,7 @@ int4 Sleigh::oneInstruction(PcodeEmit &emit,const Address &baseaddr) const
void Sleigh::registerContext(const string &name,int4 sbit,int4 ebit) void Sleigh::registerContext(const string &name,int4 sbit,int4 ebit)
{ // Inform translator of existence of context variable {
context_db->registerVariable(name,sbit,ebit); context_db->registerVariable(name,sbit,ebit);
} }

View file

@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/// \file sleigh.hh
/// \brief Classes and utilities for the main SLEIGH engine
#ifndef __SLEIGH__ #ifndef __SLEIGH__
#define __SLEIGH__ #define __SLEIGH__
@ -20,29 +24,52 @@
class LoadImage; class LoadImage;
/// \brief Class for describing a relative p-code branch destination
///
/// An intra-instruction p-code branch takes a \e relative operand.
/// The actual value produced during p-code generation is calculated at
/// the last second using \b this. It stores the index of the BRANCH
/// instruction and a reference to its destination operand. This initially
/// holds a reference to a destination \e label symbol, but is later updated
/// with the final relative value.
struct RelativeRecord { struct RelativeRecord {
VarnodeData *dataptr; // Record containing relative offset VarnodeData *dataptr; ///< Varnode indicating relative offset
uintb calling_index; // Index of instruction containing relative offset uintb calling_index; ///< Index of instruction containing relative offset
}; };
struct PcodeData { // Data for building one pcode instruction /// \brief Data for building one p-code instruction
OpCode opc; ///
VarnodeData *outvar; // Points to outvar is there is an output /// Raw data used by the emitter to produce a single PcodeOp
VarnodeData *invar; // Inputs struct PcodeData {
int4 isize; // Number of inputs OpCode opc; ///< The op code
VarnodeData *outvar; ///< Output Varnode data (or null)
VarnodeData *invar; ///< Array of input Varnode data
int4 isize; ///< Number of input Varnodes
}; };
class PcodeCacher { // Cached chunk of pcode, prior to emitting /// \brief Class for caching a chunk of p-code, prior to emitting
VarnodeData *poolstart; ///
VarnodeData *curpool; /// The engine accumulates PcodeData and VarnodeData objects for
VarnodeData *endpool; /// a single instruction. Once the full instruction is constructed,
vector<PcodeData> issued; /// the objects are passed to the emitter (PcodeEmit) via the emit() method.
list<RelativeRecord> label_refs; // References to labels /// The class acts as a pool of memory for PcodeData and VarnodeData objects
vector<uintb> labels; // Locations of labels /// that can be reused repeatedly to emit multiple instructions.
VarnodeData *expandPool(uint4 size); class PcodeCacher {
VarnodeData *poolstart; ///< Start of the pool of VarnodeData objects
VarnodeData *curpool; ///< First unused VarnodeData
VarnodeData *endpool; ///< End of the pool of VarnodeData objects
vector<PcodeData> issued; ///< P-code ops issued for the current instruction
list<RelativeRecord> label_refs; ///< References to labels
vector<uintb> labels; ///< Locations of labels
VarnodeData *expandPool(uint4 size); ///< Expand the memory pool
public: public:
PcodeCacher(void); PcodeCacher(void); ///< Constructor
~PcodeCacher(void); ~PcodeCacher(void); ///< Destructor
/// \brief Allocate data objects for a new set of Varnodes
///
/// \param size is the number of objects to allocate
/// \return a pointer to the array of available VarnodeData objects
VarnodeData *allocateVarnodes(uint4 size) { VarnodeData *allocateVarnodes(uint4 size) {
VarnodeData *newptr = curpool + size; VarnodeData *newptr = curpool + size;
if (newptr <= endpool) { if (newptr <= endpool) {
@ -52,6 +79,10 @@ public:
} }
return expandPool(size); return expandPool(size);
} }
/// \brief Allocate a data object for a new p-code operation
///
/// \return the new PcodeData object
PcodeData *allocateInstruction(void) { PcodeData *allocateInstruction(void) {
issued.emplace_back(); issued.emplace_back();
PcodeData *res = &issued.back(); PcodeData *res = &issued.back();
@ -59,41 +90,54 @@ public:
res->invar = (VarnodeData *)0; res->invar = (VarnodeData *)0;
return res; return res;
} }
void addLabelRef(VarnodeData *ptr); void addLabelRef(VarnodeData *ptr); ///< Denote a Varnode holding a \e relative \e branch offset
void addLabel(uint4 id); void addLabel(uint4 id); ///< Attach a label to the \e next p-code instruction
void clear(void); void clear(void); ///< Reset the cache so that all objects are unallocated
void resolveRelatives(void); void resolveRelatives(void); ///< Rewrite branch target Varnodes as \e relative offsets
void emit(const Address &addr,PcodeEmit *emt) const; void emit(const Address &addr,PcodeEmit *emt) const; ///< Pass the cached p-code data to the emitter
}; };
/// \brief A container for disassembly context used by the SLEIGH engine
///
/// This acts as a factor for the ParserContext objects which are used to disassemble
/// a single instruction. These all share a ContextCache which is a front end for
/// accessing the ContextDatabase and resolving context variables from the SLEIGH spec.
/// ParserContext objects are stored in a hash-table keyed by the address of the instruction.
class DisassemblyCache { class DisassemblyCache {
ContextCache *contextcache; ContextCache *contextcache; ///< Cached values from the ContextDatabase
AddrSpace *constspace; AddrSpace *constspace; ///< The constant address space
int4 minimumreuse; // Can call getParserContext this many times, before a ParserContext is reused int4 minimumreuse; ///< Can call getParserContext this many times, before a ParserContext is reused
uint4 mask; // Size of the hashtable in form 2^n-1 uint4 mask; ///< Size of the hashtable in form 2^n-1
ParserContext **list; // (circular) array of currently cached ParserContext objects ParserContext **list; ///< (circular) array of currently cached ParserContext objects
int4 nextfree; // Current end/beginning of circular list int4 nextfree; ///< Current end/beginning of circular list
ParserContext **hashtable; // Hashtable for looking up ParserContext via Address ParserContext **hashtable; ///< Hashtable for looking up ParserContext via Address
void initialize(int4 min,int4 hashsize); void initialize(int4 min,int4 hashsize); ///< Initialize the hash-table of ParserContexts
void free(void); void free(void); ///< Free the hash-table of ParserContexts
public: public:
DisassemblyCache(ContextCache *ccache,AddrSpace *cspace,int4 cachesize,int4 windowsize); DisassemblyCache(ContextCache *ccache,AddrSpace *cspace,int4 cachesize,int4 windowsize); ///< Constructor
~DisassemblyCache(void) { free(); } ~DisassemblyCache(void) { free(); } ///< Destructor
ParserContext *getParserContext(const Address &addr); ParserContext *getParserContext(const Address &addr); ///< Get the parser for a particular Address
}; };
/// \brief Build p-code from a pre-parsed instruction
///
/// Through the build() method, \b this walks the parse tree and prepares data
/// for final emission as p-code. (The final emitting is done separately through the
/// PcodeCacher.emit() method). Generally, only p-code for one instruction is prepared.
/// But, through the \b delay-slot mechanism, build() may recursively visit
/// additional instructions.
class SleighBuilder : public PcodeBuilder { class SleighBuilder : public PcodeBuilder {
virtual void dump( OpTpl *op ); virtual void dump( OpTpl *op );
AddrSpace *const_space; AddrSpace *const_space; ///< The constant address space
AddrSpace *uniq_space; AddrSpace *uniq_space; ///< The unique address space
uintb uniquemask; uintb uniquemask; ///< Mask of address bits to use to uniquify temporary registers
uintb uniqueoffset; uintb uniqueoffset; ///< Uniquifier bits for \b this instruction
DisassemblyCache *discache; DisassemblyCache *discache; ///< Cache of disassembled instructions
PcodeCacher *cache; PcodeCacher *cache; ///< Cache accumulating p-code data for the instruction
void buildEmpty(Constructor *ct,int4 secnum); void buildEmpty(Constructor *ct,int4 secnum);
void generateLocation(const VarnodeTpl *vntpl,VarnodeData &vn); void generateLocation(const VarnodeTpl *vntpl,VarnodeData &vn);
AddrSpace *generatePointer(const VarnodeTpl *vntpl,VarnodeData &vn); AddrSpace *generatePointer(const VarnodeTpl *vntpl,VarnodeData &vn);
void setUniqueOffset(const Address &addr); void setUniqueOffset(const Address &addr); ///< Set uniquifying bits for the current instruction
public: public:
SleighBuilder(ParserWalker *w,DisassemblyCache *dcache,PcodeCacher *pc,AddrSpace *cspc,AddrSpace *uspc,uint4 umask); SleighBuilder(ParserWalker *w,DisassemblyCache *dcache,PcodeCacher *pc,AddrSpace *cspc,AddrSpace *uspc,uint4 umask);
virtual void appendBuild(OpTpl *bld,int4 secnum); virtual void appendBuild(OpTpl *bld,int4 secnum);
@ -102,21 +146,31 @@ public:
virtual void appendCrossBuild(OpTpl *bld,int4 secnum); virtual void appendCrossBuild(OpTpl *bld,int4 secnum);
}; };
/// \brief A full SLEIGH engine
///
/// Its provided with a LoadImage of the bytes to be disassembled and
/// a ContextDatabase.
///
/// Assembly is produced via the printAssembly() method, provided with an
/// AssemblyEmit object and an Address.
///
/// P-code is produced via the oneInstruction() method, provided with a PcodeEmit
/// object and an Address.
class Sleigh : public SleighBase { class Sleigh : public SleighBase {
LoadImage *loader; LoadImage *loader; ///< The mapped bytes in the program
ContextDatabase *context_db; ContextDatabase *context_db; ///< Database of context values steering disassembly
ContextCache *cache; ContextCache *cache; ///< Cache of recently used context values
mutable DisassemblyCache *discache; mutable DisassemblyCache *discache; ///< Cache of recently parsed instructions
mutable PcodeCacher pcode_cache; mutable PcodeCacher pcode_cache; ///< Cache of p-code data just prior to emitting
void clearForDelete(void); void clearForDelete(void); ///< Delete the context and disassembly caches
protected: protected:
ParserContext *obtainContext(const Address &addr,int4 state) const; ParserContext *obtainContext(const Address &addr,int4 state) const;
void resolve(ParserContext &pos) const; void resolve(ParserContext &pos) const; ///< Generate a parse tree suitable for disassembly
void resolveHandles(ParserContext &pos) const; void resolveHandles(ParserContext &pos) const; ///< Prepare the parse tree for p-code generation
public: public:
Sleigh(LoadImage *ld,ContextDatabase *c_db); Sleigh(LoadImage *ld,ContextDatabase *c_db); ///< Constructor
virtual ~Sleigh(void); virtual ~Sleigh(void); ///< Destructor
void reset(LoadImage *ld,ContextDatabase *c_db); void reset(LoadImage *ld,ContextDatabase *c_db); ///< Reset the engine for a new program
virtual void initialize(DocumentStorage &store); virtual void initialize(DocumentStorage &store);
virtual void registerContext(const string &name,int4 sbit,int4 ebit); virtual void registerContext(const string &name,int4 sbit,int4 ebit);
virtual void setContextDefault(const string &nm,uintm val); virtual void setContextDefault(const string &nm,uintm val);

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/// \file ghidra_string.hh /// \file string_ghidra.hh
/// \brief Implementation of the StringManager through the ghidra client /// \brief Implementation of the StringManager through the ghidra client
#ifndef __STRING_GHIDRA__ #ifndef __STRING_GHIDRA__

View file

@ -30,10 +30,11 @@ class Architecture;
/// Stores the decoded string until its needed for presentation. /// Stores the decoded string until its needed for presentation.
class StringManager { class StringManager {
protected: protected:
/// \brief String data (a sequence of bytes) stored by StringManager
class StringData { class StringData {
public: public:
bool isTruncated; // \b true if the the string is truncated bool isTruncated; ///< \b true if the the string is truncated
vector<uint1> byteData; // UTF8 encoded string data vector<uint1> byteData; ///< UTF8 encoded string data
}; };
map<Address,StringData> stringMap; ///< Map from address to string data map<Address,StringData> stringMap; ///< Map from address to string data
int4 maximumChars; ///< Maximum characters in a string before truncating int4 maximumChars; ///< Maximum characters in a string before truncating

View file

@ -201,7 +201,7 @@ public:
bool isFloatExtension(void) const { return (pieces.size() == 1); } ///< Does this record extend a float varnode bool isFloatExtension(void) const { return (pieces.size() == 1); } ///< Does this record extend a float varnode
const VarnodeData &getPiece(int4 i) const { return pieces[i]; } ///< Get the i-th piece const VarnodeData &getPiece(int4 i) const { return pieces[i]; } ///< Get the i-th piece
const VarnodeData &getUnified(void) const { return unified; } ///< Get the Varnode whole const VarnodeData &getUnified(void) const { return unified; } ///< Get the Varnode whole
Address getEquivalentAddress(uintb offset,int4 &pos) const; ///< Given offset in \join space, get equivalent address of piece Address getEquivalentAddress(uintb offset,int4 &pos) const; ///< Given offset in \e join space, get equivalent address of piece
bool operator<(const JoinRecord &op2) const; ///< Compare records lexigraphically by pieces bool operator<(const JoinRecord &op2) const; ///< Compare records lexigraphically by pieces
}; };

View file

@ -318,7 +318,7 @@ void Datatype::saveXmlRef(ostream &s) const
/// A CPUI_PTRSUB must act on a pointer data-type where the given offset addresses a component. /// A CPUI_PTRSUB must act on a pointer data-type where the given offset addresses a component.
/// Perform this check. /// Perform this check.
/// \param is the given offset /// \param offset is the given offset
/// \return \b true if \b this is a suitable PTRSUB data-type /// \return \b true if \b this is a suitable PTRSUB data-type
bool Datatype::isPtrsubMatching(uintb offset) const bool Datatype::isPtrsubMatching(uintb offset) const
@ -422,7 +422,7 @@ uint8 Datatype::hashName(const string &nm)
/// The hashing is reversible by feeding the output ID back into this function with the same size. /// The hashing is reversible by feeding the output ID back into this function with the same size.
/// \param id is the given ID to (de)uniquify /// \param id is the given ID to (de)uniquify
/// \param size is the instance size of the structure /// \param size is the instance size of the structure
/// \param return the (de)uniquified id /// \return the (de)uniquified id
uint8 Datatype::hashSize(uint8 id,int4 size) uint8 Datatype::hashSize(uint8 id,int4 size)
{ {

View file

@ -123,6 +123,7 @@ public:
/// Given a specific language and PcodeOp, emit the expression rooted at the operation. /// Given a specific language and PcodeOp, emit the expression rooted at the operation.
/// \param lng is the PrintLanguage to emit /// \param lng is the PrintLanguage to emit
/// \param op is the specific PcodeOp /// \param op is the specific PcodeOp
/// \param readOp is the PcodeOp consuming the output (or null)
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const=0; virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const=0;
/// \brief Print (for debugging purposes) \b this specific PcodeOp to the stream /// \brief Print (for debugging purposes) \b this specific PcodeOp to the stream

View file

@ -22,7 +22,7 @@
/// properly, in which case the union of the two ranges can exist without /// properly, in which case the union of the two ranges can exist without
/// destroying data-type information. /// destroying data-type information.
/// \param b is the range to reconcile with \b this /// \param b is the range to reconcile with \b this
/// \param \b true if the data-type information can be reconciled /// \return \b true if the data-type information can be reconciled
bool RangeHint::reconcile(const RangeHint *b) const bool RangeHint::reconcile(const RangeHint *b) const
{ {

View file

@ -399,7 +399,7 @@ void Varnode::setSymbolEntry(SymbolEntry *entry)
/// This used when there is a constant address reference to the Symbol and the Varnode holds the /// This used when there is a constant address reference to the Symbol and the Varnode holds the
/// reference, not the actual value of the Symbol. /// reference, not the actual value of the Symbol.
/// \param entry is a mapping to the given Symbol /// \param entry is a mapping to the given Symbol
/// \off is the byte offset into the Symbol of the reference /// \param off is the byte offset into the Symbol of the reference
void Varnode::setSymbolReference(SymbolEntry *entry,int4 off) void Varnode::setSymbolReference(SymbolEntry *entry,int4 off)
{ {