/* Soot - a J*va Optimization Framework
* Copyright (C) 2011 Richard Xiao
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package soot.jimple.spark.geom.geomPA;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import soot.SootMethod;
import soot.jimple.spark.geom.geomPA.CallsiteContextVar;
import soot.jimple.spark.geom.geomPA.CgEdge;
import soot.jimple.spark.geom.geomPA.GeomPointsTo;
import soot.jimple.spark.geom.geomPA.IVarAbstraction;
import soot.jimple.spark.geom.geomPA.ZArrayNumberer;
import soot.jimple.spark.pag.AllocNode;
import soot.jimple.spark.pag.LocalVarNode;
import soot.jimple.spark.pag.Node;
/**
* Output the points-to matrix in various formats.
* This is used to facilitate the pointer analysis experimenting outside SOOT.
*
* @author xiao
*
*/
public class PointsToDumper
{
/**
* Dump the context insensitive points-to result generated from the geometric analysis by throwing away the context information.
* @param ptsProvider
*/
public static void dump_context_insensitive_mapped_result( GeomPointsTo ptsProvider )
{
try {
final PrintWriter file = new PrintWriter(new FileOutputStream(
new File("pags", ptsProvider.dump_file_name + ".ptm")));
// First dump a descriptor
// 0 is the result of pointer and object insensitive matrix
file.println( "0" );
file.println( ptsProvider.getNumberOfPointers() + " " + ptsProvider.getNumberOfObjects() );
for (IVarAbstraction pn : ptsProvider.pointers) {
pn = pn.getRepresentative();
Set<AllocNode> objSet = pn.get_all_points_to_objects();
file.print( objSet.size() );
for ( AllocNode obj : objSet ) {
IVarAbstraction pobj = ptsProvider.findInternalNode(obj);
file.print( " " + pobj.getNumber() );
}
file.println();
}
file.close();
} catch( IOException e ) {
throw new RuntimeException( "Couldn't dump solution."+e );
}
}
/**
* Dump the 1-CFA pointer context sensitive but object insensitive result.
*/
public static void dump_pointer_1cfa_object_insensitive_mapped_result( GeomPointsTo ptsProvider )
{
int var_num;
final List<AllocNode> list = new ArrayList<AllocNode>();
try {
final PrintWriter file = new PrintWriter(new FileOutputStream(
new File("pags", ptsProvider.dump_file_name + ".ptm")));
// First dump a descriptor
// 0 is the result of pointer and object insensitive matrix
file.println( "16" ); // 0x00000010
var_num = 0;
for ( IVarAbstraction pn : ptsProvider.pointers ) {
pn = pn.getRepresentative();
Node v = pn.getWrappedNode();
if ( v instanceof LocalVarNode ) {
LocalVarNode lvn = (LocalVarNode)v;
SootMethod sm = lvn.getMethod();
int sm_int = ptsProvider.getIDFromSootMethod(sm);
var_num += ptsProvider.getCallEdgesInto(sm_int).size();
}
else
var_num++;
}
file.println( var_num + " " + ptsProvider.getNumberOfObjects() );
for (IVarAbstraction pn : ptsProvider.pointers ) {
pn = pn.getRepresentative();
Node v = pn.getWrappedNode();
if ( v instanceof LocalVarNode ) {
// We map the local pointer to its 1-cfa versions
LocalVarNode lvn = (LocalVarNode)v;
SootMethod sm = lvn.getMethod();
int sm_int = ptsProvider.getIDFromSootMethod(sm);
LinkedList<CgEdge> edges = ptsProvider.getCallEdgesInto( sm_int );
for ( Iterator<CgEdge> it = edges.iterator(); it.hasNext(); ) {
CgEdge p = it.next();
long l = p.map_offset;
long r = l + ptsProvider.max_context_size_block[p.s];
list.clear();
for ( AllocNode obj : pn.get_all_points_to_objects() ) {
if ( pn.pointer_interval_points_to(l, r, obj) )
list.add(obj);
}
file.print( list.size() );
for ( AllocNode obj : list ) {
IVarAbstraction po = ptsProvider.findInternalNode(obj);
file.print( " " + po.getNumber() );
}
file.println();
}
}
else {
Set<AllocNode> objSet = pn.get_all_points_to_objects();
file.print( objSet.size() );
for ( AllocNode obj : objSet ) {
IVarAbstraction po = ptsProvider.findInternalNode(obj);
file.print( " " + po.getNumber() );
}
file.println();
}
}
file.close();
} catch( IOException e ) {
throw new RuntimeException( "Couldn't dump solution."+e );
}
}
/**
* Dump the pointer insensitive but object 1-CFA context sensitive points-to result.
*/
public static void dump_pointer_insensitive_object_1cfa_mapped_result( GeomPointsTo ptsProvider )
{
int var_num, obj_num;
ZArrayNumberer<CallsiteContextVar> ct_sens_objs = new ZArrayNumberer<CallsiteContextVar>();
Vector<CallsiteContextVar> outList = new Vector<CallsiteContextVar>();
CallsiteContextVar context_obj = null;
try {
final PrintWriter file = new PrintWriter(new FileOutputStream(
new File("pags", ptsProvider.dump_file_name + ".ptm")));
// First dump a descriptor
// 0 is the result of pointer and object insensitive matrix
file.println( "1" ); //0x00000001
var_num = 0;
obj_num = 0;
for ( IVarAbstraction pn : ptsProvider.pointers ) {
if ( pn == pn.getRepresentative() )
var_num++;
}
// Construct all the context sensitive objects
for ( IVarAbstraction pobj : ptsProvider.allocations ) {
AllocNode obj = (AllocNode)pobj.getWrappedNode();
SootMethod sm = obj.getMethod();
if ( sm == null ) {
obj_num++;
context_obj = new CallsiteContextVar(null, obj);
ct_sens_objs.add(context_obj);
}
else {
int sm_int = ptsProvider.getIDFromSootMethod(sm);
if ( ptsProvider.isReachableMethod(sm_int) ) {
// We also temporarily build the 1cfa object
List<CgEdge> edges = ptsProvider.getCallEdgesInto(sm_int);
obj_num += edges.size();
for ( CgEdge ce : edges ) {
context_obj = new CallsiteContextVar(ce, obj);
ct_sens_objs.add(context_obj);
}
}
}
}
// The points-to matrix rows and columns
file.println( var_num + " " + obj_num );
// The points-to matrix
for (IVarAbstraction pn : ptsProvider.pointers ) {
if ( pn != pn.getRepresentative() )
continue;
file.print( pn.get_all_context_sensitive_objects(1, GeomPointsTo.MAX_CONTEXTS, ct_sens_objs, outList) );
for ( CallsiteContextVar cobj : outList ) {
cobj.inQ = false;
file.print( " " + cobj.getNumber() );
}
file.println();
}
// The context objects to callsites table
obj_num = ptsProvider.getNumberOfObjects();
file.println( obj_num );
int i = 1, j = 0;
while ( true ) {
// We first identify all the objects that are mapped to the same callsite
CallsiteContextVar first_obj = ct_sens_objs.get(j);
while ( i < obj_num ) {
CallsiteContextVar cobj = ct_sens_objs.get(i);
if ( cobj.var != first_obj.var )
break;
++i;
}
// output
file.print( (i-j) );
while ( j < i ) {
file.print(" " + j);
++j;
}
file.println();
if ( i == obj_num )
break;
}
file.close();
} catch( IOException e ) {
throw new RuntimeException( "Couldn't dump solution."+e );
}
}
/**
* Dump both the pointer and object 1-CFA context sensitive points-to result.
*/
public static void dump_pointer_object_1cfa_mapped_result( GeomPointsTo ptsProvider )
{
int var_num, obj_num;
int sm_int;
ZArrayNumberer<CallsiteContextVar> ct_sens_objs = new ZArrayNumberer<CallsiteContextVar>();
Vector<CallsiteContextVar> outList = new Vector<CallsiteContextVar>();
CallsiteContextVar context_obj = null;
try {
final PrintWriter file = new PrintWriter(new FileOutputStream(
new File("pags", ptsProvider.dump_file_name + ".ptm")));
// First dump a descriptor
// 0 is the result of pointer and object insensitive matrix
file.println( "17" ); //0x00000011
var_num = 0;
obj_num = 0;
for ( IVarAbstraction pn : ptsProvider.pointers ) {
// pn = pn.getRepresentative();
if ( pn != pn.getRepresentative() )
continue;
Node v = pn.getWrappedNode();
if ( v instanceof LocalVarNode ) {
LocalVarNode lvn = (LocalVarNode)v;
SootMethod sm = lvn.getMethod();
sm_int = ptsProvider.getIDFromSootMethod(sm);
var_num += ptsProvider.getCallEdgesInto(sm_int).size();
}
else
var_num++;
}
for ( IVarAbstraction pobj : ptsProvider.allocations ) {
AllocNode obj = (AllocNode)pobj.getWrappedNode();
SootMethod sm = obj.getMethod();
if ( sm == null ) {
obj_num++;
context_obj = new CallsiteContextVar(null, obj);
ct_sens_objs.add(context_obj);
}
else {
sm_int = ptsProvider.getIDFromSootMethod(sm);
if ( ptsProvider.isReachableMethod(sm_int) ) {
// We also temporarily build the 1cfa object
List<CgEdge> edges = ptsProvider.getCallEdgesInto(sm_int);
obj_num += edges.size();
for ( CgEdge ce : edges ) {
context_obj = new CallsiteContextVar(ce, obj);
ct_sens_objs.add(context_obj);
}
}
}
}
// Matrix rows and columns
file.println( var_num + " " + obj_num );
for (IVarAbstraction pn : ptsProvider.pointers) {
// pn = pn.getRepresentative();
if ( pn != pn.getRepresentative() )
continue;
Node v = pn.getWrappedNode();
if ( v instanceof LocalVarNode ) {
// We map the local pointer to its 1-cfa versions
LocalVarNode lvn = (LocalVarNode)v;
SootMethod sm = lvn.getMethod();
sm_int = ptsProvider.getIDFromSootMethod(sm);
LinkedList<CgEdge> edges = ptsProvider.getCallEdgesInto(sm_int);
for ( Iterator<CgEdge> it = edges.iterator(); it.hasNext(); ) {
CgEdge p = it.next();
long l = p.map_offset;
long r = l + ptsProvider.max_context_size_block[p.s];
file.print( pn.get_all_context_sensitive_objects(l, r, ct_sens_objs, outList) );
for ( CallsiteContextVar cobj : outList ) {
cobj.inQ = false;
file.print( " " + cobj.getNumber() );
}
file.println();
}
}
else {
file.print( pn.get_all_context_sensitive_objects(1, GeomPointsTo.MAX_CONTEXTS, ct_sens_objs, outList) );
for ( CallsiteContextVar cobj : outList ) {
cobj.inQ = false;
file.print( " " + cobj.getNumber() );
}
file.println();
}
}
file.close();
} catch( IOException e ) {
throw new RuntimeException( "Couldn't dump solution."+e );
}
}
}