1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.dex.file;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.DalvCode;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.DalvInsnList;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.LocalList;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.PositionList;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstMethodRef;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.AnnotatedOutput;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.ExceptionWithContext;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.PrintWriter;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic class DebugInfoItem extends OffsettedItem {
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** the required alignment for instances of this class */
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final int ALIGNMENT = 1;
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static final boolean ENABLE_ENCODER_SELF_CHECK = false;
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} the code this item represents */
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final DalvCode code;
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private byte[] encoded;
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final boolean isStatic;
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final CstMethodRef ref;
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref) {
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // We don't know the write size yet.
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        super (ALIGNMENT, -1);
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (code == null) {
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new NullPointerException("code == null");
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.code = code;
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.isStatic = isStatic;
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.ref = ref;
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public ItemType itemType() {
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return ItemType.TYPE_DEBUG_INFO_ITEM;
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void addContents(DexFile file) {
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // No contents to add.
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected void place0(Section addedTo, int offset) {
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Encode the data and note the size.
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            encoded = encode(addedTo.getFile(), null, null, null, false);
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            setWriteSize(encoded.length);
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (RuntimeException ex) {
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw ExceptionWithContext.withContext(ex,
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    "...while placing debug info for " + ref.toHuman());
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public String toHuman() {
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        throw new RuntimeException("unsupported");
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Writes annotations for the elements of this list, as
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * zero-length. This is meant to be used for dumping this instance
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * directly after a code dump (with the real local list actually
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * existing elsewhere in the output).
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param file {@code non-null;} the file to use for referencing other sections
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code non-null;} where to annotate to
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code null-ok;} prefix to attach to each line of output
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void annotateTo(DexFile file, AnnotatedOutput out, String prefix) {
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        encode(file, prefix, null, out, false);
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Does a human-friendly dump of this instance.
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code non-null;} where to dump
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code non-null;} prefix to attach to each line of output
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void debugPrint(PrintWriter out, String prefix) {
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        encode(null, prefix, out, null, false);
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@inheritDoc} */
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    @Override
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    protected void writeTo0(DexFile file, AnnotatedOutput out) {
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (out.annotates()) {
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * Re-run the encoder to generate the annotations,
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * but write the bits from the original encode
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            out.annotate(offsetString() + " debug info");
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            encode(file, null, null, out, true);
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        out.write(encoded);
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Performs debug info encoding.
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param file {@code null-ok;} file to refer to during encoding
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code null-ok;} prefix to attach to each line of output
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param debugPrint {@code null-ok;} if specified, an alternate output for
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * annotations
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code null-ok;} if specified, where annotations should go
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param consume whether to claim to have consumed output for
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code out}
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the encoded array
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint,
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            AnnotatedOutput out, boolean consume) {
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        byte[] result = encode0(file, prefix, debugPrint, out, consume);
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (ENABLE_ENCODER_SELF_CHECK && (file != null)) {
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            try {
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                DebugInfoDecoder.validateEncode(result, file, ref, code,
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        isStatic);
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } catch (RuntimeException ex) {
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // Reconvert, annotating to System.err.
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                encode0(file, "", new PrintWriter(System.err, true), null,
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        false);
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw ex;
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #encode} to do most of the work.
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param file {@code null-ok;} file to refer to during encoding
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param prefix {@code null-ok;} prefix to attach to each line of output
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param debugPrint {@code null-ok;} if specified, an alternate output for
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * annotations
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param out {@code null-ok;} if specified, where annotations should go
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param consume whether to claim to have consumed output for
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code out}
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the encoded array
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private byte[] encode0(DexFile file, String prefix, PrintWriter debugPrint,
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            AnnotatedOutput out, boolean consume) {
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        PositionList positions = code.getPositions();
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        LocalList locals = code.getLocals();
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        DalvInsnList insns = code.getInsns();
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int codeSize = insns.codeSize();
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int regSize = insns.getRegistersSize();
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        DebugInfoEncoder encoder =
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            new DebugInfoEncoder(positions, locals,
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    file, codeSize, regSize, isStatic, ref);
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        byte[] result;
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if ((debugPrint == null) && (out == null)) {
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result = encoder.convert();
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result = encoder.convertAndAnnotate(prefix, debugPrint, out,
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    consume);
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
195