00001 package edu.ksu.cis.bandera.abstraction.predicate.parser;
00002
00003
00004
00005
00006
00007
00008 import java.util.*;
00009 import java.io.*;
00010 import ca.mcgill.sable.soot.grimp.*;
00011 import ca.mcgill.sable.soot.jimple.*;
00012 import ca.mcgill.sable.soot.*;
00013 import edu.ksu.cis.bandera.jext.*;
00014 import edu.ksu.cis.bandera.jjjc.*;
00015
00016 public class PredicateProcessor implements PredicateParserVisitor {
00017 private static PredicateProcessor visitor = new PredicateProcessor();
00018 private static Grimp grimp = Grimp.v();
00019 private Value baseValue = null;
00020 private static SootClassManager scm = null;
00021
00022
00023
00024 public PredicateProcessor() {
00025 super();
00026 }
00027 public Value binOpProcess(List el, String tok, Object data)
00028 {
00029 if (el.size() == 0) throw new RuntimeException("Token or expression list is zero!");
00030 Value v1 = null, v2 = null;
00031
00032 for (Iterator ei = el.iterator(); ei.hasNext(); )
00033 {
00034 v2 = (Value) ((SimpleNode) ei.next()).jjtAccept(this, data);
00035 if (v1 != null)
00036 {
00037 if (tok.equals("|"))
00038 {
00039 v1 = grimp.newOrExpr(v1, v2);
00040 } else if (tok.equals("&"))
00041 {
00042 v1 = grimp.newAndExpr(v1, v2);
00043 } else if (tok.equals("^"))
00044 {
00045 v1 = grimp.newXorExpr(v1, v2);
00046 } else if (tok.equals("||"))
00047 {
00048 v1 = new LogicalOrExpr(v1, v2);
00049 } else if (tok.equals("&&"))
00050 {
00051 v1 = new LogicalAndExpr(v1, v2);
00052 } else throw new RuntimeException("Error: Undefined token '"+tok+"'");
00053 } else v1 = v2;
00054 }
00055
00056 return v1;
00057 }
00058 public List convert(ASTCompilationUnit top)
00059 {
00060 return (List) top.jjtAccept(visitor,null);
00061 }
00062 private Value fieldAccess(String s)
00063 {
00064 String context = getContext(s);
00065 if (context == null) return null;
00066
00067
00068 String field;
00069 if (s.length() > context.length())
00070 field = s.substring(context.length() + 1);
00071 else field = s;
00072 return fieldAccess(context,field);
00073 }
00074 private Value fieldAccess(String clsName, String field)
00075 {
00076 return fieldAccess(clsName, field, null);
00077 }
00078 private Value fieldAccess(String clsName, String field, Value base)
00079 {
00080
00081 SootClass sc;
00082 SootField sf;
00083 String temp = field;
00084 int idx;
00085 String s;
00086 if (base == null) base = grimp.newLocal("this", RefType.v(clsName));
00087 if (field.equals("this")) return base;
00088 if (field == null || field.equals("")) throw new RuntimeException("Field access violation!");
00089
00090
00091 do {
00092
00093 sc = getSootClass(base.getType().toString());
00094 if (sc == null) throw new RuntimeException("SootClass '"+base.getType().toString()+"' is not found!");
00095
00096 idx = temp.indexOf('.');
00097 if (idx > -1)
00098 {
00099 s = temp.substring(0, idx);
00100 temp = temp.substring(idx + 1);
00101 } else
00102 {
00103 s = temp; temp = null;
00104 }
00105
00106 if (!sc.declaresField(s)) return null;
00107
00108 try
00109 {
00110 sf = sc.getField(s);
00111 } catch (Exception e)
00112 {
00113
00114
00115
00116
00117 {
00118 throw new RuntimeException("Unable to reference field '" + s + "': " + e.getMessage());
00119 }
00120 }
00121
00122 if (Modifier.isStatic(sf.getModifiers()))
00123 {
00124 base = grimp.newStaticFieldRef(sf);
00125 } else
00126 {
00127 base = grimp.newInstanceFieldRef(base, sf);
00128 }
00129 } while (temp != null);
00130
00131 return base;
00132 }
00133 private String getContext(String s)
00134 {
00135 if (getSootClass(s) != null) return s;
00136
00137 String context = s;
00138 int idx;
00139 do {
00140 idx = context.lastIndexOf('.');
00141 if (idx > -1)
00142 {
00143 context = context.substring(0,idx);
00144 if (getSootClass(context) != null) return context;
00145 }
00146 } while (idx > -1);
00147 return null;
00148 }
00149 private Value getLocal(PredicateImpl pred, String loc)
00150 {
00151 SootClass sc = pred.getClassContext();
00152 if (sc == null) throw new RuntimeException("Error: Class '"+pred.getClassName()+"' is not found!");
00153 SootMethod sm = pred.getMethodContext();
00154
00155 JimpleBody jb = (JimpleBody) sm.getBody(Jimple.v());
00156
00157 Value v = null;
00158 int idx = loc.indexOf('.');
00159 if (idx > -1)
00160 {
00161
00162 String first = loc.substring(0,idx);
00163 String rest = loc.substring(idx+1);
00164 if (!jb.declaresLocal(first)) return null;
00165 v = jb.getLocal(first);
00166 v = fieldAccess(sm.getName(), rest, v);
00167 } else
00168 {
00169 if (!jb.declaresLocal(loc)) return null;
00170 v = jb.getLocal(loc);
00171 }
00172
00173 return v;
00174 }
00175 public static SootClass getSootClass(String name)
00176 {
00177 SootClass sc = scm.managesClass(name) ? scm.getClass(name) : null;
00178 return sc;
00179 }
00180 public static SootMethod getSootMethod(String cls, String method, List type)
00181 {
00182 SootClass sc = getSootClass(cls);
00183 if (sc == null) throw new RuntimeException("Cannot find class name '"+cls+"'");
00184
00185
00186 ca.mcgill.sable.util.LinkedList ll = new ca.mcgill.sable.util.LinkedList();
00187 for (Iterator i = type.iterator(); i.hasNext(); )
00188 {
00189 ll.addLast(i.next());
00190 }
00191
00192 SootMethod sm = sc.getMethod(method, ll);
00193 if (sm == null) System.out.println("Warning: The method '"+method+"' on class '"+cls+"' with "+type+" is not found!");
00194 return sm;
00195 }
00196 public static void main(String[] args)
00197 {
00198 if (args.length == 3)
00199 {
00200 try {
00201 CompilationManager.setDoBSL(false);
00202 CompilationManager.reset();
00203 CompilationManager.setFilename(args[2]+File.separator+args[0]);
00204 CompilationManager.setClasspath(args[2]);
00205 CompilationManager.setIncludedPackagesOrTypes(new String[0]);
00206
00207 CompilationManager.compile();
00208 if (CompilationManager.getExceptions().size() > 0)
00209 {
00210 throw new RuntimeException("Compilation failed!\n");
00211 }
00212 System.out.println("Compiled successfully!\n");
00213
00214 System.out.println("Parsing: " + args[2]+File.separator+args[1]);
00215 FileInputStream in = new FileInputStream(args[2]+File.separator+args[1]);
00216 List pred = process(in, CompilationManager.getSootClassManager());
00217 if (pred == null)
00218 System.out.println("Error!");
00219 } catch (Exception e)
00220 {
00221 System.out.println("Waaaah! " + e.getMessage());
00222 }
00223 }
00224 }
00225 public Value multiBinOpProcess(List el, List tl, Object data)
00226 {
00227 if (tl.size() == 0 || el.size() == 0) throw new RuntimeException("Token or expression list is zero!");
00228 if (tl.size() != el.size()-1) throw new RuntimeException("Unbalanced operator and operands!");
00229 Iterator ti = tl.iterator();
00230 Value v1 = null, v2 = null;
00231
00232 for (Iterator ei = el.iterator(); ei.hasNext(); )
00233 {
00234 v2 = (Value) ((SimpleNode) ei.next()).jjtAccept(this, data);
00235 if (v1 != null)
00236 {
00237 String tok = (String) ti.next();
00238 if (tok.equals("<<"))
00239 {
00240 v1 = grimp.newShlExpr(v1, v2);
00241 } else if (tok.equals(">>"))
00242 {
00243 v1 = grimp.newShrExpr(v1, v2);
00244 } else if (tok.equals(">>>"))
00245 {
00246 v1 = grimp.newUshrExpr(v1, v2);
00247 } else if (tok.equals("+"))
00248 {
00249 v1 = grimp.newAddExpr(v1, v2);
00250 } else if (tok.equals("-"))
00251 {
00252 v1 = grimp.newSubExpr(v1, v2);
00253 } else if (tok.equals("*"))
00254 {
00255 v1 = grimp.newMulExpr(v1, v2);
00256 } else if (tok.equals("/"))
00257 {
00258 v1 = grimp.newDivExpr(v1, v2);
00259 } else if (tok.equals("%"))
00260 {
00261 v1 = grimp.newRemExpr(v1, v2);
00262 } else if (tok.equals("=="))
00263 {
00264 v1 = grimp.newEqExpr(v1, v2);
00265 } else if (tok.equals("!="))
00266 {
00267 v1 = grimp.newNeExpr(v1, v2);
00268 } else throw new RuntimeException("Error: Undefined token '"+tok+"'");
00269 } else v1 = v2;
00270 }
00271
00272 return v1;
00273 }
00274 public static List process(InputStream in, SootClassManager cm) throws Exception
00275 {
00276 ASTCompilationUnit node = PredicateParser.parse(in);
00277 scm = cm;
00278 List pred = visitor.convert(node);
00279 return pred;
00280 }
00281
00282
00283
00284 public Object visit(ASTAddSubExpr node, Object data) {
00285 return multiBinOpProcess(node.getExprList(), node.getTokenList(), data);
00286 }
00287
00288
00289
00290 public Object visit(ASTAndExpr node, Object data) {
00291 return binOpProcess(node.getExprList(), node.getToken(), data);
00292 }
00293
00294
00295
00296 public Object visit(ASTArguments node, Object data) {
00297 List args = node.getArguments();
00298 LinkedList l = new LinkedList();
00299
00300 for (Iterator i = args.iterator(); i.hasNext(); )
00301 {
00302 l.addLast(((SimpleNode) i.next()).jjtAccept(this, data));
00303 }
00304 return l;
00305 }
00306
00307
00308
00309 public Object visit(ASTArrayExpr node, Object data) {
00310 Value arr = (Value) node.getExpr().jjtAccept(this, data);
00311 String s = node.getTag();
00312 if (s != null)
00313 {
00314 arr = grimp.newArrayRef(fieldAccess(s),arr);
00315 } else
00316 {
00317 if (baseValue == null) throw new RuntimeException("We've gotta have a base value!");
00318 arr = grimp.newArrayRef(baseValue,arr);
00319 }
00320
00321 return arr;
00322 }
00323
00324
00325
00326 public Object visit(ASTBitAndExpr node, Object data) {
00327 return binOpProcess(node.getExprList(), node.getToken(), data);
00328 }
00329
00330
00331
00332 public Object visit(ASTBitOrExpr node, Object data) {
00333 return binOpProcess(node.getExprList(), node.getToken(), data);
00334 }
00335
00336
00337
00338 public Object visit(ASTBitXorExpr node, Object data) {
00339 return binOpProcess(node.getExprList(), node.getToken(), data);
00340 }
00341
00342
00343
00344 public Object visit(ASTCastExpr node, Object data) {
00345 Value v = (Value) node.getExpr().jjtAccept(this,data);
00346 Type t = (Type) node.getType().jjtAccept(this,data);
00347 return grimp.newCastExpr(v,t);
00348 }
00349
00350
00351
00352 public Object visit(ASTCastLookahead node, Object data) {
00353 throw new RuntimeException("CastLookahead is unused!");
00354 }
00355
00356
00357
00358 public Object visit(ASTCompilationUnit node, Object data) {
00359 List ll = node.getPredicate();
00360
00361 if (ll == null || ll.isEmpty()) throw new RuntimeException("Predicate Processor: No predicates are mentioned!");
00362 for (Iterator i = ll.iterator(); i.hasNext(); )
00363 {
00364 PredicateImpl p = (PredicateImpl) i.next();
00365 p.resolveArgs(this);
00366 p.setExpr((Value) p.getExprAST().jjtAccept(this,p));
00367 }
00368 return ll;
00369 }
00370
00371
00372
00373 public Object visit(ASTCondExpr node, Object data) {
00374 SimpleNode ts = node.getTestExpr(), th = node.getThenExpr(), el = node.getElseExpr(), result;
00375
00376 Value v1 = (Value) ts.jjtAccept(this, data);
00377 Value v2 = (Value) th.jjtAccept(this, data);
00378 Value v3 = (Value) el.jjtAccept(this, data);
00379
00380 return new HookExpr(v1, v2, v3);
00381 }
00382
00383
00384
00385 public Object visit(ASTDotClassExpr node, Object data) {
00386 if (baseValue != null) throw new RuntimeException("dot class expression: Invalid combination!");
00387
00388 Type t = (Type) node.getExpr().jjtAccept(this,data);
00389 Vector param = new Vector();
00390 ca.mcgill.sable.util.LinkedList l = new ca.mcgill.sable.util.LinkedList();
00391
00392 l.addLast(node.getTag());
00393 param.add("java.lang.String");
00394
00395 return grimp.newStaticInvokeExpr(getSootMethod("java.lang.Class","forName",param),l);
00396 }
00397
00398
00399
00400 public Object visit(ASTDottedExpr node, Object data) {
00401 if (baseValue == null) throw new RuntimeException("dotted expression: Invalid combination!");
00402 return fieldAccess(((PredicateImpl) data).getClassName(), node.getTag(), baseValue);
00403 }
00404
00405
00406
00407 public Object visit(ASTEqExpr node, Object data) {
00408 return multiBinOpProcess(node.getExprList(), node.getTokenList(), data);
00409 }
00410
00411
00412
00413 public Object visit(ASTInstanceOfExpr node, Object data) {
00414 Value v = (Value) node.getExpr().jjtAccept(this,data);
00415 Type t = (Type) node.getType().jjtAccept(this,data);
00416 return grimp.newInstanceOfExpr(v,t);
00417 }
00418
00419
00420
00421 public Object visit(ASTLiteral node, Object data) {
00422 Object l = node.getLiteral();
00423
00424 if (l == null) return NullConstant.v();
00425 if (l instanceof Integer) return IntConstant.v(((Integer) l).intValue());
00426 if (l instanceof Long) return LongConstant.v(((Long) l).longValue());
00427 if (l instanceof Float) return FloatConstant.v(((Float) l).floatValue());
00428 if (l instanceof Double) return DoubleConstant.v(((Double) l).doubleValue());
00429 if (l instanceof Boolean) return null;
00430 if (l instanceof Character) return null;
00431 if (l instanceof String) return StringConstant.v((String) l);
00432
00433 throw new RuntimeException("Undefined Literal!");
00434 }
00435
00436
00437
00438 public Object visit(ASTMulDivExpr node, Object data) {
00439 return multiBinOpProcess(node.getExprList(), node.getTokenList(), data);
00440 }
00441
00442
00443
00444 public Object visit(ASTName node, Object data) {
00445 return node.getTag();
00446 }
00447
00448
00449
00450 public Object visit(ASTOrExpr node, Object data) {
00451 return binOpProcess(node.getExprList(), node.getToken(), data);
00452 }
00453
00454
00455
00456 public Object visit(ASTPrimaryExpr node, Object data) {
00457
00458 baseValue = null;
00459 for (Iterator i = node.getNodes().iterator(); i.hasNext(); )
00460 {
00461 SimpleNode n = (SimpleNode) i.next();
00462
00463 if (n instanceof ASTName)
00464 {
00465 if (baseValue != null) throw new RuntimeException("Name expression: Invalid combination!");
00466 String s = (String) n.jjtAccept(this,data);
00467
00468 if (!i.hasNext())
00469 {
00470 if (getContext(s) == null)
00471 {
00472
00473 PredicateImpl pred = (PredicateImpl) data;
00474
00475 Value v = getLocal(pred,s);
00476 if (v != null)
00477 {
00478 return v;
00479 }
00480
00481 v = fieldAccess(pred.getClassName(),s);
00482 if (v != null)
00483 {
00484 return v;
00485 }
00486
00487
00488 throw new RuntimeException("Invalid reference on '"+s+"'");
00489
00490 } else
00491 {
00492
00493 Value v = (Value) fieldAccess(s);
00494 if (v != null) return v;
00495
00496
00497 throw new RuntimeException("Invalid reference on '"+s+"'");
00498 }
00499
00500 } else throw new RuntimeException("Unhandled case!");
00501 } else if (n instanceof ASTLiteral)
00502 {
00503 if (baseValue != null) throw new RuntimeException("Literal expression: Invalid combination!");
00504
00505 Value v = (Value) n.jjtAccept(this,data);
00506 if (!i.hasNext()) return v;
00507 if (i.hasNext() && !(v instanceof StringConstant))
00508 {
00509 throw new RuntimeException("Illegal literal expression: It can't be trailled by any other things!");
00510 }
00511
00512
00513 throw new RuntimeException("String literal with method call: Unhandled case!");
00514 } else if (n instanceof ASTThisExpr)
00515 {
00516 baseValue = (Value) n.jjtAccept(this,data);
00517 } else if (n instanceof ASTSuperExpr)
00518 {
00519 baseValue = (Value) n.jjtAccept(this,data);
00520 } else if (n instanceof ASTDottedExpr)
00521 {
00522 baseValue = (Value) n.jjtAccept(this,data);
00523 } else if (n instanceof ASTDotClassExpr)
00524 {
00525 baseValue = (Value) n.jjtAccept(this,data);
00526 } else if (n instanceof ASTArrayExpr)
00527 {
00528 baseValue = (Value) n.jjtAccept(this,data);
00529 } else throw new RuntimeException("Unexpected nodes!");
00530 }
00531 if (baseValue == null) throw new RuntimeException("Unexpected end of nodes!");
00532 return baseValue;
00533 }
00534
00535
00536
00537 public Object visit(ASTPrimitiveType node, Object data) {
00538 throw new RuntimeException("PrimitiveType is unused! It's already bypassed");
00539 }
00540
00541
00542
00543 public Object visit(ASTRelationalExpr node, Object data) {
00544 Value v1 = (Value) node.getOp1().jjtAccept(this, data);
00545 Value v2 = (Value) node.getOp2().jjtAccept(this, data);
00546 String tok = node.getTag();
00547
00548 if (tok.equals("<"))
00549 {
00550 return grimp.newLtExpr(v1, v2);
00551 } else if (tok.equals(">"))
00552 {
00553 return grimp.newGtExpr(v1, v2);
00554 } else if (tok.equals("<="))
00555 {
00556 return grimp.newLeExpr(v1, v2);
00557 } else if (tok.equals(">="))
00558 {
00559 return grimp.newGeExpr(v1, v2);
00560 } else throw new RuntimeException("Error: Undefined token '"+tok+"'");
00561 }
00562
00563
00564
00565 public Object visit(ASTShiftExpr node, Object data) {
00566 return multiBinOpProcess(node.getExprList(), node.getTokenList(), data);
00567 }
00568
00569
00570
00571 public Object visit(ASTSuperExpr node, Object data) {
00572 if (baseValue == null)
00573 return grimp.newThisRef(((PredicateImpl) data).getClassContext().getSuperClass());
00574 else
00575 {
00576 if (baseValue instanceof ThisRef)
00577 return grimp.newThisRef(getSootClass(baseValue.getType().toString()).getSuperClass());
00578 else throw new RuntimeException("Invalid combination on 'super' exception");
00579 }
00580 }
00581
00582
00583
00584 public Object visit(ASTThisExpr node, Object data) {
00585 if (baseValue != null) throw new RuntimeException("'this' expression: Invalid combination!");
00586 return grimp.newThisRef(((PredicateImpl) data).getClassContext());
00587 }
00588
00589
00590
00591 public Object visit(ASTType node, Object data) {
00592 String type = node.getBaseType();
00593 int dim = node.getDimension();
00594 Type t;
00595
00596 if (type.equals("int")) t = IntType.v();
00597 else if (type.equals("long")) t = LongType.v();
00598 else if (type.equals("boolean")) t = BooleanType.v();
00599 else if (type.equals("char")) t = CharType.v();
00600 else if (type.equals("short")) t = ShortType.v();
00601 else if (type.equals("byte")) t = ByteType.v();
00602 else if (type.equals("float")) t = FloatType.v();
00603 else if (type.equals("double")) t = DoubleType.v();
00604 else t = RefType.v(type);
00605
00606 if (dim > 0) t = ArrayType.v((BaseType) t, dim);
00607
00608 return t;
00609 }
00610
00611
00612
00613 public Object visit(ASTUnaryExpr node, Object data) {
00614 return node.getExpr().jjtAccept(this,data);
00615 }
00616
00617
00618
00619 public Object visit(ASTUnaryMathExpr node, Object data) {
00620 Value v = (Value) (node.getExpr().jjtAccept(this,data));
00621 String tok = node.getTag();
00622 if (tok.equals("+"))
00623 {
00624
00625 } else if (tok.equals("-"))
00626 {
00627 v = grimp.newNegExpr(v);
00628 } else if (tok.equals("~"))
00629 {
00630
00631 Type t = v.getType();
00632 if (t instanceof ArrayType) t = ((ArrayType) t).baseType;
00633 if (t.equals(IntType.v()) || t.equals(ShortType.v()) || t.equals(ByteType.v()))
00634 {
00635 v = grimp.newSubExpr(IntConstant.v(-1), v);
00636 } else if (t.equals(LongType.v()))
00637 {
00638 v = grimp.newSubExpr(LongConstant.v(-1), v);
00639 } else throw new RuntimeException("Error: Cannot apply ~ operator to "+t.toString()+" on "+v.toString());
00640 } else if (tok.equals("!"))
00641 {
00642 v = new LogicalNotExpr(v);
00643 } else throw new RuntimeException("Error: Unexpected token '"+tok+"'");
00644 return v;
00645 }
00646
00647
00648
00649 public Object visit(SimpleNode node, Object data) {
00650 throw new RuntimeException("SimpleNode is unused!");
00651 }
00652 }