mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
remote debug console
This commit is contained in:
parent
0f0a82b8b1
commit
36c5a5c62b
9 changed files with 201 additions and 47 deletions
|
@ -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
|
||||
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -54,6 +54,7 @@ public:
|
|||
#endif
|
||||
IfaceDecompData(void);
|
||||
virtual ~IfaceDecompData(void);
|
||||
void allocateCallGraph(void);
|
||||
void abortFunction(ostream &s);
|
||||
void clearArchitecture(void);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue