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;
}
void Action::clearBreakPoints(void)
{
breakpoint = 0;
}
/// 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
/// specifying its name.
@ -371,6 +377,15 @@ void ActionGroup::addAction(Action *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
{
@ -870,6 +885,15 @@ int4 ActionPool::apply(Funcdata &data)
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
{

View file

@ -99,6 +99,7 @@ public:
virtual void printStatistics(ostream &s) const; ///< Dump statistics to stream
int4 perform(Funcdata &data); ///< Perform this action (if necessary)
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 disableRule(const string &specify); ///< Disable 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
virtual ~ActionGroup(void); ///< Destructor
void addAction(Action *ac); ///< Add an Action to the group
virtual void clearBreakPoints(void);
virtual Action *clone(const ActionGroupList &grouplist) const;
virtual void reset(Funcdata &data);
virtual void resetStats(void);
@ -216,6 +218,7 @@ public:
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 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 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
@ -266,6 +269,7 @@ public:
ActionPool(uint4 f,const string &nm) : Action(f,nm,"") {} ///< Construct providing properties and name
virtual ~ActionPool(void); ///< Destructor
void addRule(Rule *rl); ///< Add a Rule to the pool
virtual void clearBreakPoints(void);
virtual Action *clone(const ActionGroupList &grouplist) const;
virtual void reset(Funcdata &data);
virtual void resetStats(void);

View file

@ -17,44 +17,46 @@
#include "flow.hh"
#include "blockaction.hh"
#ifdef OPACTION_DEBUG
#ifdef __REMOTE_SOCKET__
#include "ifacedecomp.hh"
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) {
ghidra_dcp = new IfaceStatus("[ghidradbg]> ",cin,cout);
ghidra_dcp->optr = (ostream *)0;
ghidra_dcp->fileoptr = (ostream *)0;
IfaceCapability::registerAllCommands(ghidra_dcp);
if (remote == (RemoteSocket *)0) {
remote = new RemoteSocket();
if (remote->open("/tmp/ghidrasocket")) {
ghidra_dcp = new IfaceStatus("[ghidradbg]> ",*remote->getInputStream(),*remote->getOutputStream());
IfaceCapability::registerAllCommands(ghidra_dcp);
}
}
// Check if debug script exists
ifstream is("ghidracom.txt");
if (!is) return;
is.close();
if (!remote->isSocketOpen())
return;
IfaceDecompData *decomp_data = (IfaceDecompData *)ghidra_dcp->getData("decompile");
decomp_data->fd = fd;
decomp_data->conf = fd->getArch();
ghidra_dcp->pushScript("ghidracom.txt","ghidradbg> ");
ghidra_dcp->optr = new ofstream("ghidrares.txt");
ghidra_dcp->fileoptr = ghidra_dcp->optr;
decomp_data->conf->setDebugStream(ghidra_dcp->optr);
ostream *oldPrintStream = decomp_data->conf->print->getOutputStream();
bool emitXml = decomp_data->conf->print->emitsXml();
decomp_data->conf->print->setOutputStream(remote->getOutputStream());
decomp_data->conf->print->setXML(false);
ghidra_dcp->reset();
mainloop(ghidra_dcp);
ghidra_dcp->popScript();
}
void turn_off_debugging(Funcdata *fd)
{
if (ghidra_dcp->optr != (ostream *)0) {
delete ghidra_dcp->optr;
ghidra_dcp->optr = (ostream *)0;
}
decomp_data->conf->clearAnalysis(fd);
decomp_data->conf->print->setOutputStream(oldPrintStream);
decomp_data->conf->print->setXML(emitXml);
fd->debugDisable();
decomp_data->conf->allacts.getCurrent()->clearBreakPoints();
}
#endif
@ -213,9 +215,13 @@ void DeregisterProgram::loadParameters(void)
void DeregisterProgram::rawAction(void)
{
#ifdef OPACTION_DEBUG
#ifdef __REMOTE_SOCKET__
if (ghidra_dcp != (IfaceStatus *)0)
delete ghidra_dcp;
if (remote != (RemoteSocket *)0)
delete remote;
ghidra_dcp = (IfaceStatus *)0;
remote = (RemoteSocket *)0;
#endif
if (ghidra != (ArchitectureGhidra *)0) {
res = 1;
@ -284,14 +290,11 @@ void DecompileAt::rawAction(void)
throw LowlevelError(s.str());
}
if (!fd->isProcStarted()) {
#ifdef OPACTION_DEBUG
turn_on_debugging(fd);
#ifdef __REMOTE_SOCKET__
connect_to_console(fd);
#endif
ghidra->allacts.getCurrent()->reset( *fd );
ghidra->allacts.getCurrent()->perform( *fd );
#ifdef OPACTION_DEBUG
turn_off_debugging(fd);
#endif
}
sout.write("\000\000\001\016",4);

View file

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

View file

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

View file

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

View file

@ -14,6 +14,12 @@
* limitations under the License.
*/
#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;
@ -30,6 +36,84 @@ void IfaceCapability::registerAllCommands(IfaceStatus *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)
{
@ -75,6 +159,15 @@ void IfaceStatus::popScript(void)
inerror = false;
}
void IfaceStatus::reset(void)
{
while(!inputstack.empty())
popScript();
errorisdone = false;
done = false;
}
void IfaceStatus::saveHistory(const string &line)
{ // Save line in circular history buffer

View file

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