remote debug console

This commit is contained in:
caheckman 2020-05-15 12:44:49 -04:00
parent 0f0a82b8b1
commit 36c5a5c62b
9 changed files with 201 additions and 47 deletions

View file

@ -182,6 +182,12 @@ bool Action::setBreakPoint(uint4 tp,const string &specify)
return false; return false;
} }
void Action::clearBreakPoints(void)
{
breakpoint = 0;
}
/// If enabled, a warning will be printed whenever this action applies. /// If enabled, a warning will be printed whenever this action applies.
/// The warning can be toggled for \b this Action or some sub-action by /// The warning can be toggled for \b this Action or some sub-action by
/// specifying its name. /// specifying its name.
@ -371,6 +377,15 @@ void ActionGroup::addAction(Action *ac)
list.push_back(ac); list.push_back(ac);
} }
void ActionGroup::clearBreakPoints(void)
{
vector<Action *>::const_iterator iter;
for(iter=list.begin();iter!= list.end();++iter)
(*iter)->clearBreakPoints();
Action::clearBreakPoints();
}
Action *ActionGroup::clone(const ActionGroupList &grouplist) const Action *ActionGroup::clone(const ActionGroupList &grouplist) const
{ {
@ -870,6 +885,15 @@ int4 ActionPool::apply(Funcdata &data)
return 0; // Indicate successful completion return 0; // Indicate successful completion
} }
void ActionPool::clearBreakPoints(void)
{
vector<Rule *>::const_iterator iter;
for(iter=allrules.begin();iter!=allrules.end();++iter)
(*iter)->clearBreakPoints();
Action::clearBreakPoints();
}
Action *ActionPool::clone(const ActionGroupList &grouplist) const Action *ActionPool::clone(const ActionGroupList &grouplist) const
{ {

View file

@ -99,6 +99,7 @@ public:
virtual void printStatistics(ostream &s) const; ///< Dump statistics to stream virtual void printStatistics(ostream &s) const; ///< Dump statistics to stream
int4 perform(Funcdata &data); ///< Perform this action (if necessary) int4 perform(Funcdata &data); ///< Perform this action (if necessary)
bool setBreakPoint(uint4 tp,const string &specify); ///< Set a breakpoint on this action bool setBreakPoint(uint4 tp,const string &specify); ///< Set a breakpoint on this action
virtual void clearBreakPoints(void); ///< Clear all breakpoints set on \b this Action
bool setWarning(bool val,const string &specify); ///< Set a warning on this action bool setWarning(bool val,const string &specify); ///< Set a warning on this action
bool disableRule(const string &specify); ///< Disable a specific Rule within \b this bool disableRule(const string &specify); ///< Disable a specific Rule within \b this
bool enableRule(const string &specify); ///< Enable a specific Rule within \b this bool enableRule(const string &specify); ///< Enable a specific Rule within \b this
@ -147,6 +148,7 @@ public:
ActionGroup(uint4 f,const string &nm) : Action(f,nm,"") {} ///< Construct given properties and a name ActionGroup(uint4 f,const string &nm) : Action(f,nm,"") {} ///< Construct given properties and a name
virtual ~ActionGroup(void); ///< Destructor virtual ~ActionGroup(void); ///< Destructor
void addAction(Action *ac); ///< Add an Action to the group void addAction(Action *ac); ///< Add an Action to the group
virtual void clearBreakPoints(void);
virtual Action *clone(const ActionGroupList &grouplist) const; virtual Action *clone(const ActionGroupList &grouplist) const;
virtual void reset(Funcdata &data); virtual void reset(Funcdata &data);
virtual void resetStats(void); virtual void resetStats(void);
@ -216,6 +218,7 @@ public:
uint4 getNumApply(void) { return count_apply; } ///< Get number of successful applications uint4 getNumApply(void) { return count_apply; } ///< Get number of successful applications
void setBreak(uint4 tp) { breakpoint |= tp; } ///< Set a breakpoint on \b this Rule void setBreak(uint4 tp) { breakpoint |= tp; } ///< Set a breakpoint on \b this Rule
void clearBreak(uint4 tp) { breakpoint &= ~tp; } ///< Clear a breakpoint on \b this Rule void clearBreak(uint4 tp) { breakpoint &= ~tp; } ///< Clear a breakpoint on \b this Rule
void clearBreakPoints(void) { breakpoint = 0; } ///< Clear all breakpoints on \b this Rule
void turnOnWarnings(void) { flags |= warnings_on; } ///< Enable warnings for \b this Rule void turnOnWarnings(void) { flags |= warnings_on; } ///< Enable warnings for \b this Rule
void turnOffWarnings(void) { flags &= ~warnings_on; } ///< Disable warnings for \b this Rule void turnOffWarnings(void) { flags &= ~warnings_on; } ///< Disable warnings for \b this Rule
bool isDisabled(void) const { return ((flags & type_disable)!=0); } ///< Return \b true if \b this Rule is disabled bool isDisabled(void) const { return ((flags & type_disable)!=0); } ///< Return \b true if \b this Rule is disabled
@ -266,6 +269,7 @@ public:
ActionPool(uint4 f,const string &nm) : Action(f,nm,"") {} ///< Construct providing properties and name ActionPool(uint4 f,const string &nm) : Action(f,nm,"") {} ///< Construct providing properties and name
virtual ~ActionPool(void); ///< Destructor virtual ~ActionPool(void); ///< Destructor
void addRule(Rule *rl); ///< Add a Rule to the pool void addRule(Rule *rl); ///< Add a Rule to the pool
virtual void clearBreakPoints(void);
virtual Action *clone(const ActionGroupList &grouplist) const; virtual Action *clone(const ActionGroupList &grouplist) const;
virtual void reset(Funcdata &data); virtual void reset(Funcdata &data);
virtual void resetStats(void); virtual void resetStats(void);

View file

@ -17,44 +17,46 @@
#include "flow.hh" #include "flow.hh"
#include "blockaction.hh" #include "blockaction.hh"
#ifdef OPACTION_DEBUG #ifdef __REMOTE_SOCKET__
#include "ifacedecomp.hh" #include "ifacedecomp.hh"
static IfaceStatus *ghidra_dcp = (IfaceStatus *)0; static IfaceStatus *ghidra_dcp = (IfaceStatus *)0;
static RemoteSocket *remote = (RemoteSocket *)0;
void turn_on_debugging(Funcdata *fd) /// \brief Establish a debug console for decompilation of the given function
///
/// Attempt to connect to a UNIX domain socket and direct the i/o streams to
/// the decompiler console interface. The socket must have been previously established
/// by another process.
/// From the command-line, `nc -l -U /tmp/ghidrasocket` for example.
void connect_to_console(Funcdata *fd)
{ {
if (ghidra_dcp == (IfaceStatus *)0) { if (remote == (RemoteSocket *)0) {
ghidra_dcp = new IfaceStatus("[ghidradbg]> ",cin,cout); remote = new RemoteSocket();
ghidra_dcp->optr = (ostream *)0; if (remote->open("/tmp/ghidrasocket")) {
ghidra_dcp->fileoptr = (ostream *)0; ghidra_dcp = new IfaceStatus("[ghidradbg]> ",*remote->getInputStream(),*remote->getOutputStream());
IfaceCapability::registerAllCommands(ghidra_dcp); IfaceCapability::registerAllCommands(ghidra_dcp);
}
} }
// Check if debug script exists if (!remote->isSocketOpen())
ifstream is("ghidracom.txt"); return;
if (!is) return;
is.close();
IfaceDecompData *decomp_data = (IfaceDecompData *)ghidra_dcp->getData("decompile"); IfaceDecompData *decomp_data = (IfaceDecompData *)ghidra_dcp->getData("decompile");
decomp_data->fd = fd; decomp_data->fd = fd;
decomp_data->conf = fd->getArch(); decomp_data->conf = fd->getArch();
ghidra_dcp->pushScript("ghidracom.txt","ghidradbg> "); ostream *oldPrintStream = decomp_data->conf->print->getOutputStream();
ghidra_dcp->optr = new ofstream("ghidrares.txt"); bool emitXml = decomp_data->conf->print->emitsXml();
ghidra_dcp->fileoptr = ghidra_dcp->optr; decomp_data->conf->print->setOutputStream(remote->getOutputStream());
decomp_data->conf->setDebugStream(ghidra_dcp->optr); decomp_data->conf->print->setXML(false);
ghidra_dcp->reset();
mainloop(ghidra_dcp); mainloop(ghidra_dcp);
ghidra_dcp->popScript(); decomp_data->conf->clearAnalysis(fd);
} decomp_data->conf->print->setOutputStream(oldPrintStream);
decomp_data->conf->print->setXML(emitXml);
void turn_off_debugging(Funcdata *fd) fd->debugDisable();
decomp_data->conf->allacts.getCurrent()->clearBreakPoints();
{
if (ghidra_dcp->optr != (ostream *)0) {
delete ghidra_dcp->optr;
ghidra_dcp->optr = (ostream *)0;
}
} }
#endif #endif
@ -213,9 +215,13 @@ void DeregisterProgram::loadParameters(void)
void DeregisterProgram::rawAction(void) void DeregisterProgram::rawAction(void)
{ {
#ifdef OPACTION_DEBUG #ifdef __REMOTE_SOCKET__
if (ghidra_dcp != (IfaceStatus *)0) if (ghidra_dcp != (IfaceStatus *)0)
delete ghidra_dcp; delete ghidra_dcp;
if (remote != (RemoteSocket *)0)
delete remote;
ghidra_dcp = (IfaceStatus *)0;
remote = (RemoteSocket *)0;
#endif #endif
if (ghidra != (ArchitectureGhidra *)0) { if (ghidra != (ArchitectureGhidra *)0) {
res = 1; res = 1;
@ -284,14 +290,11 @@ void DecompileAt::rawAction(void)
throw LowlevelError(s.str()); throw LowlevelError(s.str());
} }
if (!fd->isProcStarted()) { if (!fd->isProcStarted()) {
#ifdef OPACTION_DEBUG #ifdef __REMOTE_SOCKET__
turn_on_debugging(fd); connect_to_console(fd);
#endif #endif
ghidra->allacts.getCurrent()->reset( *fd ); ghidra->allacts.getCurrent()->reset( *fd );
ghidra->allacts.getCurrent()->perform( *fd ); ghidra->allacts.getCurrent()->perform( *fd );
#ifdef OPACTION_DEBUG
turn_off_debugging(fd);
#endif
} }
sout.write("\000\000\001\016",4); sout.write("\000\000\001\016",4);

View file

@ -230,9 +230,8 @@ public:
virtual void rawAction(void); virtual void rawAction(void);
}; };
#ifdef OPACTION_DEBUG #ifdef __REMOTE_SOCKET__
extern void turn_on_debugging(Funcdata *fd); extern void connect_to_console(Funcdata *fd);
extern void turn_off_debugging(Funcdata *fd);
#endif #endif
#endif #endif

View file

@ -225,6 +225,14 @@ IfaceDecompData::~IfaceDecompData(void)
// fd will get deleted with Database // fd will get deleted with Database
} }
void IfaceDecompData::allocateCallGraph(void)
{
if (cgraph != (CallGraph *)0)
delete cgraph;
cgraph = new CallGraph(conf);
}
void IfaceDecompData::abortFunction(ostream &s) void IfaceDecompData::abortFunction(ostream &s)
{ // Clear references to current function { // Clear references to current function
@ -2096,10 +2104,7 @@ void IfcDuplicateHash::iterationCallback(Funcdata *fd)
void IfcCallGraphBuild::execute(istream &s) void IfcCallGraphBuild::execute(istream &s)
{ // Build call graph from existing function starts { // Build call graph from existing function starts
if (dcp->cgraph != (CallGraph *)0) dcp->allocateCallGraph();
delete dcp->cgraph;
dcp->cgraph = new CallGraph(dcp->conf);
dcp->cgraph->buildAllNodes(); // Build a node in the graph for existing symbols dcp->cgraph->buildAllNodes(); // Build a node in the graph for existing symbols
quick = false; quick = false;
@ -2146,11 +2151,7 @@ void IfcCallGraphBuild::iterationCallback(Funcdata *fd)
void IfcCallGraphBuildQuick::execute(istream &s) void IfcCallGraphBuildQuick::execute(istream &s)
{ // Build call graph from existing function starts, do only disassembly { // Build call graph from existing function starts, do only disassembly
if (dcp->cgraph != (CallGraph *)0) dcp->allocateCallGraph();
delete dcp->cgraph;
dcp->cgraph = new CallGraph(dcp->conf);
dcp->cgraph->buildAllNodes(); // Build a node in the graph for existing symbols dcp->cgraph->buildAllNodes(); // Build a node in the graph for existing symbols
quick = true; quick = true;
iterateFunctionsAddrOrder(); iterateFunctionsAddrOrder();
@ -2199,7 +2200,7 @@ void IfcCallGraphLoad::execute(istream &s)
DocumentStorage store; DocumentStorage store;
Document *doc = store.parseDocument(is); Document *doc = store.parseDocument(is);
dcp->cgraph = new CallGraph(dcp->conf); dcp->allocateCallGraph();
dcp->cgraph->restoreXml(doc->getRoot()); dcp->cgraph->restoreXml(doc->getRoot());
*status->optr << "Successfully read in callgraph" << endl; *status->optr << "Successfully read in callgraph" << endl;
@ -2744,6 +2745,7 @@ void mainloop(IfaceStatus *status) {
for(;;) { for(;;) {
while(!status->isStreamFinished()) { while(!status->isStreamFinished()) {
status->writePrompt(); status->writePrompt();
status->optr->flush();
execute(status,dcp); execute(status,dcp);
} }
if (status->done) break; if (status->done) break;

View file

@ -54,6 +54,7 @@ public:
#endif #endif
IfaceDecompData(void); IfaceDecompData(void);
virtual ~IfaceDecompData(void); virtual ~IfaceDecompData(void);
void allocateCallGraph(void);
void abortFunction(ostream &s); void abortFunction(ostream &s);
void clearArchitecture(void); void clearArchitecture(void);
}; };

View file

@ -14,6 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
#include "interface.hh" #include "interface.hh"
#ifdef __REMOTE_SOCKET__
#include "sys/socket.h"
#include "sys/un.h"
#include "unistd.h"
#include "ext/stdio_filebuf.h"
#endif
vector<IfaceCapability *> IfaceCapability::thelist; vector<IfaceCapability *> IfaceCapability::thelist;
@ -30,6 +36,84 @@ void IfaceCapability::registerAllCommands(IfaceStatus *status)
thelist[i]->registerCommands(status); thelist[i]->registerCommands(status);
} }
#ifdef __REMOTE_SOCKET__
RemoteSocket::RemoteSocket(void)
{
fileDescriptor = 0;
inbuf = (basic_filebuf<char> *)0;
outbuf = (basic_filebuf<char> *)0;
inStream = (istream *)0;
outStream = (ostream *)0;
isOpen = false;
}
void RemoteSocket::close(void)
{
if (inStream != (istream *)0) {
delete inStream;
inStream = (istream *)0;
}
if (outStream != (ostream *)0) {
delete outStream;
outStream = (ostream *)0;
}
if (inbuf != (basic_filebuf<char> *)0) {
// Destroying the buffer should automatically close the socket
delete inbuf;
inbuf = (basic_filebuf<char> *)0;
}
if (outbuf != (basic_filebuf<char> *)0) {
delete outbuf;
outbuf = (basic_filebuf<char> *)0;
}
isOpen = false;
}
bool RemoteSocket::open(const string &filename)
{
if (isOpen) return false;
if ((fileDescriptor = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
throw IfaceError("Could not create socket");
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
int4 len = filename.length();
if (len >= sizeof(addr.sun_path))
throw IfaceError("Socket name too long");
memcpy(addr.sun_path,filename.c_str(),len);
addr.sun_path[len] = '\0';
len += sizeof(addr.sun_family);
if (connect(fileDescriptor, (struct sockaddr *)&addr, len) < 0) {
::close(fileDescriptor);
return false;
}
fdopen(fileDescriptor, "r");
inbuf = new __gnu_cxx::stdio_filebuf<char>(fileDescriptor,ios::in);
fdopen(fileDescriptor, "w");
outbuf = new __gnu_cxx::stdio_filebuf<char>(fileDescriptor,ios::out);
inStream = new istream(inbuf);
outStream = new ostream(outbuf);
isOpen = true;
return true;
}
bool RemoteSocket::isSocketOpen(void)
{
if (!isOpen) return false;
if (inStream->eof()) {
close();
return false;
}
return true;
}
#endif
IfaceStatus::IfaceStatus(const string &prmpt,istream &is,ostream &os,int4 mxhist) IfaceStatus::IfaceStatus(const string &prmpt,istream &is,ostream &os,int4 mxhist)
{ {
@ -75,6 +159,15 @@ void IfaceStatus::popScript(void)
inerror = false; inerror = false;
} }
void IfaceStatus::reset(void)
{
while(!inputstack.empty())
popScript();
errorisdone = false;
done = false;
}
void IfaceStatus::saveHistory(const string &line) void IfaceStatus::saveHistory(const string &line)
{ // Save line in circular history buffer { // Save line in circular history buffer

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -44,6 +44,32 @@
using namespace std; using namespace std;
#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
struct IfaceError { struct IfaceError {
string explain; // Explanatory string string explain; // Explanatory string
IfaceError(const string &s) { explain = s; } IfaceError(const string &s) { explain = s; }
@ -136,6 +162,7 @@ public:
void setErrorIsDone(bool val) { errorisdone = val; } void setErrorIsDone(bool val) { errorisdone = val; }
void pushScript(const string &filename,const string &newprompt); void pushScript(const string &filename,const string &newprompt);
void popScript(void); void popScript(void);
void reset(void);
int4 getNumInputStreamSize(void) const { return inputstack.size(); } int4 getNumInputStreamSize(void) const { return inputstack.size(); }
void writePrompt(void) { *optr << prompt; } void writePrompt(void) { *optr << prompt; }
void registerCom(IfaceCommand *fptr, const char *nm1, void registerCom(IfaceCommand *fptr, const char *nm1,

View file

@ -239,6 +239,7 @@ CPUI_DEBUG -- This is the ONE debug switch that should be passed in
#ifdef CPUI_DEBUG #ifdef CPUI_DEBUG
# define OPACTION_DEBUG # define OPACTION_DEBUG
# define PRETTY_DEBUG # define PRETTY_DEBUG
//# define __REMOTE_SOCKET__
//# define TYPEPROP_DEBUG //# define TYPEPROP_DEBUG
//# define DFSVERIFY_DEBUG //# define DFSVERIFY_DEBUG
//# define BLOCKCONSISTENT_DEBUG //# define BLOCKCONSISTENT_DEBUG