• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref)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
itemType()57     public ItemType itemType() {
58         return ItemType.TYPE_DEBUG_INFO_ITEM;
59     }
60 
61     /** {@inheritDoc} */
62     @Override
addContents(DexFile file)63     public void addContents(DexFile file) {
64         // No contents to add.
65     }
66 
67     /** {@inheritDoc} */
68     @Override
place0(Section addedTo, int offset)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
toHuman()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      */
annotateTo(DexFile file, AnnotatedOutput out, String prefix)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      */
debugPrint(PrintWriter out, String prefix)107     public void debugPrint(PrintWriter out, String prefix) {
108         encode(null, prefix, out, null, false);
109     }
110 
111     /** {@inheritDoc} */
112     @Override
writeTo0(DexFile file, AnnotatedOutput out)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      */
encode(DexFile file, String prefix, PrintWriter debugPrint, AnnotatedOutput out, boolean consume)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      */
encode0(DexFile file, String prefix, PrintWriter debugPrint, AnnotatedOutput out, boolean consume)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