KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > jimple > toolkits > callgraph > OnFlyCallGraphBuilder


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 2003 Ondrej Lhotak
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */

19
20 package soot.jimple.toolkits.callgraph;
21 import soot.*;
22 import soot.options.*;
23 import soot.jimple.*;
24 import java.util.*;
25 import soot.util.*;
26 import soot.util.queue.*;
27
28 /** Models the call graph.
29  * @author Ondrej Lhotak
30  */

31 public final class OnFlyCallGraphBuilder
32 {
33     /** context-insensitive stuff */
34     private CallGraph cicg = new CallGraph();
35     private HashSet analyzedMethods = new HashSet();
36
37     private LargeNumberedMap receiverToSites = new LargeNumberedMap( Scene.v().getLocalNumberer() ); // Local -> List(VirtualCallSite)
38
private LargeNumberedMap methodToReceivers = new LargeNumberedMap( Scene.v().getMethodNumberer() ); // SootMethod -> List(Local)
39
public LargeNumberedMap methodToReceivers() { return methodToReceivers; }
40
41     private SmallNumberedMap stringConstToSites = new SmallNumberedMap( Scene.v().getLocalNumberer() ); // Local -> List(VirtualCallSite)
42
private LargeNumberedMap methodToStringConstants = new LargeNumberedMap( Scene.v().getMethodNumberer() ); // SootMethod -> List(Local)
43
public LargeNumberedMap methodToStringConstants() { return methodToStringConstants; }
44
45     private CGOptions options;
46
47     private boolean appOnly;
48
49     /** context-sensitive stuff */
50     private ReachableMethods rm;
51     private QueueReader worklist;
52
53     private ContextManager cm;
54
55     private ChunkedQueue targetsQueue = new ChunkedQueue();
56     private QueueReader targets = targetsQueue.reader();
57
58
59     public OnFlyCallGraphBuilder( ContextManager cm, ReachableMethods rm ) {
60         this.cm = cm;
61         this.rm = rm;
62         worklist = rm.listener();
63         options = new CGOptions( PhaseOptions.v().getPhaseOptions("cg") );
64         if( !options.verbose() ) {
65             G.v().out.println( "[Call Graph] For information on where the call graph may be incomplete, use the verbose option to the cg phase." );
66         }
67     }
68     public OnFlyCallGraphBuilder( ContextManager cm, ReachableMethods rm, boolean appOnly ) {
69         this( cm, rm );
70         this.appOnly = appOnly;
71     }
72     public void processReachables() {
73         while(true) {
74             if( !worklist.hasNext() ) {
75                 rm.update();
76                 if( !worklist.hasNext() ) break;
77             }
78             MethodOrMethodContext momc = (MethodOrMethodContext) worklist.next();
79             SootMethod m = momc.method();
80             if( appOnly && !m.getDeclaringClass().isApplicationClass() ) continue;
81             if( analyzedMethods.add( m ) ) processNewMethod( m );
82             processNewMethodContext( momc );
83         }
84     }
85     public boolean wantTypes( Local receiver ) {
86         return receiverToSites.get(receiver) != null;
87     }
88     public void addType( Local receiver, Context srcContext, Type type, Context typeContext ) {
89         FastHierarchy fh = Scene.v().getOrMakeFastHierarchy();
90         for( Iterator siteIt = ((Collection) receiverToSites.get( receiver )).iterator(); siteIt.hasNext(); ) {
91             final VirtualCallSite site = (VirtualCallSite) siteIt.next();
92             InstanceInvokeExpr iie = site.iie();
93             if( site.kind() == Kind.THREAD
94             && !fh.canStoreType( type, clRunnable ) )
95                 continue;
96
97             if( site.iie() instanceof SpecialInvokeExpr ) {
98                 targetsQueue.add( VirtualCalls.v().resolveSpecial(
99                             (SpecialInvokeExpr) site.iie(),
100                             site.subSig(),
101                             site.container() ) );
102             } else {
103                 VirtualCalls.v().resolve( type,
104                         receiver.getType(),
105                         site.subSig(),
106                         site.container(),
107                         targetsQueue );
108             }
109             while(targets.hasNext()) {
110                 SootMethod target = (SootMethod) targets.next();
111                 cm.addVirtualEdge(
112                         MethodContext.v( site.container(), srcContext ),
113                         site.stmt(),
114                         target,
115                         site.kind(),
116                         typeContext );
117             }
118         }
119     }
120     public boolean wantStringConstants( Local stringConst ) {
121         return stringConstToSites.get(stringConst) != null;
122     }
123     public void addStringConstant( Local l, Context srcContext, String JavaDoc constant ) {
124         for( Iterator siteIt = ((Collection) stringConstToSites.get( l )).iterator(); siteIt.hasNext(); ) {
125             final VirtualCallSite site = (VirtualCallSite) siteIt.next();
126             if( constant == null ) {
127                 if( options.verbose() ) {
128                     G.v().out.println( "Warning: Method "+site.container()+
129                         " is reachable, and calls Class.forName on a"+
130                         " non-constant String; graph will be incomplete!"+
131                         " Use safe-forname option for a conservative result." );
132                 }
133             } else {
134                 if( constant.charAt(0) == '[' ) {
135                     if( constant.length() > 1 && constant.charAt(1) == 'L'
136                     && constant.charAt(constant.length()-1) == ';' ) {
137                         constant = constant.substring(2,constant.length()-1);
138                     } else continue;
139                 }
140                 if( !Scene.v().containsClass( constant ) ) {
141                     if( options.verbose() ) {
142                         G.v().out.println( "Warning: Class "+constant+" is"+
143                             " a dynamic class, and you did not specify"+
144                             " it as such; graph will be incomplete!" );
145                     }
146                 } else {
147                     SootClass sootcls = Scene.v().getSootClass( constant );
148                     if( !sootcls.isApplicationClass() ) {
149                         sootcls.setLibraryClass();
150                     }
151                     for( Iterator clinitIt = EntryPoints.v().clinitsOf(sootcls).iterator(); clinitIt.hasNext(); ) {
152                         final SootMethod clinit = (SootMethod) clinitIt.next();
153                         cm.addStaticEdge(
154                                 MethodContext.v( site.container(), srcContext ),
155                                 site.stmt(),
156                                 clinit,
157                                 Kind.CLINIT );
158                     }
159                 }
160             }
161         }
162     }
163
164     /* End of public methods. */
165
166     private void addVirtualCallSite( Stmt s, SootMethod m, Local receiver,
167             InstanceInvokeExpr iie, NumberedString subSig, Kind kind ) {
168         List sites = (List) receiverToSites.get(receiver);
169         if (sites == null) {
170             receiverToSites.put(receiver, sites = new ArrayList());
171             List receivers = (List) methodToReceivers.get(m);
172             if( receivers == null )
173                 methodToReceivers.put(m, receivers = new ArrayList());
174             receivers.add(receiver);
175         }
176         sites.add(new VirtualCallSite(s, m, iie, subSig, kind));
177     }
178     private void processNewMethod( SootMethod m ) {
179         if( m.isNative() || m.isPhantom() ) {
180             return;
181         }
182         Body b = m.retrieveActiveBody();
183         getImplicitTargets( m );
184         findReceivers(m, b);
185     }
186     private void findReceivers(SootMethod m, Body b) {
187         for( Iterator sIt = b.getUnits().iterator(); sIt.hasNext(); ) {
188             final Stmt s = (Stmt) sIt.next();
189             if (s.containsInvokeExpr()) {
190                 InvokeExpr ie = (InvokeExpr) s.getInvokeExpr();
191
192                 if (ie instanceof InstanceInvokeExpr) {
193                     InstanceInvokeExpr iie = (InstanceInvokeExpr) ie;
194                     Local receiver = (Local) iie.getBase();
195                     NumberedString subSig =
196                         iie.getMethodRef().getSubSignature();
197                     addVirtualCallSite( s, m, receiver, iie, subSig,
198                             Edge.ieToKind(iie) );
199                     if( subSig == sigStart ) {
200                         addVirtualCallSite( s, m, receiver, iie, sigRun,
201                                 Kind.THREAD );
202                     }
203                 } else {
204                     SootMethod tgt = ((StaticInvokeExpr) ie).getMethod();
205                     addEdge(m, s, tgt);
206                     if( tgt.getSignature().equals( "<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedAction)>" )
207                     || tgt.getSignature().equals( "<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedExceptionAction)>" )
208                     || tgt.getSignature().equals( "<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)>" )
209                     || tgt.getSignature().equals( "<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedExceptionAction,java.security.AccessControlContext)>" ) ) {
210
211                         Local receiver = (Local) ie.getArg(0);
212                         addVirtualCallSite( s, m, receiver, null, sigObjRun,
213                                 Kind.PRIVILEGED );
214                     }
215                 }
216             }
217         }
218     }
219     
220     private void getImplicitTargets( SootMethod source ) {
221         List stringConstants = (List) methodToStringConstants.get(source);
222         if( stringConstants == null )
223             methodToStringConstants.put(source, stringConstants = new ArrayList());
224         final SootClass scl = source.getDeclaringClass();
225         if( source.isNative() || source.isPhantom() ) return;
226         if( source.getSubSignature().indexOf( "<init>" ) >= 0 ) {
227             handleInit(source, scl);
228         }
229         Body b = source.retrieveActiveBody();
230         boolean warnedAlready = false;
231         for( Iterator sIt = b.getUnits().iterator(); sIt.hasNext(); ) {
232             final Stmt s = (Stmt) sIt.next();
233             if( s.containsInvokeExpr() ) {
234                 InvokeExpr ie = (InvokeExpr) s.getInvokeExpr();
235                 if( ie.getMethod().getSignature().equals( "<java.lang.reflect.Method: java.lang.Object invoke(java.lang.Object,java.lang.Object[])>" ) ) {
236                     if( !warnedAlready ) {
237                         if( options.verbose() ) {
238                             G.v().out.println( "Warning: call to "+
239                                 "java.lang.reflect.Method: invoke() from "+source+
240                                 "; graph will be incomplete!" );
241                         }
242                         warnedAlready = true;
243                     }
244                 }
245                 if( ie.getMethod().getSignature().equals( "<java.lang.Class: java.lang.Object newInstance()>" ) ) {
246                     if( options.safe_newinstance() ) {
247                         for( Iterator tgtIt = EntryPoints.v().inits().iterator(); tgtIt.hasNext(); ) {
248                             final SootMethod tgt = (SootMethod) tgtIt.next();
249                             addEdge( source, s, tgt, Kind.NEWINSTANCE );
250                         }
251                     } else {
252                         if( options.verbose() ) {
253                             G.v().out.println( "Warning: Method "+source+
254                                 " is reachable, and calls Class.newInstance;"+
255                                 " graph will be incomplete!"+
256                                 " Use safe-newinstance option for a conservative result." );
257                         }
258                     }
259                 }
260                 if( ie instanceof StaticInvokeExpr ) {
261                     SootClass cl = ie.getMethodRef().declaringClass();
262                     for( Iterator clinitIt = EntryPoints.v().clinitsOf(cl).iterator(); clinitIt.hasNext(); ) {
263                         final SootMethod clinit = (SootMethod) clinitIt.next();
264                         addEdge( source, s, clinit, Kind.CLINIT );
265                     }
266                 }
267                 if( ie.getMethodRef().getSubSignature() == sigForName ) {
268                     Value className = ie.getArg(0);
269                     if( className instanceof StringConstant ) {
270                         String JavaDoc cls = ((StringConstant) className ).value;
271                         constantForName( cls, source, s );
272                     } else {
273                         Local constant = (Local) className;
274                         if( options.safe_forname() ) {
275                             for( Iterator tgtIt = EntryPoints.v().clinits().iterator(); tgtIt.hasNext(); ) {
276                                 final SootMethod tgt = (SootMethod) tgtIt.next();
277                                 addEdge( source, s, tgt, Kind.CLINIT );
278                             }
279                         } else {
280                             VirtualCallSite site = new VirtualCallSite( s, source, null, null, Kind.CLINIT );
281                             List sites = (List) stringConstToSites.get(constant);
282                             if (sites == null) {
283                                 stringConstToSites.put(constant, sites = new ArrayList());
284                                 stringConstants.add(constant);
285                             }
286                             sites.add(site);
287                         }
288                     }
289                 }
290             }
291             if( s.containsFieldRef() ) {
292                 FieldRef fr = (FieldRef) s.getFieldRef();
293                 if( fr instanceof StaticFieldRef ) {
294                     SootClass cl = fr.getFieldRef().declaringClass();
295                     for( Iterator clinitIt = EntryPoints.v().clinitsOf(cl).iterator(); clinitIt.hasNext(); ) {
296                         final SootMethod clinit = (SootMethod) clinitIt.next();
297                         addEdge( source, s, clinit, Kind.CLINIT );
298                     }
299                 }
300             }
301             if( s instanceof AssignStmt ) {
302                 Value rhs = ((AssignStmt)s).getRightOp();
303                 if( rhs instanceof NewExpr ) {
304                     NewExpr r = (NewExpr) rhs;
305                     SootClass cl = r.getBaseType().getSootClass();
306                     for( Iterator clinitIt = EntryPoints.v().clinitsOf(cl).iterator(); clinitIt.hasNext(); ) {
307                         final SootMethod clinit = (SootMethod) clinitIt.next();
308                         addEdge( source, s, clinit, Kind.CLINIT );
309                     }
310                 } else if( rhs instanceof NewArrayExpr || rhs instanceof NewMultiArrayExpr ) {
311                     Type t = rhs.getType();
312                     if( t instanceof ArrayType ) t = ((ArrayType)t).baseType;
313                     if( t instanceof RefType ) {
314                         SootClass cl = ((RefType) t).getSootClass();
315                         for( Iterator clinitIt = EntryPoints.v().clinitsOf(cl).iterator(); clinitIt.hasNext(); ) {
316                             final SootMethod clinit = (SootMethod) clinitIt.next();
317                             addEdge( source, s, clinit, Kind.CLINIT );
318                         }
319                     }
320                 }
321             }
322         }
323     }
324
325     private void processNewMethodContext( MethodOrMethodContext momc ) {
326         SootMethod m = momc.method();
327         Object JavaDoc ctxt = momc.context();
328         Iterator it = cicg.edgesOutOf(m);
329         while( it.hasNext() ) {
330             Edge e = (Edge) it.next();
331             cm.addStaticEdge( momc, e.srcUnit(), e.tgt(), e.kind() );
332         }
333     }
334
335     private void handleInit(SootMethod source, final SootClass scl) {
336         addEdge( source, null, scl, sigFinalize, Kind.FINALIZE );
337         FastHierarchy fh = Scene.v().getOrMakeFastHierarchy();
338     }
339     private void constantForName( String JavaDoc cls, SootMethod src, Stmt srcUnit ) {
340         if( cls.charAt(0) == '[' ) {
341             if( cls.charAt(1) == 'L' && cls.charAt(cls.length()-1) == ';' ) {
342                 cls = cls.substring(2,cls.length()-1);
343                 constantForName( cls, src, srcUnit );
344             }
345         } else {
346             if( !Scene.v().containsClass( cls ) ) {
347                 if( options.verbose() ) {
348                     G.v().out.println( "Warning: Class "+cls+" is"+
349                         " a dynamic class, and you did not specify"+
350                         " it as such; graph will be incomplete!" );
351                 }
352             } else {
353                 SootClass sootcls = Scene.v().getSootClass( cls );
354                 if( !sootcls.isApplicationClass() ) {
355                     sootcls.setLibraryClass();
356                 }
357                 for( Iterator clinitIt = EntryPoints.v().clinitsOf(sootcls).iterator(); clinitIt.hasNext(); ) {
358                     final SootMethod clinit = (SootMethod) clinitIt.next();
359                     addEdge( src, srcUnit, clinit, Kind.CLINIT );
360                 }
361
362             }
363         }
364     }
365
366     private void addEdge( SootMethod src, Stmt stmt, SootMethod tgt,
367             Kind kind ) {
368         cicg.addEdge( new Edge( src, stmt, tgt, kind ) );
369     }
370
371     private void addEdge( SootMethod src, Stmt stmt, SootClass cls, NumberedString methodSubSig, Kind kind ) {
372         if( cls.declaresMethod( methodSubSig ) ) {
373             addEdge( src, stmt, cls.getMethod( methodSubSig ), kind );
374         }
375     }
376     private void addEdge( SootMethod src, Stmt stmt, String JavaDoc methodSig, Kind kind ) {
377         if( Scene.v().containsMethod( methodSig ) ) {
378             addEdge( src, stmt, Scene.v().getMethod( methodSig ), kind );
379         }
380     }
381     private void addEdge( SootMethod src, Stmt stmt, SootMethod tgt ) {
382         InvokeExpr ie = stmt.getInvokeExpr();
383         addEdge( src, stmt, tgt, Edge.ieToKind(ie) );
384     }
385
386     private final NumberedString sigMain = Scene.v().getSubSigNumberer().
387         findOrAdd( "void main(java.lang.String[])" );
388     private final NumberedString sigFinalize = Scene.v().getSubSigNumberer().
389         findOrAdd( "void finalize()" );
390     private final NumberedString sigExit = Scene.v().getSubSigNumberer().
391         findOrAdd( "void exit()" );
392     private final NumberedString sigStart = Scene.v().getSubSigNumberer().
393         findOrAdd( "void start()" );
394     private final NumberedString sigRun = Scene.v().getSubSigNumberer().
395         findOrAdd( "void run()" );
396     private final NumberedString sigObjRun = Scene.v().getSubSigNumberer().
397         findOrAdd( "java.lang.Object run()" );
398     private final NumberedString sigForName = Scene.v().getSubSigNumberer().
399         findOrAdd( "java.lang.Class forName(java.lang.String)" );
400     private final RefType clRunnable = RefType.v("java.lang.Runnable");
401     
402 }
403
404
Popular Tags