00001 package edu.ksu.cis.bandera.bofa; 00002 00003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 00004 * Bandera, a Java(TM) analysis and transformation toolkit * 00005 * Copyright (C) 1998, 1999 * 00006 * John Hatcliff (hatcliff@cis.ksu.edu) 00007 * All rights reserved. * 00008 * * 00009 * This work was done as a project in the SAnToS Laboratory, * 00010 * Department of Computing and Information Sciences, Kansas State * 00011 * University, USA (http://www.cis.ksu.edu/santos). * 00012 * It is understood that any modification not identified as such is * 00013 * not covered by the preceding statement. * 00014 * * 00015 * This work is free software; you can redistribute it and/or * 00016 * modify it under the terms of the GNU Library General Public * 00017 * License as published by the Free Software Foundation; either * 00018 * version 2 of the License, or (at your option) any later version. * 00019 * * 00020 * This work is distributed in the hope that it will be useful, * 00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00023 * Library General Public License for more details. * 00024 * * 00025 * You should have received a copy of the GNU Library General Public * 00026 * License along with this toolkit; if not, write to the * 00027 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * 00028 * Boston, MA 02111-1307, USA. * 00029 * * 00030 * Java is a trademark of Sun Microsystems, Inc. * 00031 * * 00032 * To submit a bug report, send a comment, or get the latest news on * 00033 * this project and other SAnToS projects, please visit the web-site * 00034 * http://www.cis.ksu.edu/santos * 00035 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 00036 00037 import ca.mcgill.sable.util.*; 00038 import ca.mcgill.sable.soot.*; 00039 import ca.mcgill.sable.soot.jimple.*; 00040 import org.apache.log4j.Category; 00041 00042 /** 00043 * The class in which the statements of a method are processed to extend the 00044 * FlowGraph for the MethodVariant. 00045 * 00046 * @author <A HREF="http://www.cis.ksu.edu/~hatcliff">John Hatcliff</A> 00047 * @author 00048 * <a href="http://www.cis.ksu.edu/~rvprasad">Venkatesh Prasad Ranganath</a> 00049 * @version $Name: $($Revision: 1.1.1.1 $) 00050 */ 00051 public class FGStmt extends AbstractStmtSwitch 00052 { 00053 /** 00054 * The method variant for which the flow graph needs to be 00055 * extended. 00056 */ 00057 private MethodVariant methodVariant; 00058 00059 /** 00060 * The method associated with the method variant. 00061 */ 00062 private SootMethod sootMethod; 00063 00064 /** 00065 * Maps the AST nodes occuring in the method to flow graph nodes. 00066 */ 00067 private Map astNodes; 00068 00069 /** 00070 * The FGExpr object which will process the expressions that occur in the 00071 * statement that will be processed. 00072 */ 00073 private FGExpr fgExpr; 00074 00075 /** 00076 * The current statement in the method being processed. 00077 */ 00078 private Stmt stmt; 00079 00080 /** 00081 * The object used to process LHS expressions. 00082 * 00083 */ 00084 private TempAbstJmplValSwitch sw; 00085 00086 /** 00087 * Provides logging capability through log4j. 00088 * 00089 */ 00090 private static Category cat; 00091 00092 static { 00093 cat = Category.getInstance("edu.ksu.cis.bandera.bofa.FGStmt"); 00094 } 00095 00096 /** 00097 * The class in which nodes corresponding to LHS expressions are created. 00098 */ 00099 class TempAbstJmplValSwitch extends AbstractJimpleValueSwitch 00100 { 00101 /** 00102 * Handles a local variable on LHS. 00103 * 00104 * @param l the local variable on LHS. 00105 */ 00106 public void caseLocal(Local l) 00107 { 00108 FGNodeAST astNode = new FGNodeAST(l); 00109 FGNode.makeArc(astNode, methodVariant.getLocalNode(l)); 00110 astNodes.put(l, astNode); 00111 ((AbstractJimpleValueSwitch)this).setResult(astNode); 00112 } 00113 00114 /** 00115 * Handles a static field variable on LHS. 00116 * 00117 * @param f the static field variable on LHS. 00118 */ 00119 public void caseStaticFieldRef(StaticFieldRef f) 00120 { 00121 SootField field = f.getField(); 00122 FGNodeAST astNode = new FGNodeAST(f); 00123 FGNode.makeArc(astNode, StaticFieldManager.select(field)); 00124 astNodes.put(f, astNode); 00125 ((AbstractJimpleValueSwitch)this).setResult(astNode); 00126 } 00127 00128 /** 00129 * Handles a instance field variable on LHS. 00130 * 00131 * @param f the instance field variable on LHS. */ 00132 public void caseInstanceFieldRef(InstanceFieldRef f) 00133 { 00134 SootField field = f.getField(); 00135 FGNodeAST astNode = 00136 new FGNodeAST(f); 00137 FGNode.makeArc(astNode, 00138 InstanceVariantManager.select(field).getNode()); 00139 astNodes.put(f, astNode); 00140 ((AbstractJimpleValueSwitch)this).setResult(astNode); 00141 } 00142 00143 // should we also handle CaughtExceptionRef() and NextNextStmtRef() 00144 00145 /** 00146 * Handles array references on LHS. 00147 * 00148 * @param ref the array reference on LHS. 00149 */ 00150 public void caseArrayRef(ArrayRef ref) 00151 { 00152 FGNode baseNode = fgExpr.build(ref.getBase(), stmt); 00153 00154 /* 00155 * The "type" attribute of the array ref AST is the component type 00156 * of the array. Make an array type to use in 00157 * ClassTokenArray.select() 00158 */ 00159 ArrayType arrayType = 00160 ClassTokenArray.componentToArrayType(ref.getType()); 00161 00162 ClassTokenArray classTokenArray = ClassTokenArray.select(arrayType); 00163 00164 // Here, we need to attach an action to the flowgraph as in RHS 00165 // array reference. 00166 FGNodeAST arrayRefNode = new FGNodeAST(ref); 00167 /* 00168 * generate action: Different array objects (represented by value 00169 * variants) may flow into the base node. 00170 * 00171 * For any new value variant that flows into the base node, the 00172 * array variant FGNode that summarizes the contents of the array 00173 * will be found and an FG arc will be made from the AST node to the 00174 * array variant node. 00175 */ 00176 baseNode.addAction(new FGActionArrayStore(classTokenArray, 00177 arrayRefNode)); 00178 astNodes.put(ref,arrayRefNode); 00179 ((AbstractJimpleValueSwitch)this).setResult(arrayRefNode); 00180 } 00181 00182 /** 00183 * Handles all cases that are unhandled at present. 00184 * 00185 * @param o the object representing the value occuring on LHS which is 00186 * currently not handled. 00187 */ 00188 public void defaultCase(Object o) { 00189 cat.debug("Unhandled LHS: " + o.getClass()); 00190 ((AbstractJimpleValueSwitch)this).setResult(null); 00191 } 00192 } 00193 00194 /* This code seems to be tightly coupled to MethodVariant. Perhaps 00195 it should be placed in that class (same for FGExpr). 00196 */ 00197 /** 00198 * Constructor of the class. 00199 * 00200 * @param methodVariant the method whose statements needs to be processed. 00201 * @param astNodes the map of AST nodes for the given method. 00202 */ 00203 public FGStmt(MethodVariant methodVariant, Map astNodes) 00204 { 00205 this.methodVariant = methodVariant; 00206 this.sootMethod = methodVariant.getMethod(); 00207 this.fgExpr = new FGExpr(methodVariant, astNodes); 00208 this.astNodes = astNodes; 00209 sw = new TempAbstJmplValSwitch(); 00210 } 00211 /** 00212 * Starts the extension of flow graph for the given statement. 00213 * 00214 * @param s the statement for which the FG needs to be created. 00215 */ 00216 public void build(Stmt s) 00217 { 00218 stmt = s; 00219 s.apply(this); 00220 } 00221 /** 00222 * Extends the part of flow graph for assignment statement. 00223 * 00224 * @param s the object representing an assignment statement. 00225 */ 00226 public void caseAssignStmt(AssignStmt s) 00227 { 00228 Value lhs, rhs; 00229 FGNodeAST lhsNode, rhsNode; 00230 00231 lhs = s.getLeftOp(); 00232 rhs = s.getRightOp(); 00233 00234 lhsNode = getLHSNode(lhs); 00235 rhsNode = fgExpr.build(rhs, s); 00236 00237 FGNode.makeArc(rhsNode, lhsNode); 00238 } 00239 /** 00240 * Extends the part of flow graph for the entermonitor statement. We just 00241 * process the expression. 00242 * 00243 * @param s the object representing the entermonitor statement. 00244 */ 00245 public void caseEnterMonitorStmt(EnterMonitorStmt s) 00246 { 00247 fgExpr.build(s.getOp(), s); 00248 } 00249 /** 00250 * Extends the part of flow graph for the exitmonitor statement. We just 00251 * process the expression. 00252 * 00253 * @param s the object representing the exitmonitor statement. 00254 */ 00255 public void caseExitMonitorStmt(ExitMonitorStmt s) 00256 { 00257 fgExpr.build(s.getOp(), s); 00258 } 00259 /** 00260 * Extends the part of flow graph for identity statement. 00261 * 00262 * @param s the object representing an identity statement. 00263 */ 00264 public void caseIdentityStmt(IdentityStmt s) 00265 { 00266 /* 00267 * Identity: Generate graph for RHS. Then, make a FG arc from RHS 00268 * node to node for (variable) that appears on LHS. Note that if no 00269 * object values are produced in the RHS, then rhsNode should be null 00270 * and FG.makeArc is defined to do nothing when the source node is null. 00271 * 00272 * Remember: identity is used to represent actions that happen during 00273 * JVM method invocation and manipulation of exceptions. For example, 00274 * in the actual byte code, there is an implicit transfer of the actual 00275 * parameters into slots in the frame (which represent formal parameters 00276 * which are represented the same as locals). In this case, we have 00277 * a Jimple statement like local-a := @param2 --- this represents the 00278 * transfer from the stack into the frame location associated with the 00279 * local variable 'local-a'. 00280 * 00281 * In a similar way, catch blocks like try {...} catch (Exception e) 00282 * {...} are parameterized on the exception e, and there is an implicit 00283 * transfer when the JVM is executing from the current exception to the 00284 * variable e. So this generates identity statements like e := 00285 * @caughtexception. */ 00286 Value lhs, rhs; 00287 FGNodeAST lhsNode, rhsNode; 00288 00289 lhs = s.getLeftOp(); 00290 rhs = s.getRightOp(); 00291 00292 lhsNode = getLHSNode(lhs); 00293 rhsNode = fgExpr.build(rhs, s); 00294 00295 FGNode.makeArc(rhsNode, lhsNode); 00296 } 00297 /** 00298 * Extends the part of flow graph for if statement. We just process the 00299 * boolean expression. 00300 * 00301 * @param s the object representing the if statement. 00302 */ 00303 public void caseIfStmt(IfStmt s) 00304 { 00305 /* 00306 * If: Generate graph for test expression. No outgoing arc since there 00307 * is nothing returned here. We may be able to eliminate traversing the 00308 * expression if there is not object flow within (e.g., no method 00309 * applications). 00310 */ 00311 fgExpr.build(s.getCondition(), s); 00312 } 00313 /** 00314 * Extends the part of flow graph for invoke statement. 00315 * 00316 * @param s the object representing the invocation statement. 00317 */ 00318 public void caseInvokeStmt(InvokeStmt s) 00319 { 00320 fgExpr.build(s.getInvokeExpr(), s); 00321 } 00322 /** 00323 * Extends the part of flow graph for return statement. 00324 * 00325 * @param s the object representing the return statment. 00326 */ 00327 public void caseReturnStmt(ReturnStmt s) 00328 { 00329 /** 00330 * Return: 00331 * Generate a FG for return expression, and make an arc from the return 00332 * expression to the exit node for this method. 00333 */ 00334 FGNode.makeArc(fgExpr.build((Value)s.getReturnValue(), s), 00335 methodVariant.getReturnNode()); 00336 } 00337 /** 00338 * Extends the part of flow graph for the throw statement. We just process 00339 * the expression. 00340 * @param s the object representing the throw statement. 00341 */ 00342 public void caseThrowStmt(ThrowStmt s) 00343 { 00344 fgExpr.build(s.getOp(), s); 00345 } 00346 /** 00347 * Raise an exception for all unhandled statement form. 00348 * 00349 * @param obj the object representing the statement. 00350 */ 00351 public void defaultCase(Object obj) 00352 { 00353 System.out.println("Unhandled Statement: " + obj.getClass()); 00354 } 00355 /** 00356 * Extends the part of flow graph node for LHS expressions. 00357 * 00358 * @param v the object representing the LHS expression. 00359 * @return the flow node corresponding to the given LHS expression. 00360 */ 00361 public FGNodeAST getLHSNode(Value v) 00362 { 00363 v.apply(sw); 00364 FGNodeAST astNode = (FGNodeAST)sw.getResult(); 00365 if (astNode != null) { 00366 astNode.setStmt(stmt); 00367 } // end of if (astNode != null) 00368 return astNode; 00369 } 00370 }