Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: jreversepro/revengine/JBranchTable.java


1   /**
2     * @(#)JBranchTable.java
3     * JReversePro - Java Decompiler / Disassembler.
4     * Copyright (C) 2000 2001 Karthik Kumar.
5     * EMail: akkumar@users.sourceforge.net
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it , under the terms of the GNU General Public License as published
9     * by the Free Software Foundation; either version 2 of the License,
10    * or (at your option) any later version.
11    *
12    * This program is distributed in the hope that it will be useful,
13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15    * See the GNU General Public License for more details.
16    * You should have received a copy of the GNU General Public License
17    * along with this program.If not, write to
18    *  The Free Software Foundation, Inc.,
19    *  59 Temple Place - Suite 330,
20    *  Boston, MA 02111-1307, USA.
21    **/
22  
23  package jreversepro.revengine;
24  
25  
26  import jreversepro.reflect.JInstruction;
27  import jreversepro.reflect.JException;
28  import jreversepro.reflect.JMethod;
29  
30  import jreversepro.common.Helper;
31  //import jreversepro.common.KeyWords;
32  import jreversepro.common.JJvmOpcodes;
33  
34  import java.util.Vector;
35  import java.util.Map;
36  import java.util.HashMap;
37  import java.util.List;
38  import java.util.Collections;
39  import java.util.Iterator;
40  
41  /**
42   * JBranchTable manages the objects of JGotoEntry and JBranchEntry.
43   *
44   * @author Karthik Kumar
45   **/
46  public class JBranchTable implements BranchConstants, JJvmOpcodes {
47  
48      /**
49       * Branches is a list, with the individual elemens containing
50       * 'JBranchEntry'.
51       **/
52      List branches;
53  
54      /**
55       * gotos 
56       * Key - StartPc ( java.lang.Integer ) 
57       * Value - TargetPc ( Absolute target -java.lang.Integer).
58       **/
59      Map gotos;
60  
61      /**
62       * List of switch instructions. Individual members are 
63       * JInstruction.
64       **/
65      List switches; 
66  
67      /**
68       * It is a Vector of 'Integer's. 
69       * The integers are the target of the jump sub routine instruction.
70       **/
71      Vector mJSRTarget;
72  
73      /**
74       * Map of monitor instructions.
75       **/
76      Map mMonitor;
77  
78      /** Method reference **/
79      JMethod method;
80      
81      /**
82       * @param method Method reference.
83       **/
84      public JBranchTable(JMethod method) {
85          mJSRTarget = new Vector();
86          mMonitor =  new HashMap();
87          branches =  new Vector();
88          switches  = new Vector();
89          gotos = new HashMap();
90          this.method = method;
91      }
92  
93      /**
94       * Setter method for the branch tables.
95       * @param aBranches Branches to be added.
96       **/
97      public void setTables(List aBranches) {
98          branches.addAll(aBranches);
99      }
100 
101     /**
102      * Getter method for goto tables.
103      * @return Map of goto table entries.
104      * key - goto pc. 
105      * value - target of that goto table.
106      **/
107     public Map getGotoTable() {
108         return gotos;
109     }
110 
111     /**
112      * Adds a Goto entry to the internal data structure.
113      * @param startPc StartPc of the goto statement.
114      * @param targetPc TargetPc of the goto statement.
115      **/
116     public void addGotoEntry(int startPc, int targetPc) {
117         gotos.put(new Integer(startPc),
118                         new Integer(targetPc));
119     }
120 
121     /**
122      * Finalizer method.
123      **/
124     protected void finalize() {
125         branches  = null;
126         gotos  = null;
127     }
128 
129     /**
130      * Adds a new branch entry to the list of branches.
131      * @param ent  branch entry to be added.
132      **/
133     public void add(JBranchEntry ent) {
134         branches.add(ent);
135     }
136 
137     /**
138      * Checks if the Pc passed as argument is the target for 
139      * any JSR instructions.
140      * @param currPc Pc for which it is to be checked if it is the 
141      * target for any JSR instruction.
142      * @return true, if there exists a JSR instruction with its target
143      * currPc. false, otherwise.
144      **/ 
145     public boolean isJSRTarget(int currPc) {
146         return mJSRTarget.contains(new Integer(currPc));
147     }
148 
149     /**
150      * This adds the pc given as input as a JSR target.
151      * @param targetPc TargetPc for a JSR instruction that is to be 
152      * added to the internal data structure ( list ).
153      **/
154     public void addJSRPc(int targetPc) {
155         Integer intPc = new Integer(targetPc);
156         if (!mJSRTarget.contains(intPc)) {
157             mJSRTarget.add (intPc);
158         }
159     }
160 
161     /**
162      * When a RET instruction is encountered we add a branch with the 
163      * last element of the JSR target lists.
164      * JSR instructions signify 'synchronized' and catch..all blocks.
165      * @param retPc PC of the instruction which is a RET.
166      **/
167     public void addRetPc(int retPc) {
168         Object obj = mJSRTarget.lastElement();
169         int startPc = ((Integer) obj).intValue();
170         branches.add(new JBranchEntry(
171                             method, startPc,
172                             startPc, retPc,
173                             TYPE_JSR, "", "", ""));
174     }
175 
176     /**
177      * This sorts the list containing branches such that no 
178      * branch overlaps with the one previously existing.
179      * See JBranchComparator for more details.
180      **/
181     public void sort() {
182         Collections.sort(branches,  new JBranchComparator());
183     }
184 
185     /**
186      * Adds a monitor Pc. 
187      * @param aMonitorPc Pc that is monitorenter.
188      * @param aMonObject Object that is 'monitored'. In the sense
189      * object for which lock is obtained before entering a 
190      * 'synchronized' object.
191      **/
192     public void addMonitorPc(int aMonitorPc, String  aMonObject) {
193         mMonitor.put(new Integer(aMonitorPc), aMonObject) ;
194     }
195 
196     /**
197      * Returns the monitor type for the monitor that begins with 
198      * Pc.
199      * @param monitorBeginPc Pc that begins with the monitor.
200      * @return monitor object associated with this branch.
201      **/
202     public String doesMonitorBegin(int monitorBeginPc) {
203         return (String) mMonitor.get(new Integer(monitorBeginPc));
204     }
205 
206     /**
207      * Identifies the else..if and else branches.
208      * Identifies catch.. branches.
209      * @throws RevEngineException Thrown in case of any error.
210      **/
211     public void identifyMoreBranches()
212         throws RevEngineException {
213 
214         for (int i = 0 ; i < branches.size() ; i++) {
215             JBranchEntry jbe = (JBranchEntry) branches.get(i);
216             int gotoStartPc = jbe.getEndBlockPc() - 3;
217             int gotoNextPc = gotoStartPc + 3;
218             Object obj = gotos.get(new  Integer(gotoStartPc));
219             switch (jbe.getType()) {
220                 case TYPE_IF:
221                 case TYPE_ELSE_IF:
222                     if (obj != null) {
223                         //Before adding else, check for else if.
224                         int gotoTargetPc = ((Integer) obj).intValue();
225                         if (gotoTargetPc - gotoStartPc == 3) {
226                            break;
227                         }
228                         JBranchEntry elsif =
229                                     contains(startsWith(gotoNextPc),
230                                                       TYPE_IF);
231 
232                         if (elsif == null) {
233                             JBranchEntry caseEntry =
234                                 contains(startsWith(gotoNextPc),
235                                                     TYPE_CASE);
236                             if (caseEntry == null) {
237                                 JBranchEntry elseEntry =
238                                     new JBranchEntry(
239                                                 method,
240                                                 gotoNextPc,
241                                                 gotoNextPc,
242                                                 gotoTargetPc,
243                                                 TYPE_ELSE,
244                                                 jbe.opr1,
245                                                 jbe.opr2,
246                                                 jbe.operator);
247                                 branches.add(elseEntry);
248                             }
249                         } else {
250                             elsif.setType(TYPE_ELSE_IF);
251                         }
252                     }
253                     break;
254                 case TYPE_DO_WHILE:
255                     if (gotos.containsValue(new Integer(jbe.startPc))) {
256                         jbe.setType(TYPE_WHILE);
257                     }
258                     break;
259             }
260         }
261     }
262 
263     /**
264      * Adds the switch entries and the case entries under the same to the 
265      * branch table.
266      * @param switchEntry switch table containing entries about switch 
267      * statements.
268      **/
269     public void addSwitch(JSwitchTable switchEntry) {
270         int defaultByte = switchEntry.getDefaultByte();
271         int maxTarget = defaultByte;
272         List enumCases = switchEntry.getCases();
273 
274         Helper.log("No: Case Entries " + enumCases.size());
275         for (int j = 0 ; j < enumCases.size() ; j++) {
276             JCaseEntry singleCase = (JCaseEntry) enumCases.get(j);
277             int caseTarget = singleCase.getTarget();
278             int endCase =  singleCase.getEndTarget();
279 
280             List caseValues =  singleCase.getValues();
281             StringBuffer sb =  new StringBuffer();
282             for (int k = 0 ; k < caseValues.size() ; k++) {
283                 sb.append(caseValues.get(k) + ",");
284             }
285             JBranchEntry ent = new JBranchEntry(
286                                 method,
287                                 caseTarget, caseTarget, 
288                                 endCase, TYPE_CASE,
289                                 sb.toString(), "", "");
290             branches.add(ent);
291         }
292         branches.add(switchEntry.getBranchEntry());
293     }
294 
295     /**
296      * List of JException entries.
297      * @param excTryTable Individual entries being JException.
298      **/
299     public void addTryBlocks(List excTryTable) {
300         Helper.log("Number of Try..blocks " + excTryTable.size());
301         for (int i = 0 ; i < excTryTable.size(); i++) {
302             JException exc = (JException) excTryTable.get(i);
303             int insIndex = exc.getStartPc();
304             if (insIndex == -1) {
305                 continue;
306             }
307 
308             int endPc = exc.getEffectiveEndPc(method.getInstructions());
309             String syncLock = doesMonitorBegin(insIndex - 1);
310             if (syncLock != null) {
311                 branches.add (new JBranchEntry (
312                                     method,
313                                     insIndex, insIndex, endPc,
314                                     TYPE_SYNC, syncLock, "", ""));
315             } else {
316                 branches.add (new JBranchEntry (
317                                     method,
318                                     insIndex, insIndex, endPc,
319                                (exc.isAny()) ? TYPE_TRY_ANY : TYPE_TRY,
320                                      "", "", ""));
321             }
322         }
323     }
324 
325     /**
326      * For the given pc return the target of the instruction.
327      * The instruction is a goto statement.
328      * @param startPc Start Pc.
329      * @return the TargetPc for the goto instruction at the 
330      * startPc
331      **/
332     public int findGotoTarget(int startPc) {
333         Object obj = gotos.get(
334                             new Integer(startPc));
335         if (obj == null) {
336             return  -1;
337         } else {
338             return ((Integer) obj).intValue();
339         }
340     }
341 
342     /**
343      * Returns the list of branches that starts with the 
344      * mentioned aInsIndex.
345      * @param aInsIndex Instruction index.
346      * @return List of JBranchEntry -
347      * list of branches that starts with the mentioned
348      * instruction index.
349      * @throws RevEngineException thrown in case of an error.
350      **/
351     public List startsWith(int aInsIndex)
352                    throws RevEngineException {
353 
354         List branchEntries = new Vector();
355         for (int i = 0 ; i < branches.size() ; i++) {
356             JBranchEntry jbe = (JBranchEntry) branches.get(i);
357             if (jbe.doesStartWith(aInsIndex)) {
358                 branchEntries.add(jbe);
359             }
360         }
361         return branchEntries;
362     }
363 
364     /**
365      * Delete the branch that corresponds to a else ..
366      * branch starting with the given Pc
367      * @param startElse PC for which the else statement 
368      * is to be deleted.
369      **/
370     public void deleteElse(int startElse) {
371         for (int i = 0 ; i < branches.size() ; i++)  {
372             JBranchEntry jbe = (JBranchEntry) branches.get(i);
373             if (jbe.getType() == TYPE_ELSE 
374                 && jbe.getStartPc() == startElse) {
375                 branches.remove(i);
376             }
377         }
378     }
379 
380     /**
381      * Returns the first branch in the mentioned branchlist
382      * that matches the particular type.
383      * @param listBranchEntries list of branch entries.
384      * @param type Type that is to be searched for.
385      * @return first branch entry that matches the type mentioned 
386      * in the list given.
387      **/
388     public static JBranchEntry contains (List listBranchEntries,
389                                             int type) {
390         if (listBranchEntries.size() == 0) {
391             return null;
392         }
393         for (int i = 0 ; i < listBranchEntries.size(); i++) {
394             JBranchEntry ent = (JBranchEntry) listBranchEntries.get(i);
395             if (ent.getType() == type) {
396                 return ent;
397             }
398         }
399         return null;
400     }
401 
402     /**
403      * @param byteIns BytecodeInstruction List.
404      * @param start StartPc.
405      * @param end EndPc.
406      * @return Returns a JInstruction reference.
407      **/
408     public JInstruction findGotoIns(List byteIns, int start, int end) {
409         int i;
410         for (i = 0; i < byteIns.size(); i++) {
411             if (((JInstruction) byteIns.get(i)).index == start) {
412                 break;
413             }
414         }
415         JInstruction ins = (JInstruction) byteIns.get(i);
416         JInstruction curIns = ins;
417         while (curIns != null
418                 && curIns.opcode != OPCODE_GOTO
419                 && curIns.opcode != OPCODE_GOTOW) {
420             if (curIns.index == end) {
421                 curIns = null;
422                 break;
423             } else if (curIns.opcode == OPCODE_RETURN) {
424                 curIns = curIns.next();
425                 break;
426             }
427             curIns = curIns.next();
428         }
429         return curIns;
430     }
431 
432     /**
433      * Stringifies the braches alone.
434      * @return Returns a Stringifed version of the branches alone.
435      **/
436     public String branchesToString() {
437         StringBuffer sb = new StringBuffer("");
438         int size = branches.size();
439         if (size > 0) {
440             sb.append("Branches:\n");
441             for (int i = 0; i < size; i++) {
442                 sb.append((JBranchEntry) branches.get(i) + "\n");
443             }
444         }
445         return sb.toString();
446     }
447 
448     /**
449      * @return Stringified form of the class
450      **/
451     public String toString() {
452         StringBuffer sb =  new StringBuffer("");
453         sb.append(branchesToString());
454         int size = gotos.size();
455         if (size > 0) {
456             sb.append("Gotos:\n");
457             Iterator it = gotos.entrySet().iterator();
458             for (int i = 0; i < size; i++) {
459                 sb.append(it.next() + "\n");
460             }
461         }
462         size = mJSRTarget.size();
463         if (size > 0) {
464             sb.append("JSRTargets:\n");
465             for (int i = 0; i < size; i++) {
466                 sb.append(mJSRTarget.get(i) + "\n");
467             }
468         }
469         return sb.toString();
470     }
471 }