/* * jimple2boogie - Translates Jimple (or Java) Programs to Boogie * Copyright (C) 2013 Martin Schaef and Stephan Arlt * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.joogie.util; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import org.joogie.GlobalsCache; import org.joogie.soot.SootPrelude; import org.joogie.soot.SootProcedureInfo; import org.joogie.soot.SootValueSwitch; import soot.Local; import soot.Scene; import soot.SootClass; import soot.SootField; import soot.SootMethod; import soot.Trap; import soot.TrapManager; import soot.Unit; import soot.jimple.StaticFieldRef; import soot.jimple.Stmt; import soot.tagkit.LineNumberTag; import soot.tagkit.SourceFileTag; import soot.tagkit.SourceLnNamePosTag; import soot.tagkit.Tag; import boogie.ProgramFactory; import boogie.ast.Attribute; import boogie.ast.expression.Expression; import boogie.ast.expression.IdentifierExpression; import boogie.ast.statement.Statement; import boogie.type.BoogieType; /** * @author schaef * */ public class TranslationHelpers { public static Statement havocEverything(SootProcedureInfo procInfo, SootValueSwitch valueswitch) { LinkedList<IdentifierExpression> havoc_var = new LinkedList<IdentifierExpression>(); for (IdentifierExpression id : procInfo.getLocalVariables()) { havoc_var.add(id); } for (IdentifierExpression id : procInfo.getOutParamters()) { havoc_var.add(id); } for (StaticFieldRef sr : procInfo.usedStaticFields) { sr.apply(valueswitch); IdentifierExpression ide = (IdentifierExpression) valueswitch .getExpression(); havoc_var.add(ide); } havoc_var.add(SootPrelude.v().getHeapVariable()); return GlobalsCache .v() .getPf() .mkHavocStatement( new Attribute[] {}, havoc_var.toArray(new IdentifierExpression[havoc_var .size()])); } public static void getReachableTraps(Unit s, SootMethod m, List<Trap> out_traps, List<Trap> out_finally) { if (m.getActiveBody() == null) { throw new RuntimeException("cannot look into " + m.getSignature()); } out_traps.addAll(TrapManager.getTrapsAt(s, m.getActiveBody())); SootClass throwable = Scene.v().loadClass("java.lang.Throwable", SootClass.SIGNATURES); Unit trap_begin = null; Unit trap_end = null; SootClass trap_exception = null; // Unit trap_handler = null; for (Trap trap : new LinkedList<Trap>(out_traps)) { if (trap.getBeginUnit() == trap_begin && trap.getEndUnit() == trap_end && trap.getException() == trap_exception) { out_traps.remove(trap); if (trap.getException() == throwable) { // in that case the second trap was most likely // of type "any" and thus is a finally block, but // soot translated that into Throwable. out_finally.add(trap); // System.err.println("unreachable finally "+GlobalsCache.v().getUnitLabel((Stmt) // trap.getHandlerUnit())); // System.err.println("\t\t"+GlobalsCache.v().getUnitLabel((Stmt) // trap_handler)); } } else { // everything fine. } trap_begin = trap.getBeginUnit(); trap_end = trap.getEndUnit(); trap_exception = trap.getException(); // trap_handler = trap.getHandlerUnit(); } } public static Statement mkLocationAssertion(Stmt s) { return mkLocationAssertion(s, false, null); } public static Statement mkLocationAssertion(Stmt s, boolean forceCloneAttribute) { return mkLocationAssertion(s, forceCloneAttribute, null); } public static Statement mkLocationAssertion(Stmt s, boolean forceCloneAttribute, String comment) { return GlobalsCache .v() .getPf() .mkAssertStatement( javaLocation2Attribute(s, forceCloneAttribute, comment), GlobalsCache.v().getPf().mkBooleanLiteral(true)); } public static final HashSet<Stmt> clonedFinallyBlocks = new HashSet<Stmt>(); public static Attribute[] javaLocation2Attribute(Stmt s) { return javaLocation2Attribute(s, false, null); } public static Attribute[] javaLocation2Attribute(Stmt s, boolean forceCloneAttribute, String comment) { return javaLocation2Attribute(s.getTags(), clonedFinallyBlocks.contains(s) || forceCloneAttribute, comment); } public static Attribute[] javaLocation2Attribute(List<Tag> list) { return javaLocation2Attribute(list, false, null); } private static String getFileName(SootClass sc) { if (sc.hasOuterClass() && sc.getOuterClass()!=sc) return getFileName(sc.getOuterClass()); String filename = null; for (Tag t_ : sc.getTags()) { if (t_ instanceof SourceFileTag) { filename = ((SourceFileTag) t_).getSourceFile(); if (((SourceFileTag) t_).getAbsolutePath() != null) { filename = ((SourceFileTag) t_).getAbsolutePath(); } break; } else if (t_ instanceof SourceLnNamePosTag) { filename = ((SourceLnNamePosTag) t_).getFileName(); // don't break, mybe there is still a source file tag. } } return filename; } public static Statement createClonedAttribAssert() { ProgramFactory pf = GlobalsCache.v().getPf(); Attribute[] res = new Attribute[] { pf .mkCustomAttribute(ProgramFactory.Cloned) }; return pf.mkAssertStatement(res, pf.mkBooleanLiteral(true)); } public static Attribute[] javaLocation2Attribute(List<Tag> list, boolean isCloned, String comment) { // if the taglist is empty return no location int startln, endln, startcol, endcol; startln = -1; endln = -1; startcol = -1; endcol = -1; String filename = null; if (GlobalsCache.v().currentMethod != null) { filename = getFileName(GlobalsCache.v().currentMethod .getDeclaringClass()); } for (Tag tag : list) { if (tag instanceof LineNumberTag) { startln = ((LineNumberTag) tag).getLineNumber(); break; } else if (tag instanceof SourceLnNamePosTag) { if (filename == null) { filename = ((SourceLnNamePosTag) tag).getFileName(); } startln = ((SourceLnNamePosTag) tag).startLn(); endln = ((SourceLnNamePosTag) tag).endLn(); startcol = ((SourceLnNamePosTag) tag).startPos(); endcol = ((SourceLnNamePosTag) tag).endPos(); break; } else if (tag instanceof SourceFileTag) { if (filename == null) { filename = ((SourceFileTag) tag).getSourceFile(); if (((SourceFileTag) tag).getAbsolutePath() != null) { filename = ((SourceFileTag) tag).getAbsolutePath(); } } break; } else { // Log.info("Tag ignored: " + tag.getClass().toString()); } } if (filename == null && startln == -1 && endln == -1 && startcol == -1 && endcol == -1) { return new Attribute[0]; } if (filename == null && GlobalsCache.v().currentMethod != null) { filename = GlobalsCache.v().currentMethod.getDeclaringClass() .getName(); } ProgramFactory pf = GlobalsCache.v().getPf(); Attribute loc = pf.mkLocationAttribute(filename, startln, endln, startcol, endcol); Attribute[] res; if (isCloned) { if (comment!=null) { res = new Attribute[] { loc, pf.mkCustomAttribute(ProgramFactory.Cloned), pf.mkCommentAttribute(comment)}; } else { res = new Attribute[] { loc, pf.mkCustomAttribute(ProgramFactory.Cloned) }; } } else { if (comment!=null) { res = new Attribute[] { loc, pf.mkCommentAttribute(comment) }; } else { res = new Attribute[] { loc }; } } return res; } public static String getQualifiedName(SootClass c) { StringBuilder sb = new StringBuilder(); sb.append(c.getName()); return replaceIllegalChars(sb.toString()); } public static String getQualifiedName(SootMethod m) { StringBuilder sb = new StringBuilder(); sb.append(m.getReturnType().toString() + "$"); sb.append(m.getDeclaringClass().getName() + "$"); sb.append(m.getName() + "$"); sb.append(m.getNumber()); return replaceIllegalChars(sb.toString()); } public static String getQualifiedName(Local l) { // TODO: check if the name is really unique StringBuilder sb = new StringBuilder(); sb.append(replaceIllegalChars(l.getName())); sb.append(l.getNumber()); return sb.toString(); } public static String getQualifiedName(StaticFieldRef f) { return getQualifiedName(f.getField()); } public static String getQualifiedName(SootField f) { StringBuilder sb = new StringBuilder(); sb.append(f.getType() + "$"); sb.append(f.getDeclaringClass().getName() + "$"); sb.append(f.getName()); sb.append(f.getNumber()); return replaceIllegalChars(sb.toString()); } public static String replaceIllegalChars(String s) { String ret = s.replace("<", "$la$"); ret = ret.replace("@", "$at$"); ret = ret.replace(">", "$ra$"); ret = ret.replace("[", "$lp$"); ret = ret.replace("]", "$rp$"); ret = ret.replace("/", "$_$"); ret = ret.replace(";", "$"); return ret; } /** * This is a helper function to cast between bool and int if soot does not * distinguish them. TODO: extend to ref if necessary * * @param expr * @param target * @return */ public static Expression castBoogieTypes(Expression expr, BoogieType target) { if (expr.getType() == target) { return expr; } else if (expr.getType() == GlobalsCache.v().getPf().getIntType() && target == GlobalsCache.v().getPf().getBoolType()) { return SootPrelude.v().intToBool(expr); } else if (expr.getType() == GlobalsCache.v().getPf().getBoolType() && target == GlobalsCache.v().getPf().getIntType()) { return SootPrelude.v().boolToInt(expr); } else if (expr.getType() == GlobalsCache.v().getPf().getIntType() && target == GlobalsCache.v().getPf().getRealType()) { return SootPrelude.v().intToReal(expr); } else if (expr.getType() == GlobalsCache.v().getPf().getRealType() && target == GlobalsCache.v().getPf().getIntType()) { return SootPrelude.v().realToInt(expr); } else if (expr.getType() == SootPrelude.v().getReferenceType() && target == GlobalsCache.v().getPf().getBoolType()) { return SootPrelude.v().refToBool(expr); } else if (expr == SootPrelude.v().getNullConstant() && target == GlobalsCache.v().getPf().getRealType()) { return GlobalsCache.v().getPf().mkRealLiteral("0.0"); } else if (expr == SootPrelude.v().getNullConstant() && target == GlobalsCache.v().getPf().getIntType()) { return GlobalsCache.v().getPf().mkIntLiteral("0"); } throw new RuntimeException("Cannot cast " + expr.toString() + " from: " + ((expr.getType() == null) ? "null" : expr.getType() .getClass().toString()) + " to " + target.getClass().toString()); // return expr; } }