Home | History | Annotate | Download | only in dasm
      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          */
     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          */
     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      */
    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      */
    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      */
    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      */
    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      */
    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