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