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