1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dasm; 18 19 import com.android.dx.dex.code.CatchBuilder; 20 import com.android.dx.dex.code.CatchHandlerList; 21 import com.android.dx.dex.code.CatchTable; 22 import com.android.dx.dex.code.CodeAddress; 23 import com.android.dx.rop.cst.CstType; 24 import com.android.dx.rop.type.Type; 25 26 import dasm.DAsm.LabelTableEntry; 27 28 import java.util.Enumeration; 29 import java.util.HashSet; 30 import java.util.Hashtable; 31 import java.util.Vector; 32 33 /** 34 * Constructor of (@link CatchTable) instances from table of labels and list of 35 * catch blocks defined in method. 36 */ 37 public class DasmCatchBuilder implements CatchBuilder { 38 39 /** 40 * Represents catch block that was not processed yet. Holds "from" and "to" 41 * labels as well as list of exceptions to catch. 42 */ 43 private class UnprocessedCatch { 44 45 String from; 46 String to; 47 Hashtable<CstType, String> type_branch = 48 new Hashtable<CstType, String>(); 49 50 /** 51 * Constructs an instance. 52 * 53 * @param exception 54 * exception type 55 * @param from 56 * "from" label 57 * @param to 58 * "to" label 59 * @param branch 60 * "with" label 61 */ UnprocessedCatch(String exception, String from, String to, String branch)62 UnprocessedCatch(String exception, String from, String to, 63 String branch) { 64 this.from = from; 65 this.to = to; 66 add(exception, branch); 67 } 68 69 /** 70 * Adds new exception type and branch label to current "from-to" block 71 * to allow to have code like try { // do something } catch(Exception1 72 * e1) { } catch(Exception2 e2) { } or in Dasm: Label1: ; do something 73 * Labe2: ; .... Label3: ; .... Label4: ; .... .catch 74 * java/lang/Exception from Label1 to Label2 using Label3 .catch 75 * java/lang/Throwable from Label1 to Label2 using Label4 76 * 77 * @param exception 78 * exception type 79 * @param branch 80 * "with" label 81 */ add(String exception, String branch)82 void add(String exception, String branch) { 83 CstType type; 84 if (exception.compareToIgnoreCase("all") == 0) 85 type = CstType.OBJECT; 86 else 87 type = CstType.intern(Type.internClassName(exception)); 88 89 String s = type_branch.get(type); 90 if (s != null && s.compareToIgnoreCase(branch) != 0) 91 throw new RuntimeException( 92 "Bad .catch directive: same exception (" + exception 93 + ") but different branch addresses (" + s 94 + " and " + branch + ")"); 95 type_branch.put(type, branch); 96 } 97 } 98 99 private Vector<UnprocessedCatch> unprocessed_catches = 100 new Vector<UnprocessedCatch>(); 101 102 private Hashtable<String, LabelTableEntry> labels_table; 103 104 /** 105 * Constructs an instance. 106 * 107 * @param labels_table 108 * holds list of labels defined in method being processed 109 */ DasmCatchBuilder(Hashtable<String, LabelTableEntry> labels_table)110 public DasmCatchBuilder(Hashtable<String, LabelTableEntry> labels_table) { 111 this.labels_table = labels_table; 112 } 113 114 /** 115 * Gets the set of catch types associated with this instance. 116 */ getCatchTypes()117 public HashSet<Type> getCatchTypes() { 118 int sz = unprocessed_catches.size(); 119 HashSet<Type> result = new HashSet<Type>(sz); 120 for (int i = 0; i < sz; i++) { 121 Enumeration<CstType> keys = unprocessed_catches.elementAt(i) 122 .type_branch.keys(); 123 while (keys.hasMoreElements()) { 124 result.add(keys.nextElement().getClassType()); 125 } 126 } 127 return result; 128 } 129 130 /** 131 * Gets whether this instance has any catches at all. 132 */ hasAnyCatches()133 public boolean hasAnyCatches() { 134 return unprocessed_catches.size() != 0; 135 } 136 137 /** 138 * Adds new exception handler 139 * 140 * @param exception 141 * type of exception to catch 142 * @param start 143 * "from" label 144 * @param end 145 * "to" label 146 * @param branch 147 * "with" label 148 */ add(String exception, String start, String end, String branch)149 public void add(String exception, String start, String end, String branch) { 150 int sz = unprocessed_catches.size(); 151 for (int i = 0; i < sz; i++) { 152 UnprocessedCatch uc = unprocessed_catches.elementAt(i); 153 if (uc.from.compareToIgnoreCase(start) == 0) { 154 if (uc.to.compareToIgnoreCase(end) != 0) 155 throw new RuntimeException( 156 "Bad .catch directive: two blocks have the same " 157 + "start address (" 158 + uc.from 159 + ") and different end addresses (" + uc.to 160 + " and " + end + ")"); 161 uc.add(exception, branch); 162 return; 163 } 164 } 165 166 unprocessed_catches.add(new UnprocessedCatch(exception, start, end, 167 branch)); 168 } 169 170 /** 171 * Builds and returns the catch table for this instance. 172 */ build()173 public CatchTable build() { 174 int sz = unprocessed_catches.size(); 175 CatchTable result = new CatchTable(sz); 176 for (int i = 0; i < sz; i++) { 177 UnprocessedCatch uc = unprocessed_catches.elementAt(i); 178 LabelTableEntry lte = labels_table.get(uc.from); 179 // get "from" address 180 if (lte == null || lte.planted == false) 181 throw new RuntimeException("Label " + uc.from + " not defined"); 182 CodeAddress from = lte.code_address; 183 // get "to" address 184 lte = labels_table.get(uc.to); 185 if (lte == null || lte.planted == false) 186 throw new RuntimeException("Label " + uc.to + " not defined"); 187 CodeAddress to = lte.code_address; 188 189 // build handlers list 190 CatchHandlerList chl = new CatchHandlerList(uc.type_branch.size()); 191 Enumeration<CstType> keys = uc.type_branch.keys(); 192 int j = 0; 193 CatchHandlerList.Entry catch_all = null; 194 while (keys.hasMoreElements()) { 195 CstType type = keys.nextElement(); 196 String branch = uc.type_branch.get(type); 197 lte = labels_table.get(branch); 198 if (lte == null || lte.planted == false) 199 throw new RuntimeException("Label " + branch 200 + " not defined"); 201 CatchHandlerList.Entry chle = new CatchHandlerList.Entry(type, 202 lte.code_address.getAddress()); 203 // catch_all shall be the last handler in the list 204 if (type.equals(CstType.OBJECT)) { 205 catch_all = chle; 206 } else { 207 chl.set(j, chle); 208 j++; 209 } 210 } 211 if (catch_all != null) chl.set(j, catch_all); 212 chl.setImmutable(); 213 214 CatchTable.Entry entry = new CatchTable.Entry(from.getAddress(), to 215 .getAddress(), chl); 216 result.set(i, entry); 217 } 218 return result; 219 } 220 } 221