Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

DecompilerUtil.java

00001 package edu.ksu.cis.bandera.jjjc.decompiler;
00002 
00003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00004  * Bandera, a Java(TM) analysis and transformation toolkit           *
00005  * Copyright (C) 2000 Roby Joehanes (robbyjo@cis.ksu.edu)            *
00006  * All rights reserved.                                              *
00007  *                                                                   *
00008  * This work was done as a project in the SAnToS Laboratory,         *
00009  * Department of Computing and Information Sciences, Kansas State    *
00010  * University, USA (http://www.cis.ksu.edu/santos).                  *
00011  * It is understood that any modification not identified as such is  *
00012  * not covered by the preceding statement.                           *
00013  *                                                                   *
00014  * This work is free software; you can redistribute it and/or        *
00015  * modify it under the terms of the GNU Library General Public       *
00016  * License as published by the Free Software Foundation; either      *
00017  * version 2 of the License, or (at your option) any later version.  *
00018  *                                                                   *
00019  * This work is distributed in the hope that it will be useful,      *
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *
00022  * Library General Public License for more details.                  *
00023  *                                                                   *
00024  * You should have received a copy of the GNU Library General Public *
00025  * License along with this toolkit; if not, write to the             *
00026  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,      *
00027  * Boston, MA  02111-1307, USA.                                      *
00028  *                                                                   *
00029  * Java is a trademark of Sun Microsystems, Inc.                     *
00030  *                                                                   *
00031  * To submit a bug report, send a comment, or get the latest news on *
00032  * this project and other SAnToS projects, please visit the web-site *
00033  *                http://www.cis.ksu.edu/santos                      *
00034  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00035 import java.util.*;
00036 import ca.mcgill.sable.soot.*;
00037 import ca.mcgill.sable.soot.jimple.*;
00038 import edu.ksu.cis.bandera.annotation.*;
00039 import edu.ksu.cis.bandera.abstraction.*;
00040 import edu.ksu.cis.bandera.abstraction.util.*;
00041 
00042 /**
00043  * DecompilerUtil is an auxilliary class to help the
00044  * decompilation, especially in flattenning a bunch
00045  * of related statements. The ones that is visible
00046  * from outside is flattenStmts and analyzeCondition.
00047  * Everything else is internal.
00048  * @author <a href="mailto:robbyjo@cis.ksu.edu">Roby Joehanes</a>
00049  * @version 0.4.21
00050 **/
00051 public class DecompilerUtil {
00052     private static Hashtable assignedVar = new Hashtable();
00053     public static final String gotoStr = "$.goto";
00054     private static Hashtable tempTable = new Hashtable();
00055     private static boolean debugInfo = false;
00056     private static boolean allowField = false;
00057 /**
00058  * This method basically flattenning condition statements
00059  * in <TT>if</TT>, <TT>for</tt> (the second argument), <TT>while</tt>,
00060  * and <TT>do...while</tt>. The problem is that Jimple cannot have
00061  * complicated condition statements. So, conditions such as
00062  * <TT>((A && B) || C)</TT> is then divided into several <TT>if</tt>
00063  * statements. Moreover, <tt>if</tt> statements usually followed by
00064  * the nasty bad ugly <tt>goto</tt> which mess everythings up.
00065  * Which at this very moment, I'm quite perplexed.
00066 **/
00067 public static String analyzeCondition(Stmt[] stmts, int code)
00068 {
00069     Vector result = new Vector();
00070     if (stmts==null) return "";
00071     String thenID, elseID;
00072     //Hashtable tempTable = new Hashtable();
00073     Hashtable condTable = new Hashtable();
00074     int max = stmts.length;
00075     Hashtable asgInIf   = new Hashtable();
00076 /*  String lastAssignment = null;
00077     Type lastType = null;
00078 */
00079     for (int i = 0; i < max; i++)
00080     {
00081         switch (code)
00082         {
00083 //          case 0: if (i==0) DecompilerValueSwitch.isAnIfStmt(true); break;
00084             case 1: DecompilerValueSwitch.isAnIfStmt(true); break;
00085         }
00086         // First decompile it
00087         Vector res = DecompilerStmtSwitch.evaluate(stmts[i]);
00088         DecompilerStmtSwitch.reset();
00089 
00090         // Then we'd like to know whether it is an if statement
00091         if (((String) res.get(0)).equals("if"))
00092         {
00093             String ref = ((String) res.get(res.size() - 1)).trim();
00094             Stmt s = DecompilerGotoMapper.getStmt(ref);
00095 
00096             // remove if and gotos
00097             replaceOccurence(res, tempTable);
00098 
00099             // Is there any assignments in the condition? Such as:
00100             // if ((x = foo()) >0)
00101             if (!asgInIf.isEmpty())
00102             {
00103                 int j = res.size();
00104                 for (int it = 0; it < j; it++)
00105                 {
00106                     String id = (String) res.get(it);
00107                     if (asgInIf.containsKey(id))
00108                     {
00109                         // replace the token with the entry on the table
00110                         String tempStr = (String) asgInIf.get(id);
00111                         res.set(it,"("+id+" = "+tempStr+")");
00112                     }
00113                 }
00114             }
00115 
00116             String cond = fixScrewedUpThis(extractCondition(res));
00117             result.add(cond);
00118         } else
00119         {
00120             // Check the rest
00121             if (isAssignment(res))
00122             {
00123                 Vector lhs = extractLHS(res);
00124                 Vector rhs = extractRHS(res);
00125                 replaceOccurence(rhs, tempTable);
00126                 String right = fixScrewedUpThis(flattenToString(rhs));
00127                 String left = flattenToString(lhs);
00128                 right = stripImports(right);
00129                 
00130                 if (!isAllJimpleTemp(lhs))
00131                 {
00132                     replaceOccurence(lhs, tempTable);
00133                     left = fixScrewedUpThis(flattenToString(lhs));
00134                     asgInIf.put(left, right);
00135                     assignedVar.put(left, right);  // Probably we need this... in case JJJC is naughty
00136 /*                  if (stmts[i] instanceof AssignStmt)
00137                     {
00138                         AssignStmt astmt = (AssignStmt) stmts[i];
00139                         Type ltype = astmt.getLeftOp().getType();
00140                         Type rtype = astmt.getRightOp().getType();
00141                         if (ltype.equals(rtype)) {
00142                             lastAssignment = left + " = " + right;
00143                             lastType = ltype;
00144                         } else {
00145                             if (ltype instanceof BooleanType &&
00146                                 (rtype instanceof IntType || rtype instanceof LongType ||
00147                                  rtype instanceof ShortType || rtype instanceof ByteType))
00148                             {
00149                                 lastAssignment = left + " = (" + right + " != 0)";
00150                                 lastType = ltype;
00151                             } else if (rtype instanceof BooleanType &&
00152                                 (ltype instanceof IntType || ltype instanceof LongType ||
00153                                  ltype instanceof ShortType || ltype instanceof ByteType))
00154                             {
00155                             }
00156                         }
00157                     }
00158 */
00159                     //result.add(left + " = " + right + ";");
00160 
00161                 } else
00162                 {
00163                     tempTable.put(left, right);
00164                 }
00165             } else
00166             {
00167                 if (!(stmts[i] instanceof GotoStmt))
00168                 System.out.println("Error in processing condition in method "+DecompilerInfo.getMethodName());
00169             }
00170         }
00171     }
00172     if (result.size()==0)
00173     {
00174         // Slicer might have messed around us. Beware!
00175 /*      if (!asgInIf.isEmpty() && lastAssignment != null)
00176         {
00177             return "("+lastAssignment+")";
00178         }
00179 */
00180         return "(true)";
00181     }
00182     if (result.size()>1)
00183     {
00184         StringBuffer buf = new StringBuffer();
00185         buf.append("(");
00186         max = result.size();
00187 
00188         for (int i=0; i<max; i++)
00189         {
00190             buf.append((String) result.get(i));
00191             if (i<(max-1)) buf.append(" && ");
00192         }
00193         buf.append(")");
00194         return (buf.toString());
00195     }
00196     return flattenToString(result);
00197 }
00198 public static Vector dumpStmt(Stmt[] s)
00199 {
00200     if ((s == null) || !isDebugInfo()) return new Vector();
00201     int max = s.length;
00202     Vector result = new Vector();
00203 
00204     result.add("");
00205     result.add("/*");
00206     result.add("   Jimple trace:");
00207 
00208     for (int i=0; i<max; i++)
00209     {
00210         if (s[i] instanceof JIfStmt)
00211         {
00212             String x = DecompilerGotoMapper.mapStmt(((JIfStmt) s[i]).getTarget());
00213             result.add("   "+s[i].toString()+x);
00214         } else
00215         result.add("   "+s[i].toString());
00216     }
00217     result.add("*/");
00218     return result;
00219 }
00220 private static String extractCondition(Vector x)
00221 {   Vector temp = (Vector) x.clone();
00222 
00223     temp.removeElementAt(0);
00224     temp.removeElementAt(temp.size() - 1);
00225     temp.removeElementAt(temp.size() - 1);
00226     temp.removeElementAt(temp.size() - 1);
00227 
00228     return flattenToString(temp).trim();
00229 }
00230 private static Vector extractLHS(Vector x)
00231 {
00232     int eqpos = getEqPos(x);
00233     Vector res = new Vector();
00234 
00235     for (int i=0; i<eqpos; i++)
00236     {
00237         res.add(x.get(i));
00238     }
00239     return res;
00240 }
00241 private static Vector extractRHS(Vector x)
00242 {
00243     int eqpos = getEqPos(x);
00244     int max = x.size();
00245     Vector res = new Vector();
00246 
00247     for (int i=eqpos+1; i<max; i++)
00248     {
00249         res.add(x.get(i));
00250     }
00251     return res;
00252 }
00253 private static String fixScrewedUpThis(String s)
00254 {
00255     int screwedUpThis = s.indexOf("this()");
00256     if (screwedUpThis>-1)
00257     {
00258         String prefix = s.substring(0,screwedUpThis);
00259         String postfix = s.substring(screwedUpThis+6);
00260         s = prefix+"this"+postfix;
00261     }
00262     return s;
00263 }
00264 /**
00265  * This method is basically flatten out all the related
00266  * statements by replacing all occurence of Jimple's temporary
00267  * variable with the real ones. This method also detects whether
00268  * we find parameter bindings and field default values.
00269 **/
00270 public static Vector flattenStmts(Stmt[] stmts)
00271 {
00272     Vector result = new Vector();
00273     if (stmts == null || stmts.length == 0) return result;
00274     String cond = "";
00275     int max = stmts.length;
00276 
00277     // Decipher the statements
00278     for (int i = 0; i < max; i++)
00279     {
00280         // We ignore Goto Statement for a while to avoid confusion.
00281         if (stmts[i] instanceof GotoStmt) continue;
00282         Vector res = DecompilerStmtSwitch.evaluate(stmts[i]);
00283         DecompilerStmtSwitch.reset();
00284 
00285         // Normal statements contains ifs?
00286         // Suspect this
00287         if ((res.size()>0) && (((String) res.get(0)).equals("if")))
00288         {
00289             replaceOccurence(res, tempTable);
00290             cond = fixScrewedUpThis(extractCondition(res));
00291 
00292             if (cond.indexOf("quantification") != -1 || cond.indexOf("choose()") != -1)
00293             {
00294                 int eq2null = cond.lastIndexOf("!= null");
00295 
00296                 if (eq2null != -1)
00297                 {
00298                     result.add("if "+cond.substring(0,eq2null)+" == null)");
00299                 } else if (cond.indexOf("choose()") != -1)
00300                 {
00301                     // Avoid garbages
00302                     result.add("if (Bandera.choose())");
00303                 } else
00304                 {
00305                     System.out.println("Warning: Can't handle condition '"+cond+"'");
00306                 }
00307                 cond = "";
00308             }
00309         } else
00310         if (isAssignment(res))
00311         {
00312             Vector lhs = extractLHS(res);
00313             Vector rhs = extractRHS(res);
00314             replaceOccurence(rhs, tempTable);
00315             String right = flattenToString(rhs);
00316             String left = flattenToString(lhs);
00317 
00318             if (right.equals("@this")) right="this";
00319             // Detect whether it is the result of SLABS or not
00320 
00321             right = stripImports(right);
00322 
00323             // Or not an exception.
00324             if (!right.equals("@caughtexception"))
00325             {
00326                 if (!isAllJimpleTemp(lhs) && left.indexOf("qtvar") == -1)
00327                 {
00328                     replaceOccurence(lhs, tempTable);
00329                     left = flattenToString(lhs);
00330 
00331                     // Is the current method is an initializer and left hand side is a field?
00332                     if ((DecompilerInfo.isInitializer()) && (DecompilerInfo.isField(left)) &&
00333                         (DecompilerInfo.getNoOfParam()==0) && (isAllowField()))
00334                     {
00335                         DecompilerInfo.setFieldDefaultValue(left, right);
00336                     } else
00337                     {
00338                         left = fixScrewedUpThis(left);
00339                         right = fixScrewedUpThis(right);
00340 
00341                         // Nasty trick hehehehe..... ;-P
00342                         String isDef = (String) assignedVar.get(left);
00343                         if (isDef != null)
00344                         {
00345                             if (cond.length()>0)
00346                             {
00347                                 right = cond + " ? " + right + " : " + isDef;
00348                                 cond = "";
00349                             }
00350                         }
00351                         
00352                         assignedVar.put(left,right);
00353                         result.add(left + " = " + right + ";");
00354                     }
00355                 } else
00356                 {
00357                     // Nasty trick hehehehe..... ;-P again....
00358                     String isDef = (String) tempTable.get(left);
00359                     if (isDef != null)
00360                     {
00361                         if (cond.length()>0)
00362                         {
00363                             right = cond + " ? " + right + " : " + isDef;
00364                             cond = "";
00365                         }
00366                     }
00367                     tempTable.put(left, right);
00368                 }
00369             }
00370         } else
00371         {
00372             String firstToken = "", secondToken = "";
00373 
00374             if (res.size()>2)
00375             {
00376                 firstToken = (String) res.get(0);
00377                 secondToken = (String) res.get(1);
00378             }
00379 
00380             // To detect new MyClass();
00381             if (secondToken.equals("("))
00382             {
00383                 if (isJimpleID(firstToken))
00384                 {
00385                     res.removeElementAt(0);
00386                     replaceOccurence(res,tempTable);
00387                     secondToken = ((String) tempTable.get(firstToken))+flattenToString(res);
00388                     tempTable.put(firstToken,secondToken);
00389                 } else
00390                 {
00391                     String workAround = (String) assignedVar.get(firstToken);
00392                     if (workAround!=null)
00393                     {
00394                         res.removeElementAt(0);
00395                         replaceOccurence(res,tempTable);
00396                         secondToken = workAround+flattenToString(res);
00397                         assignedVar.put(firstToken,secondToken);
00398                     }
00399                 }
00400             } else
00401             {
00402                 replaceOccurence(res, tempTable);
00403                 String s = stripImports(flattenToString(res));
00404                 s = fixScrewedUpThis(s);
00405 
00406                 // Quick and dirty patch. Heh heh... ;-P
00407                 if ((!s.equals("this()")) && (s.length()>0))
00408                 {
00409                     if (DecompilerInfo.getMethodRetType().equals("boolean"))
00410                     {
00411                         if (s.equals("return 1")) s = "return true"; else
00412                         if (s.equals("return 0")) s = "return false"; else
00413                         if (s.startsWith("return") && s.endsWith("? 1 : 0"))
00414                         {
00415                             s = s.substring(0,s.length()-8).trim();
00416                         }
00417                     }
00418                     int bizzareBugPos = s.indexOf("? 1 : 0");
00419                     if (bizzareBugPos != -1 && s.indexOf("quantification") == -1)
00420                     {
00421                         s = s.substring(0,bizzareBugPos)+s.substring(bizzareBugPos+7);
00422                     }
00423                     result.add(s + ";");
00424                 }
00425             }
00426         }
00427     }
00428     return result;
00429 }
00430 public static String flattenToString(Vector x)
00431 {
00432     if (x == null) return "";
00433     StringBuffer buf = new StringBuffer();
00434     int max = x.size();
00435 
00436     for (int i=0; i<max; i++)
00437     {
00438         buf.append((String) x.get(i));
00439     }
00440     return buf.toString().trim();
00441 }
00442 public static Hashtable getAssignedVarTable()
00443 {
00444 //  Hashtable temp = assignedVar;
00445 //  assignedVar = new Hashtable();
00446     return assignedVar;
00447 }
00448 private static int getEqPos(Vector x)
00449 {
00450     if (x.contains("=")) return x.indexOf("=");
00451     if (x.contains(":=")) return x.indexOf(":=");
00452     return -1;
00453 }
00454 private static int getJimpleVarID(String str)
00455 {
00456     return Integer.parseInt(str.substring(9));
00457 }
00458 private static int getParamID(String x)
00459 {
00460     return Integer.parseInt(x.substring(10));
00461 }
00462 public static Hashtable getTempTable() { return tempTable; }
00463 private static int howManyIfs(Stmt[] stmts)
00464 {
00465     int result = 0;
00466     int max = stmts.length;
00467 
00468     for (int i = 0; i<max; i++)
00469     {
00470         if (stmts[i] instanceof IfStmt) result++;
00471     }
00472 
00473     return result;
00474 }
00475 /**
00476  * 
00477  * @return boolean
00478  */
00479 public static boolean isAbstracted(Abstraction lt) {
00480     return (((lt instanceof IntegralAbstraction) && !(lt instanceof ConcreteIntegralAbstraction)) ||
00481         ((lt instanceof RealAbstraction) && !(lt instanceof ConcreteRealAbstraction)));
00482 }
00483 private static boolean isAllJimpleTemp(Vector x)
00484 {
00485     int max = x.size();
00486 
00487     for (int i = 0; i<max; i++)
00488     {
00489         String s = ((String) x.get(i)).trim();
00490         if ((s.length()>0) && (!isJimpleID(s))) return false;
00491     }
00492     return true;
00493 }
00494 /**
00495  * 
00496  * @return boolean
00497  */
00498 public static boolean isAllowField() {
00499     return allowField;
00500 }
00501 private static boolean isAssignment(Vector x)
00502 {
00503     return x.contains("=") || x.contains(":=");
00504 }
00505 /**
00506  * 
00507  * @return boolean
00508  */
00509 public static boolean isDebugInfo() {
00510     return debugInfo;
00511 }
00512 public static boolean isEmptyAnnotation(Annotation a)
00513 {
00514     if (a==null) return true;
00515     Stmt[] stmts = a.getStatements();
00516 
00517     if (stmts.length>1) return false;
00518     if (stmts.length==0) return true;
00519     if (stmts[0] instanceof NopStmt) return true;
00520     
00521     return false;
00522 }
00523 public static boolean isJimpleID(String id)
00524 {
00525     return ((id.startsWith("JJJCTEMP$")) || (id.startsWith("$ret")) || (id.startsWith("SLABS$")));
00526 }
00527 private static void replaceOccurence(Vector x, Hashtable table)
00528 {
00529     if (table==null) return;
00530     int max = x.size();
00531 
00532     for(int i=0; i<max; i++)
00533     {
00534         String id = (String) x.get(i);
00535         if (isJimpleID(id) || id.indexOf("qtvar") != -1)
00536         {
00537             if (table.containsKey(id))
00538             {
00539                 // replace the token with the entry on the table
00540                 String tok = (String) table.get(id);
00541 
00542                 // Do another nasty trick ;=)
00543                 // to prevent new Blah.foo() being wrongly interpreted
00544                 if ((tok.startsWith("new ")) && (i<(max-1)))
00545                 {
00546                     String nextTok = (String) x.get(i+1);
00547                     if (nextTok.equals(".")) tok = "(" + tok + ")";
00548                 }
00549                 x.set(i,tok);
00550             } else
00551             {
00552                 // Nasty hack ;-P
00553                 if (id.equals("JJJCTEMP$0"))
00554                 {
00555                     x.set(i, "this");
00556                 } else
00557                 System.out.println("Slabs error: Can't find temp variable "+id+" in method "+DecompilerInfo.getMethodName());
00558             }
00559         }
00560     }
00561 }
00562 public static void resetAssignedVar()
00563 {
00564     assignedVar = new Hashtable();
00565 }
00566 public static void resetTempTable()
00567 {
00568     tempTable = new Hashtable();
00569 }
00570 /**
00571  * 
00572  * @param newAllowField boolean
00573  */
00574 public static void setAllowField(boolean newAllowField) {
00575     allowField = newAllowField;
00576 }
00577 /**
00578  * 
00579  * @param newDebugInfo boolean
00580  */
00581 public static void setDebugInfo(boolean newDebugInfo) {
00582     debugInfo = newDebugInfo;
00583 }
00584 public static int stmtIndex(Stmt s, Stmt[] stmts)
00585 {
00586     int max = stmts.length;
00587     
00588     for (int i=0; i<max; i++)
00589     {
00590         if (stmts[i]==s) return i;
00591     }
00592     return -1;
00593 }
00594 public static String stripImports(String s)
00595 {
00596     if (s.startsWith("edu.ksu.cis.bandera.slabs.lib."))
00597     {
00598         s = s.substring("edu.ksu.cis.bandera.slabs.lib.".length());
00599         Decompiler.addImports("edu.ksu.cis.bandera.slabs.lib.*");
00600     } else
00601     {
00602         // Later... 
00603     }
00604     return s;
00605 }
00606 }

Generated at Thu Feb 7 06:43:30 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001