Skip to content
Snippets Groups Projects
Commit 039862df authored by jdh8d's avatar jdh8d
Browse files

Added call graph functionality

Former-commit-id: a5916f3d8b82cd9a5373a20a4406996b9c0fb44f
parent 3540f70a
No related branches found
No related tags found
No related merge requests found
......@@ -182,6 +182,7 @@ libIRDB/LICENSE.txt -text
libIRDB/Makefile -text
libIRDB/include/cfg/BasicBlock.hpp -text
libIRDB/include/cfg/CFG.hpp -text
libIRDB/include/cfg/callgraph.hpp -text
libIRDB/include/core/address.hpp -text
libIRDB/include/core/archdesc.hpp -text
libIRDB/include/core/baseobj.hpp -text
......@@ -203,6 +204,7 @@ libIRDB/src/Makefile -text
libIRDB/src/cfg/BasicBlock.cpp -text
libIRDB/src/cfg/CFG.cpp -text
libIRDB/src/cfg/Makefile -text
libIRDB/src/cfg/callgraph.cpp -text
libIRDB/src/core/Makefile -text
libIRDB/src/core/address.cpp -text
libIRDB/src/core/all.hpp -text
......@@ -216,6 +218,7 @@ libIRDB/src/core/instruction.cpp -text
libIRDB/src/core/pqxxdb.cpp -text
libIRDB/src/core/variantid.cpp -text
libIRDB/test/Makefile -text
libIRDB/test/build_callgraph.cpp -text
libIRDB/test/calc_conflicts.cpp -text
libIRDB/test/check_thunks.cpp -text
libIRDB/test/check_thunks.hpp -text
......
#ifndef irdb_cfg_callgraph_h
#define irdb_cfg_callgraph_h
typedef libIRDB::Function_t* CallGraphNode_t;
typedef std::pair<CallGraphNode_t,CallGraphNode_t> CallGraphEdge_t;
typedef std::set<CallGraphNode_t> CallGraphNodeSet_t;
typedef libIRDB::Instruction_t* CallSite_t;
typedef std::set<CallSite_t> CallSiteSet_t;
class Callgraph_t
{
public:
Callgraph_t();
void AddFile(libIRDB::FileIR_t *firp);
bool EdgeExists(const CallGraphEdge_t& edge)
{
CallGraphNode_t from=edge.first;
CallGraphNode_t to=edge.second;
// note that this callees[from] may allocate an empty set -- probably can do better.
const CallGraphNodeSet_t &calleeSet=callees[from];
return calleeSet.find(to)!=calleeSet.end();
}
bool EdgeExists(const CallGraphNode_t& n1, const CallGraphNode_t& n2)
{ return EdgeExists(CallGraphEdge_t(n1,n2));}
CallGraphNodeSet_t& GetCalleesOfCaller(const CallGraphNode_t& caller)
{ return callees[caller]; }
CallGraphNodeSet_t& GetCallersOfCallee(const CallGraphNode_t& callee)
{ return callers[callee]; }
CallSiteSet_t& GetCallSites(const CallGraphNode_t& n1)
{ return call_sites[n1]; }
void Dump(std::ostream& fout);
private:
// mark the given insn as a call site.
void MarkCallSite(Instruction_t* insn);
typedef std::map<CallGraphNode_t, CallGraphNodeSet_t > CGNodeToCGNodeSetMap_t;
typedef std::map<CallGraphNode_t, CallSiteSet_t > NodeToCallSiteSetMap_t;
CGNodeToCGNodeSetMap_t callees; // map a callee to it's callers.
CGNodeToCGNodeSetMap_t callers; // map a caller to it's callees
NodeToCallSiteSetMap_t call_sites;
};
#endif
......@@ -35,6 +35,7 @@ namespace libIRDB
#include <cfg/BasicBlock.hpp>
#include <cfg/CFG.hpp>
#include <cfg/callgraph.hpp>
};
......
LIB=../../lib/libIRDB-cfg.a
OBJS=BasicBlock.o CFG.o
OBJS=BasicBlock.o CFG.o callgraph.o
all: $(OBJS)
......
#include <map>
#include <ostream>
#include <libIRDB-core.hpp>
#include <libIRDB-cfg.hpp>
#include <utils.hpp>
using namespace libIRDB;
using namespace std;
Callgraph_t::Callgraph_t()
{
}
static bool IsCallSite(Instruction_t* insn)
{
DISASM insnd;
insn->Disassemble(insnd);
return NULL!=(strstr(insnd.Instruction.Mnemonic,"call"));
}
static bool IsTailJmpSite(Instruction_t* insn)
{
DISASM insnd;
insn->Disassemble(insnd);
if(strstr(insnd.Instruction.Mnemonic,"jmp")==NULL)
return false;
if(insn->GetTarget()==NULL)
return true;
if(insn->GetFunction() != insn->GetTarget()->GetFunction())
return true;
return false;
}
static bool IsPushJmpSite(Instruction_t* insn)
{
DISASM insnd;
insn->Disassemble(insnd);
if(strstr(insnd.Instruction.Mnemonic,"push")==NULL || insn->GetFallthrough()==NULL)
return false;
if(insn->GetRelocations().size()==0)
return false;
insn->GetFallthrough()->Disassemble(insnd);
if(strstr(insnd.Instruction.Mnemonic,"jmp")==NULL)
return false;
return true;
}
void Callgraph_t::MarkCallSite(Instruction_t* insn)
{
Function_t* from_func=insn->GetFunction();
Instruction_t* to_insn=insn->GetTarget();
Function_t* to_func= to_insn==NULL? NULL : to_insn->GetFunction();
if(to_insn)
call_sites[from_func].insert(to_insn);
if(to_func)
{
callers[from_func].insert(to_func);
if(from_func)
callees[to_func].insert(from_func);
}
}
void Callgraph_t::AddFile(libIRDB::FileIR_t *firp)
{
// for each instruction
set<Instruction_t*> &insns=firp->GetInstructions();
Instruction_t* insn=NULL, *prev=NULL;
for(set<Instruction_t*>::iterator it=insns.begin();
insns.end() != it;
++it, prev=insn)
{
insn=*it;
if(IsCallSite(insn) || IsTailJmpSite(insn))
MarkCallSite(insn);
if(IsPushJmpSite(insn))
MarkCallSite(insn->GetFallthrough());
}
// CGNodeToCGNodeSetMap_t callees;
// CGNodeToCGNodeSetMap_t callers;
// NodeToCallSiteSetMap_t call_sites;
}
void Callgraph_t::Dump(std::ostream& fout)
{
fout<<"Dumping callgraph ..."<<endl;
fout<<"Mapping one way ..."<<endl;
for(CGNodeToCGNodeSetMap_t::iterator it=callers.begin();
callers.end()!=it;
++it)
{
Function_t* f=it->first;
fout<<"Function "<<f->GetName()<<" calls: ";
CallGraphNodeSet_t &node_callees=it->second;
for(CallGraphNodeSet_t::iterator it2=node_callees.begin();
node_callees.end()!=it2;
++it2)
{
Function_t* the_callee=*it2;
fout<<the_callee->GetName()<<", ";
}
fout<<endl;
}
fout<<"Mapping the other way ..."<<endl;
for(CGNodeToCGNodeSetMap_t::iterator it=callees.begin();
callees.end()!=it;
++it)
{
Function_t* f=it->first;
fout<<"Function "<<f->GetName()<<" called by: ";
CallGraphNodeSet_t &node_callers=it->second;
for(CallGraphNodeSet_t::iterator it2=node_callers.begin();
node_callers.end()!=it2;
++it2)
{
Function_t* the_caller=*it2;
fout<<the_caller->GetName()<<", ";
}
fout<<endl;
}
fout<<"Done!"<<endl;
}
......@@ -7,7 +7,7 @@ OPT=-g
PROGS=print_variant.exe list_programs.exe create_variant.exe create_variantir.exe read_variantir.exe clone.exe ilr.exe \
drop_variant.exe generate_spri.exe fill_in_cfg.exe fix_calls.exe fill_in_indtargs.exe unfix_calls.exe \
calc_conflicts.exe find_strings.exe
calc_conflicts.exe find_strings.exe build_callgraph.exe
all: $(PROGS)
......
/*
* Copyright (c) 2014 - Zephyr Software LLC
*
* This file may be used and modified for non-commercial purposes as long as
* all copyright, permission, and nonwarranty notices are preserved.
* Redistribution is prohibited without prior written consent from Zephyr
* Software.
*
* Please contact the authors for restrictions applying to commercial use.
*
* THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Author: Zephyr Software
* e-mail: jwd@zephyr-software.com
* URL : http://www.zephyr-software.com/
*
*/
#include <libIRDB-core.hpp>
#include <libIRDB-cfg.hpp>
#include <utils.hpp> // to_string function from libIRDB
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
using namespace libIRDB;
using namespace std;
//
// main routine to build and print a call graph.
//
main(int argc, char* argv[])
{
if(argc!=2)
{
cerr<<"Usage: "<<argv[0]<<" <variant id> "<<endl;
exit(-1);
}
string filename;
ostream *fout;
fout=&cout;
VariantID_t *varidp=NULL;
FileIR_t *firp=NULL;
/* setup the interface to the sql server */
pqxxDB_t pqxx_interface;
BaseObj_t::SetInterface(&pqxx_interface);
try
{
cerr<<"Looking up variant "<<string(argv[1])<<" from database." << endl;
varidp=new VariantID_t(atoi(argv[1]));
// A callgraph
Callgraph_t *cg=new Callgraph_t;
assert(varidp->IsRegistered()==true);
for(set<File_t*>::iterator it=varidp->GetFiles().begin();
it!=varidp->GetFiles().end();
++it
)
{
File_t* this_file=*it;
assert(this_file);
cerr<<"Reading variant "<<string(argv[1])<<":"<<this_file->GetURL()
<<" from database." << endl;
// read the db
firp=new FileIR_t(*varidp,this_file);
// ILR only for the main file.
cg->AddFile(firp);
}
cg->Dump(*fout);
}
catch (DatabaseError_t pnide)
{
cerr<<"Unexpected database error: "<<pnide<<endl;
exit(-1);
}
cerr<<"Done!"<<endl;
if(fout!=&cout)
((ofstream*)fout)->close();
delete varidp;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment