mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Candidate release of source code.
This commit is contained in:
parent
db81e6b3b0
commit
79d8f164f8
12449 changed files with 2800756 additions and 16 deletions
471
Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.cc
Normal file
471
Ghidra/Features/Decompiler/src/decompile/cpp/callgraph.cc
Normal file
|
@ -0,0 +1,471 @@
|
|||
/* ###
|
||||
* 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 "callgraph.hh"
|
||||
#include "funcdata.hh"
|
||||
|
||||
void CallGraphEdge::saveXml(ostream &s) const
|
||||
|
||||
{
|
||||
s << " <edge>\n";
|
||||
s << " ";
|
||||
from->getAddr().saveXml(s);
|
||||
s << "\n ";
|
||||
to->getAddr().saveXml(s);
|
||||
s << "\n ";
|
||||
callsiteaddr.saveXml(s);
|
||||
s << "\n </edge>\n";
|
||||
}
|
||||
|
||||
void CallGraphEdge::restoreXml(const Element *el,CallGraph *graph)
|
||||
|
||||
{
|
||||
const AddrSpaceManager *manage = graph->getArch();
|
||||
Address fromaddr,toaddr,siteaddr;
|
||||
|
||||
const List &list(el->getChildren());
|
||||
List::const_iterator iter;
|
||||
|
||||
iter = list.begin();
|
||||
fromaddr = Address::restoreXml(*iter,manage);
|
||||
++iter;
|
||||
toaddr = Address::restoreXml(*iter,manage);
|
||||
++iter;
|
||||
siteaddr = Address::restoreXml(*iter,manage);
|
||||
|
||||
CallGraphNode *fromnode = graph->findNode(fromaddr);
|
||||
if (fromnode == (CallGraphNode *)0)
|
||||
throw LowlevelError("Could not find from node");
|
||||
CallGraphNode *tonode = graph->findNode(toaddr);
|
||||
if (tonode == (CallGraphNode *)0)
|
||||
throw LowlevelError("Could not find to node");
|
||||
|
||||
graph->addEdge(fromnode,tonode,siteaddr);
|
||||
}
|
||||
|
||||
void CallGraphNode::setFuncdata(Funcdata *f)
|
||||
|
||||
{
|
||||
if ((fd != (Funcdata *)0)&&(fd != f))
|
||||
throw LowlevelError("Multiple functions at one address in callgraph");
|
||||
|
||||
if (f->getAddress() != entryaddr)
|
||||
throw LowlevelError("Setting function data at wrong address in callgraph");
|
||||
fd = f;
|
||||
}
|
||||
|
||||
void CallGraphNode::saveXml(ostream &s) const
|
||||
|
||||
{
|
||||
s << " <node";
|
||||
if (name.size() != 0)
|
||||
a_v(s,"name",name);
|
||||
s << ">\n ";
|
||||
entryaddr.saveXml(s);
|
||||
s << "\n </node>\n";
|
||||
}
|
||||
|
||||
void CallGraphNode::restoreXml(const Element *el,CallGraph *graph)
|
||||
|
||||
{
|
||||
int4 num = el->getNumAttributes();
|
||||
string name;
|
||||
for(int4 i=0;i<num;++i) {
|
||||
if (el->getAttributeName(i) == "name")
|
||||
name = el->getAttributeValue(i);
|
||||
}
|
||||
Address addr = Address::restoreXml(*el->getChildren().begin(),graph->getArch());
|
||||
|
||||
graph->addNode(addr,name);
|
||||
}
|
||||
|
||||
bool CallGraph::findNoEntry(vector<CallGraphNode *> &seeds)
|
||||
|
||||
{ // Find all functions (that are not already marked) that either have no in edges at all,
|
||||
// or have no in edges that haven't been snipped as part of cycles
|
||||
|
||||
map<Address,CallGraphNode>::iterator iter;
|
||||
CallGraphNode *lownode = (CallGraphNode *)0;
|
||||
bool allcovered = true;
|
||||
bool newseeds = false;
|
||||
|
||||
for(iter=graph.begin();iter!=graph.end();++iter) {
|
||||
CallGraphNode &node( (*iter).second );
|
||||
if (node.isMark()) continue;
|
||||
if ((node.inedge.size() == 0)||((node.flags&CallGraphNode::onlycyclein)!=0)) {
|
||||
seeds.push_back(&node);
|
||||
node.flags |= CallGraphNode::mark | CallGraphNode::entrynode;
|
||||
newseeds = true;
|
||||
}
|
||||
else {
|
||||
allcovered = false;
|
||||
// We need to worry about the case where everything is in a cycle, so we don't find a natural root
|
||||
// We use the node with the lowest number of in edges as a pseudo root
|
||||
if (lownode == (CallGraphNode *)0)
|
||||
lownode = &node;
|
||||
else {
|
||||
if (node.numInEdge() < lownode->numInEdge())
|
||||
lownode = &node;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((!newseeds)&&(!allcovered)) {
|
||||
seeds.push_back(lownode);
|
||||
lownode->flags |= CallGraphNode::mark | CallGraphNode::entrynode;
|
||||
}
|
||||
return allcovered;
|
||||
}
|
||||
|
||||
void CallGraph::snipCycles(CallGraphNode *node)
|
||||
|
||||
{ // Snip any cycles starting from root -node-
|
||||
CallGraphNode *next;
|
||||
vector<LeafIterator> stack;
|
||||
|
||||
node->flags |= CallGraphNode::currentcycle;
|
||||
stack.push_back(LeafIterator(node));
|
||||
|
||||
while(!stack.empty()) {
|
||||
CallGraphNode *cur = stack.back().node; // Current node
|
||||
int4 st = stack.back().outslot; // which out edge we will follow
|
||||
if (st >= cur->outedge.size()) {
|
||||
cur->flags &= ~((uint4)CallGraphNode::currentcycle);
|
||||
stack.pop_back();
|
||||
}
|
||||
else {
|
||||
stack.back().outslot += 1;
|
||||
if ((cur->outedge[st].flags&CallGraphEdge::cycle)!=0) continue;
|
||||
next = cur->outedge[st].to;
|
||||
if ((next->flags&CallGraphNode::currentcycle)!=0) { // Found a cycle
|
||||
snipEdge(cur,st);
|
||||
continue;
|
||||
}
|
||||
else if ((next->flags&CallGraphNode::mark)!=0) { // Already traced before
|
||||
cur->outedge[st].flags |= CallGraphEdge::dontfollow;
|
||||
continue;
|
||||
}
|
||||
next->parentedge = cur->outedge[st].complement;
|
||||
next->flags |= (CallGraphNode::currentcycle| CallGraphNode::mark);
|
||||
stack.push_back(LeafIterator(next));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraph::snipEdge(CallGraphNode *node,int4 i)
|
||||
|
||||
{
|
||||
node->outedge[i].flags |= CallGraphEdge::cycle | CallGraphEdge::dontfollow;
|
||||
int4 toi = node->outedge[i].complement;
|
||||
CallGraphNode *to = node->outedge[i].to;
|
||||
to->inedge[toi].flags |= CallGraphEdge::cycle;
|
||||
bool onlycycle = true;
|
||||
for(uint4 j=0;j<to->inedge.size();++j) {
|
||||
if ((to->inedge[j].flags & CallGraphEdge::cycle)==0) {
|
||||
onlycycle = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (onlycycle)
|
||||
to->flags |= CallGraphNode::onlycyclein;
|
||||
}
|
||||
|
||||
void CallGraph::clearMarks(void)
|
||||
|
||||
{
|
||||
map<Address,CallGraphNode>::iterator iter;
|
||||
|
||||
for(iter=graph.begin();iter!=graph.end();++iter)
|
||||
(*iter).second.clearMark();
|
||||
}
|
||||
|
||||
CallGraphEdge &CallGraph::insertBlankEdge(CallGraphNode *node,int4 slot)
|
||||
|
||||
{
|
||||
node->outedge.push_back(CallGraphEdge());
|
||||
if (node->outedge.size() > 1) {
|
||||
for(int4 i=node->outedge.size()-2;i>=slot;--i) {
|
||||
int4 newi = i+1;
|
||||
CallGraphEdge &edge( node->outedge[newi] );
|
||||
edge = node->outedge[i];
|
||||
CallGraphNode *nodeout = edge.to;
|
||||
nodeout->inedge[ edge.complement ].complement += 1;
|
||||
}
|
||||
}
|
||||
return node->outedge[slot];
|
||||
}
|
||||
|
||||
CallGraphNode *CallGraph::addNode(Funcdata *f)
|
||||
|
||||
{ // Add a node, based on an existing function -f-
|
||||
CallGraphNode &node( graph[f->getAddress()] );
|
||||
|
||||
if ((node.getFuncdata() != (Funcdata *)0)&&(node.getFuncdata() != f))
|
||||
throw LowlevelError("Functions with duplicate entry points: "+f->getName()+" "+node.getFuncdata()->getName());
|
||||
|
||||
node.entryaddr = f->getAddress();
|
||||
node.name = f->getName();
|
||||
node.fd = f;
|
||||
return &node;
|
||||
}
|
||||
|
||||
CallGraphNode *CallGraph::addNode(const Address &addr,const string &nm)
|
||||
|
||||
{
|
||||
CallGraphNode &node( graph[addr] );
|
||||
|
||||
node.entryaddr = addr;
|
||||
node.name = nm;
|
||||
|
||||
return &node;
|
||||
}
|
||||
|
||||
CallGraphNode *CallGraph::findNode(const Address &addr)
|
||||
|
||||
{ // Find function at given address, or return null
|
||||
map<Address,CallGraphNode>::iterator iter;
|
||||
|
||||
iter = graph.find(addr);
|
||||
if (iter != graph.end())
|
||||
return &(*iter).second;
|
||||
return (CallGraphNode *)0;
|
||||
}
|
||||
|
||||
void CallGraph::addEdge(CallGraphNode *from,CallGraphNode *to,const Address &addr)
|
||||
|
||||
{
|
||||
int4 i;
|
||||
for(i=0;i<from->outedge.size();++i) {
|
||||
CallGraphNode *outnode = from->outedge[i].to;
|
||||
if (outnode == to) return; // Already have an out edge
|
||||
if (to->entryaddr < outnode->entryaddr) break;
|
||||
}
|
||||
|
||||
CallGraphEdge &fromedge( insertBlankEdge(from,i) );
|
||||
|
||||
int4 toi = to->inedge.size();
|
||||
to->inedge.push_back(CallGraphEdge());
|
||||
CallGraphEdge &toedge( to->inedge.back() );
|
||||
|
||||
fromedge.from = from;
|
||||
fromedge.to = to;
|
||||
fromedge.callsiteaddr = addr;
|
||||
fromedge.complement = toi;
|
||||
|
||||
toedge.from = from;
|
||||
toedge.to = to;
|
||||
toedge.callsiteaddr = addr;
|
||||
toedge.complement = i;
|
||||
}
|
||||
|
||||
void CallGraph::deleteInEdge(CallGraphNode *node,int4 i)
|
||||
|
||||
{
|
||||
int4 tosize = node->inedge.size();
|
||||
int4 fromi = node->inedge[i].complement;
|
||||
CallGraphNode *from = node->inedge[i].from;
|
||||
int4 fromsize = from->outedge.size();
|
||||
|
||||
for(int4 j=i+1;j<tosize;++j) {
|
||||
node->inedge[j-1] = node->inedge[j];
|
||||
if (node->inedge[j-1].complement >= fromi)
|
||||
node->inedge[j-1].complement -= 1;
|
||||
}
|
||||
node->inedge.pop_back();
|
||||
|
||||
for(int4 j=fromi+1;j<fromsize;++j) {
|
||||
from->outedge[j-1] = from->outedge[j];
|
||||
if (from->outedge[j-1].complement >= i)
|
||||
from->outedge[j-1].complement -= 1;
|
||||
}
|
||||
from->outedge.pop_back();
|
||||
}
|
||||
|
||||
CallGraphNode *CallGraph::popPossible(CallGraphNode *node,int4 &outslot)
|
||||
|
||||
{
|
||||
if ((node->flags & CallGraphNode::entrynode)!=0) {
|
||||
outslot = node->parentedge;
|
||||
return (CallGraphNode *)0;
|
||||
}
|
||||
outslot = node->inedge[node->parentedge].complement;
|
||||
return node->inedge[node->parentedge].from;
|
||||
}
|
||||
|
||||
CallGraphNode *CallGraph::pushPossible(CallGraphNode *node,int4 outslot)
|
||||
|
||||
{
|
||||
if (node == (CallGraphNode *)0) {
|
||||
if (outslot >= seeds.size())
|
||||
return (CallGraphNode *)0;
|
||||
return seeds[outslot];
|
||||
}
|
||||
while(outslot < node->outedge.size()) {
|
||||
if ((node->outedge[outslot].flags & CallGraphEdge::dontfollow)!=0)
|
||||
outslot += 1;
|
||||
else
|
||||
return node->outedge[outslot].to;
|
||||
}
|
||||
return (CallGraphNode *)0;
|
||||
}
|
||||
|
||||
CallGraphNode *CallGraph::initLeafWalk(void)
|
||||
|
||||
{
|
||||
cycleStructure();
|
||||
if (seeds.empty()) return (CallGraphNode *)0;
|
||||
CallGraphNode *node = seeds[0];
|
||||
for(;;) {
|
||||
CallGraphNode *pushnode = pushPossible(node,0);
|
||||
if (pushnode == (CallGraphNode *)0)
|
||||
break;
|
||||
node = pushnode;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
CallGraphNode *CallGraph::nextLeaf(CallGraphNode *node)
|
||||
|
||||
{
|
||||
int4 outslot;
|
||||
node = popPossible(node,outslot);
|
||||
outslot += 1;
|
||||
for(;;) {
|
||||
CallGraphNode *pushnode = pushPossible(node,outslot);
|
||||
if (pushnode == (CallGraphNode *)0)
|
||||
break;
|
||||
node = pushnode;
|
||||
outslot = 0;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void CallGraph::cycleStructure(void)
|
||||
|
||||
{ // Generate list of seeds nodes (from which we can get to everything)
|
||||
if (!seeds.empty())
|
||||
return;
|
||||
uint4 walked = 0;
|
||||
bool allcovered;
|
||||
|
||||
do {
|
||||
allcovered = findNoEntry(seeds);
|
||||
while(walked < seeds.size()) {
|
||||
CallGraphNode *rootnode = seeds[walked];
|
||||
rootnode->parentedge = walked;
|
||||
snipCycles(rootnode);
|
||||
walked += 1;
|
||||
}
|
||||
} while(!allcovered);
|
||||
clearMarks();
|
||||
}
|
||||
|
||||
void CallGraph::iterateScopesRecursive(Scope *scope)
|
||||
|
||||
{
|
||||
if (!scope->isGlobal()) return;
|
||||
iterateFunctionsAddrOrder(scope);
|
||||
ScopeMap::const_iterator iter,enditer;
|
||||
iter = scope->childrenBegin();
|
||||
enditer = scope->childrenEnd();
|
||||
for(;iter!=enditer;++iter) {
|
||||
iterateScopesRecursive((*iter).second);
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraph::iterateFunctionsAddrOrder(Scope *scope)
|
||||
|
||||
{
|
||||
MapIterator miter,menditer;
|
||||
miter = scope->begin();
|
||||
menditer = scope->end();
|
||||
while(miter != menditer) {
|
||||
Symbol *sym = (*miter)->getSymbol();
|
||||
FunctionSymbol *fsym = dynamic_cast<FunctionSymbol *>(sym);
|
||||
++miter;
|
||||
if (fsym != (FunctionSymbol *)0)
|
||||
addNode(fsym->getFunction());
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraph::buildAllNodes(void)
|
||||
|
||||
{ // Make every function symbol into a node
|
||||
iterateScopesRecursive(glb->symboltab->getGlobalScope());
|
||||
}
|
||||
|
||||
void CallGraph::buildEdges(Funcdata *fd)
|
||||
|
||||
{ // Build edges from a disassembled (decompiled) function
|
||||
CallGraphNode *fdnode = findNode(fd->getAddress());
|
||||
CallGraphNode *tonode;
|
||||
if (fdnode == (CallGraphNode *)0)
|
||||
throw LowlevelError("Function is missing from callgraph");
|
||||
if (fd->getFuncProto().getModelExtraPop() == ProtoModel::extrapop_unknown)
|
||||
fd->fillinExtrapop();
|
||||
|
||||
int4 numcalls = fd->numCalls();
|
||||
for(int4 i=0;i<numcalls;++i) {
|
||||
FuncCallSpecs *fs = fd->getCallSpecs(i);
|
||||
Address addr = fs->getEntryAddress();
|
||||
if (!addr.isInvalid()) {
|
||||
tonode = findNode(addr);
|
||||
if (tonode == (CallGraphNode *)0) {
|
||||
string name;
|
||||
glb->nameFunction(addr,name);
|
||||
tonode = addNode(addr,name);
|
||||
}
|
||||
addEdge(fdnode,tonode,fs->getOp()->getAddr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallGraph::saveXml(ostream &s) const
|
||||
|
||||
{
|
||||
map<Address,CallGraphNode>::const_iterator iter;
|
||||
|
||||
s << "<callgraph>\n";
|
||||
|
||||
for(iter=graph.begin();iter!=graph.end();++iter)
|
||||
(*iter).second.saveXml(s);
|
||||
|
||||
// Dump all the "in" edges
|
||||
for(iter=graph.begin();iter!=graph.end();++iter) {
|
||||
const CallGraphNode &node( (*iter).second );
|
||||
|
||||
for(uint4 i=0;i<node.inedge.size();++i)
|
||||
node.inedge[i].saveXml(s);
|
||||
}
|
||||
|
||||
s << "</callgraph>\n";
|
||||
}
|
||||
|
||||
void CallGraph::restoreXml(const Element *el)
|
||||
|
||||
{
|
||||
const List &list(el->getChildren());
|
||||
List::const_iterator iter;
|
||||
|
||||
iter = list.begin();
|
||||
while(iter != list.end()) {
|
||||
const Element *subel = *iter;
|
||||
++iter;
|
||||
if (subel->getName() == "edge")
|
||||
CallGraphEdge::restoreXml(subel,this);
|
||||
else
|
||||
CallGraphNode::restoreXml(subel,this);
|
||||
}
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue