Skip to content
Permalink
472ad40077
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
520 lines (442 sloc) 14.5 KB
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ghidra_process.hh"
#include "flow.hh"
#include "blockaction.hh"
#ifdef __REMOTE_SOCKET__
#include "ifacedecomp.hh"
static IfaceStatus *ghidra_dcp = (IfaceStatus *)0;
static RemoteSocket *remote = (RemoteSocket *)0;
/// \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 (remote == (RemoteSocket *)0) {
remote = new RemoteSocket();
if (remote->open("/tmp/ghidrasocket")) {
ghidra_dcp = new IfaceStatus("[ghidradbg]> ",*remote->getInputStream(),*remote->getOutputStream());
IfaceCapability::registerAllCommands(ghidra_dcp);
}
}
if (!remote->isSocketOpen())
return;
IfaceDecompData *decomp_data = (IfaceDecompData *)ghidra_dcp->getData("decompile");
decomp_data->fd = fd;
decomp_data->conf = fd->getArch();
ostream *oldPrintStream = decomp_data->conf->print->getOutputStream();
bool emitXml = decomp_data->conf->print->emitsXml();
decomp_data->conf->setDebugStream(remote->getOutputStream());
decomp_data->conf->print->setOutputStream(remote->getOutputStream());
decomp_data->conf->print->setXML(false);
ghidra_dcp->reset();
mainloop(ghidra_dcp);
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
vector<ArchitectureGhidra *> archlist; // List of architectures currently running
map<string,GhidraCommand *> GhidraCapability::commandmap; // List of commands we can receive from Ghidra proper
// Constructing the singleton registers the capability
GhidraDecompCapability GhidraDecompCapability::ghidraDecompCapability;
/// This method reads an id selecting the Architecture to act on, but it can be overloaded
/// to read any set of data from the Ghidra client to configure how the command is executed.
/// Individual parameters are read using the method protocol.
void GhidraCommand::loadParameters(void)
{
int4 id = -1;
int4 type = ArchitectureGhidra::readToAnyBurst(sin);
if (type != 14)
throw JavaError("alignment","Expecting arch id start");
sin >> dec >> id;
type = ArchitectureGhidra::readToAnyBurst(sin);
if (type != 15)
throw JavaError("alignment","Expecting arch id end");
if ((id>=0)&&(id<archlist.size()))
ghidra = archlist[id];
if (ghidra == (ArchitectureGhidra *)0)
throw JavaError("decompiler","No architecture registered with decompiler");
ghidra->clearWarnings();
}
/// This method sends any warnings accumulated during execution back, but it can be overloaded
/// to send back any kind of information. Individual records are sent using
/// the message protocol.
void GhidraCommand::sendResult(void)
{
if (ghidra != (ArchitectureGhidra *)0) {
sout.write("\000\000\001\020",4);
sout << ghidra->getWarnings();
sout.write("\000\000\001\021",4);
}
}
/// This method calls the main overloaded methods:
/// - loadParameters()
/// - rawAction()
/// - sendResult()
///
/// It wraps the sequence with appropriate error handling and message protocol.
/// \return the meta-command (0=continue, 1=terminate) as issued by the command.
int4 GhidraCommand::doit(void)
{
status = 0;
sout.write("\000\000\001\006",4); // Command response header
try {
loadParameters();
int4 type = ArchitectureGhidra::readToAnyBurst(sin);
if (type != 3)
throw JavaError("alignment","Missing end of command");
rawAction();
}
catch(XmlError &err) {
string errmsg;
errmsg = "XML processing error: " + err.explain;
ghidra->printMessage( errmsg );
}
catch(JavaError &err) {
ArchitectureGhidra::passJavaException(sout,err.type,err.explain);
return status; // Abort sending any results
}
catch(RecovError &err) {
string errmsg;
errmsg = "Recoverable Error: " + err.explain;
ghidra->printMessage( errmsg );
}
catch(LowlevelError &err) {
string errmsg;
errmsg = "Low-level Error: " + err.explain;
ghidra->printMessage( errmsg );
}
sendResult();
sout.write("\000\000\001\007",4); // Command response closer
sout.flush();
return status;
}
void RegisterProgram::loadParameters(void)
{
pspec.clear();
cspec.clear();
tspec.clear();
corespec.clear();
ArchitectureGhidra::readStringStream(sin,pspec);
ArchitectureGhidra::readStringStream(sin,cspec);
ArchitectureGhidra::readStringStream(sin,tspec);
ArchitectureGhidra::readStringStream(sin,corespec);
}
void RegisterProgram::rawAction(void)
{
int4 i;
int4 open = -1;
for(i=0;i<archlist.size();++i) {
ghidra = archlist[i];
if (ghidra == (ArchitectureGhidra *)0) {
open = i; // Found open slot
}
}
ghidra = new ArchitectureGhidra(pspec,cspec,tspec,corespec,sin,sout);
DocumentStorage store; // temp storage of initialization xml docs
ghidra->init(store);
if (open == -1) {
open = archlist.size();
archlist.push_back((ArchitectureGhidra *)0);
}
archlist[open] = ghidra;
archid = open;
}
void RegisterProgram::sendResult(void)
{
sout.write("\000\000\001\016",4);
sout << dec << archid;
sout.write("\000\000\001\017",4);
GhidraCommand::sendResult();
}
void DeregisterProgram::loadParameters(void)
{
inid = -1;
int4 type = ArchitectureGhidra::readToAnyBurst(sin);
if (type!=14)
throw JavaError("alignment","Expecting deregister id start");
sin >> dec >> inid;
type = ArchitectureGhidra::readToAnyBurst(sin);
if (type!=15)
throw JavaError("alignment","Expecting deregister id end");
if ((inid>=0)&&(inid<archlist.size()))
ghidra = archlist[inid];
if (ghidra == (ArchitectureGhidra *)0)
throw JavaError("decompiler","No architecture registered with decompiler");
ghidra->clearWarnings();
}
void DeregisterProgram::rawAction(void)
{
#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;
archlist[inid] = (ArchitectureGhidra *)0;
delete ghidra;
ghidra = (ArchitectureGhidra *)0;
status = 1;
}
else
res = 0;
}
void DeregisterProgram::sendResult(void)
{
sout.write("\000\000\001\016",4);
sout << dec << res;
sout.write("\000\000\001\017",4);
GhidraCommand::sendResult();
}
void FlushNative::rawAction(void)
{
Scope *globscope = ghidra->symboltab->getGlobalScope();
globscope->clear(); // Clear symbols first as this may delete scopes
ghidra->symboltab->deleteSubScopes(globscope); // Flush cached function and globals database
ghidra->types->clearNoncore(); // Reset type information
ghidra->commentdb->clear(); // Clear any comments
ghidra->stringManager->clear(); // Clear string decodings
ghidra->cpool->clear();
res = 0;
}
void FlushNative::sendResult(void)
{
sout.write("\000\000\001\016",4);
sout << dec << res;
sout.write("\000\000\001\017",4);
GhidraCommand::sendResult();
}
void DecompileAt::loadParameters(void)
{
GhidraCommand::loadParameters();
Document *doc;
doc = ArchitectureGhidra::readXMLStream(sin); // Read XML of address directly from in stream
addr = Address::restoreXml(doc->getRoot(),ghidra); // Parse XML for functions address
addr.toPhysical(); // Only for backward compatibility
// with SLED
delete doc;
}
void DecompileAt::rawAction(void)
{
Funcdata *fd = ghidra->symboltab->getGlobalScope()->queryFunction(addr);
if (fd == (Funcdata *)0) {
ostringstream s;
s << "Bad decompile address: " << addr.getShortcut();
addr.printRaw(s);
s << "\n";
s << addr.getSpace()->getName() << " may not be a global space in the spec file.";
throw LowlevelError(s.str());
}
if (!fd->isProcStarted()) {
#ifdef __REMOTE_SOCKET__
connect_to_console(fd);
#endif
ghidra->allacts.getCurrent()->reset( *fd );
ghidra->allacts.getCurrent()->perform( *fd );
}
sout.write("\000\000\001\016",4);
// Write output XML directly to outstream
if (fd->isProcComplete()) {
//bool v1 = ghidra->getSendParamMeasures();
//sout << "value: " << ghidra->getSendParamMeasures() << "\n";
//bool v2 = (ghidra->allacts.getCurrentName() == "paramid");
//sout << "value: " << (ghidra->allacts.getCurrentName() == "paramid") << "\n";
//bool v3 = v1 && v2;
sout << "<doc>\n";
//sout << (v1?"1":"0") << "(" << (int4)v1 << ")\n" << (v2?"1":"0") << "\n" << (v3?"1":"0") << "\n";
if (ghidra->getSendParamMeasures() && (ghidra->allacts.getCurrentName() == "paramid")) {
ParamIDAnalysis pidanalysis( fd, true ); // Only send back final prototype
pidanalysis.saveXml( sout, true );
}
else {
if (ghidra->getSendParamMeasures()) {
ParamIDAnalysis pidanalysis( fd, false );
pidanalysis.saveXml( sout, true );
}
fd->saveXml(sout,0,ghidra->getSendSyntaxTree());
if (ghidra->getSendCCode()&&
(ghidra->allacts.getCurrentName() == "decompile"))
ghidra->print->docFunction(fd);
}
sout << "</doc>\n";
}
sout.write("\000\000\001\017",4);
}
void StructureGraph::loadParameters(void)
{
GhidraCommand::loadParameters();
Document *doc;
doc = ArchitectureGhidra::readXMLStream(sin);
ingraph.restoreXml(doc->getRoot(),ghidra);
delete doc;
}
void StructureGraph::rawAction(void)
{
BlockGraph resultgraph;
vector<FlowBlock *> rootlist;
resultgraph.buildCopy(ingraph);
resultgraph.structureLoops(rootlist);
resultgraph.calcForwardDominator(rootlist);
CollapseStructure collapse(resultgraph);
collapse.collapseAll();
resultgraph.orderBlocks();
sout.write("\000\000\001\016",4);
resultgraph.saveXml(sout);
sout.write("\000\000\001\017",4);
ingraph.clear();
}
void SetAction::loadParameters(void)
{
GhidraCommand::loadParameters();
actionstring.clear();
printstring.clear();
ArchitectureGhidra::readStringStream(sin,actionstring);
ArchitectureGhidra::readStringStream(sin,printstring);
}
void SetAction::rawAction(void)
{
res = false;
if (actionstring.size() != 0)
ghidra->allacts.setCurrent(actionstring);
if (printstring.size() != 0) {
if (printstring == "tree")
ghidra->setSendSyntaxTree(true);
else if (printstring == "notree")
ghidra->setSendSyntaxTree(false);
else if (printstring == "c")
ghidra->setSendCCode(true);
else if (printstring == "noc")
ghidra->setSendCCode(false);
else if (printstring == "parammeasures")
ghidra->setSendParamMeasures(true);
else if (printstring == "noparammeasures")
ghidra->setSendParamMeasures(false);
else if (printstring == "jumpload")
ghidra->flowoptions |= FlowInfo::record_jumploads;
else if (printstring == "nojumpload")
ghidra->flowoptions &= ~((uint4)FlowInfo::record_jumploads);
else
throw LowlevelError("Unknown print action: "+printstring);
}
res = true;
}
void SetAction::sendResult(void)
{
if (res)
ArchitectureGhidra::writeStringStream(sout,"t");
else
ArchitectureGhidra::writeStringStream(sout,"f");
GhidraCommand::sendResult();
}
SetOptions::SetOptions(void) : GhidraCommand()
{
doc = (Document *)0;
}
SetOptions::~SetOptions(void)
{
if (doc != (Document *)0)
delete doc;
}
void SetOptions::loadParameters(void)
{
GhidraCommand::loadParameters();
if (doc != (Document *)0) {
delete doc;
doc = (Document *)0;
}
doc = ArchitectureGhidra::readXMLStream(sin);
}
void SetOptions::rawAction(void)
{
res = false;
ghidra->resetDefaults();
ghidra->options->restoreXml(doc->getRoot());
delete doc;
doc = (Document *)0;
res = true;
}
void SetOptions::sendResult(void)
{
if (res)
ArchitectureGhidra::writeStringStream(sout,"t");
else
ArchitectureGhidra::writeStringStream(sout,"f");
GhidraCommand::sendResult();
}
/// A command is read from the Ghidra client. The matching GhidraCommand object is
/// looked up in the \b commandmap, and control is handed over to the command,
/// with the i/o streams. The command must be issued following the proper
/// message protocol (see ArchitectureGhidra::readToAnyBurst) or an exception is thrown.
/// \param sin is the input stream from the client
/// \param out is the output stream to the client
/// \return the result code of the command
int4 GhidraCapability::readCommand(istream &sin,ostream &out)
{
string function;
int4 type;
do {
type = ArchitectureGhidra::readToAnyBurst(sin); // Align ourselves
} while(type != 2);
ArchitectureGhidra::readStringStream(sin,function);
map<string,GhidraCommand *>::const_iterator iter;
iter = commandmap.find(function);
if (iter == commandmap.end()) {
out.write("\000\000\001\006",4); // Command response header
out.write("\000\000\001\020",4);
out << "Bad command: " << function;
out.write("\000\000\001\021",4);
out.write("\000\000\001\007",4); // Command response closer
out.flush();
return 0;
}
return (*iter).second->doit();
}
void GhidraCapability::shutDown(void)
{
map<string,GhidraCommand *>::iterator iter;
for(iter=commandmap.begin();iter!=commandmap.end();++iter)
delete (*iter).second;
}
void GhidraDecompCapability::initialize(void)
{
commandmap["registerProgram"] = new RegisterProgram();
commandmap["deregisterProgram"] = new DeregisterProgram();
commandmap["flushNative"] = new FlushNative();
commandmap["decompileAt"] = new DecompileAt();
commandmap["structureGraph"] = new StructureGraph();
commandmap["setAction"] = new SetAction();
commandmap["setOptions"] = new SetOptions();
}
int main(int argc,char **argv)
{
signal(SIGSEGV, &ArchitectureGhidra::segvHandler); // Exit on SEGV errors
CapabilityPoint::initializeAll();
int4 status = 0;
while(status == 0) {
status = GhidraCapability::readCommand(cin,cout);
}
GhidraCapability::shutDown();
}