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 }