Home | History | Annotate | Download | only in file
      1 /*
      2  * Copyright (C) 2007 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 com.android.dx.dex.file;
     18 
     19 import com.android.dx.dex.code.DalvCode;
     20 import com.android.dx.dex.code.DalvInsnList;
     21 import com.android.dx.dex.code.LocalList;
     22 import com.android.dx.dex.code.PositionList;
     23 import com.android.dx.rop.cst.CstMethodRef;
     24 import com.android.dx.util.AnnotatedOutput;
     25 import com.android.dx.util.ExceptionWithContext;
     26 
     27 import java.io.PrintWriter;
     28 
     29 public class DebugInfoItem extends OffsettedItem {
     30     /** the required alignment for instances of this class */
     31     private static final int ALIGNMENT = 1;
     32 
     33     private static final boolean ENABLE_ENCODER_SELF_CHECK = false;
     34 
     35     /** {@code non-null;} the code this item represents */
     36     private final DalvCode code;
     37 
     38     private byte[] encoded;
     39 
     40     private final boolean isStatic;
     41     private final CstMethodRef ref;
     42 
     43     public DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref) {
     44         // We don't know the write size yet.
     45         super (ALIGNMENT, -1);
     46 
     47         if (code == null) {
     48             throw new NullPointerException("code == null");
     49         }
     50 
     51         this.code = code;
     52         this.isStatic = isStatic;
     53         this.ref = ref;
     54     }
     55 
     56     /** {@inheritDoc} */
     57     @Override
     58     public ItemType itemType() {
     59         return ItemType.TYPE_DEBUG_INFO_ITEM;
     60     }
     61 
     62     /** {@inheritDoc} */
     63     @Override
     64     public void addContents(DexFile file) {
     65         // No contents to add.
     66     }
     67 
     68     /** {@inheritDoc} */
     69     @Override
     70     protected void place0(Section addedTo, int offset) {
     71         // Encode the data and note the size.
     72 
     73         try {
     74             encoded = encode(addedTo.getFile(), null, null, null, false);
     75             setWriteSize(encoded.length);
     76         } catch (RuntimeException ex) {
     77             throw ExceptionWithContext.withContext(ex,
     78                     "...while placing debug info for " + ref.toHuman());
     79         }
     80     }
     81 
     82     /** {@inheritDoc} */
     83     @Override
     84     public String toHuman() {
     85         throw new RuntimeException("unsupported");
     86     }
     87 
     88     /**
     89      * Writes annotations for the elements of this list, as
     90      * zero-length. This is meant to be used for dumping this instance
     91      * directly after a code dump (with the real local list actually
     92      * existing elsewhere in the output).
     93      *
     94      * @param file {@code non-null;} the file to use for referencing other sections
     95      * @param out {@code non-null;} where to annotate to
     96      * @param prefix {@code null-ok;} prefix to attach to each line of output
     97      */
     98     public void annotateTo(DexFile file, AnnotatedOutput out, String prefix) {
     99         encode(file, prefix, null, out, false);
    100     }
    101 
    102     /**
    103      * Does a human-friendly dump of this instance.
    104      *
    105      * @param out {@code non-null;} where to dump
    106      * @param prefix {@code non-null;} prefix to attach to each line of output
    107      */
    108     public void debugPrint(PrintWriter out, String prefix) {
    109         encode(null, prefix, out, null, false);
    110     }
    111 
    112     /** {@inheritDoc} */
    113     @Override
    114     protected void writeTo0(DexFile file, AnnotatedOutput out) {
    115         if (out.annotates()) {
    116             /*
    117              * Re-run the encoder to generate the annotations,
    118              * but write the bits from the original encode
    119              */
    120 
    121             out.annotate(offsetString() + " debug info");
    122             encode(file, null, null, out, true);
    123         }
    124 
    125         out.write(encoded);
    126     }
    127 
    128     /**
    129      * Performs debug info encoding.
    130      *
    131      * @param file {@code null-ok;} file to refer to during encoding
    132      * @param prefix {@code null-ok;} prefix to attach to each line of output
    133      * @param debugPrint {@code null-ok;} if specified, an alternate output for
    134      * annotations
    135      * @param out {@code null-ok;} if specified, where annotations should go
    136      * @param consume whether to claim to have consumed output for
    137      * {@code out}
    138      * @return {@code non-null;} the encoded array
    139      */
    140     private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint,
    141             AnnotatedOutput out, boolean consume) {
    142         byte[] result = encode0(file, prefix, debugPrint, out, consume);
    143 
    144         if (ENABLE_ENCODER_SELF_CHECK && (file != null)) {
    145             try {
    146                 DebugInfoDecoder.validateEncode(result, file, ref, code,
    147                         isStatic);
    148             } catch (RuntimeException ex) {
    149                 // Reconvert, annotating to System.err.
    150                 encode0(file, "", new PrintWriter(System.err, true), null,
    151                         false);
    152                 throw ex;
    153             }
    154         }
    155 
    156         return result;
    157     }
    158 
    159     /**
    160      * Helper for {@link #encode} to do most of the work.
    161      *
    162      * @param file {@code null-ok;} file to refer to during encoding
    163      * @param prefix {@code null-ok;} prefix to attach to each line of output
    164      * @param debugPrint {@code null-ok;} if specified, an alternate output for
    165      * annotations
    166      * @param out {@code null-ok;} if specified, where annotations should go
    167      * @param consume whether to claim to have consumed output for
    168      * {@code out}
    169      * @return {@code non-null;} the encoded array
    170      */
    171     private byte[] encode0(DexFile file, String prefix, PrintWriter debugPrint,
    172             AnnotatedOutput out, boolean consume) {
    173         PositionList positions = code.getPositions();
    174         LocalList locals = code.getLocals();
    175         DalvInsnList insns = code.getInsns();
    176         int codeSize = insns.codeSize();
    177         int regSize = insns.getRegistersSize();
    178 
    179         DebugInfoEncoder encoder =
    180             new DebugInfoEncoder(positions, locals,
    181                     file, codeSize, regSize, isStatic, ref);
    182 
    183         byte[] result;
    184 
    185         if ((debugPrint == null) && (out == null)) {
    186             result = encoder.convert();
    187         } else {
    188             result = encoder.convertAndAnnotate(prefix, debugPrint, out,
    189                     consume);
    190         }
    191 
    192         return result;
    193     }
    194 }
    195