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