/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.dx.dex.file; import com.android.dx.dex.code.DalvCode; import com.android.dx.dex.code.DalvInsnList; import com.android.dx.dex.code.LocalList; import com.android.dx.dex.code.PositionList; import com.android.dx.rop.cst.CstMethodRef; import com.android.dx.rop.cst.CstType; import com.android.dx.rop.cst.CstUtf8; import com.android.dx.util.AnnotatedOutput; import com.android.dx.util.ExceptionWithContext; import java.io.PrintWriter; public class DebugInfoItem extends OffsettedItem { /** the required alignment for instances of this class */ private static final int ALIGNMENT = 1; private static final boolean ENABLE_ENCODER_SELF_CHECK = false; /** {@code non-null;} the code this item represents */ private final DalvCode code; private byte[] encoded; private final boolean isStatic; private final CstMethodRef ref; public DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref) { // We don't know the write size yet. super (ALIGNMENT, -1); if (code == null) { throw new NullPointerException("code == null"); } this.code = code; this.isStatic = isStatic; this.ref = ref; } /** {@inheritDoc} */ @Override public ItemType itemType() { return ItemType.TYPE_DEBUG_INFO_ITEM; } /** {@inheritDoc} */ @Override public void addContents(DexFile file) { // No contents to add. } /** {@inheritDoc} */ @Override protected void place0(Section addedTo, int offset) { // Encode the data and note the size. try { encoded = encode(addedTo.getFile(), null, null, null, false); setWriteSize(encoded.length); } catch (RuntimeException ex) { throw ExceptionWithContext.withContext(ex, "...while placing debug info for " + ref.toHuman()); } } /** {@inheritDoc} */ @Override public String toHuman() { throw new RuntimeException("unsupported"); } /** * Writes annotations for the elements of this list, as * zero-length. This is meant to be used for dumping this instance * directly after a code dump (with the real local list actually * existing elsewhere in the output). * * @param file {@code non-null;} the file to use for referencing other sections * @param out {@code non-null;} where to annotate to * @param prefix {@code null-ok;} prefix to attach to each line of output */ public void annotateTo(DexFile file, AnnotatedOutput out, String prefix) { encode(file, prefix, null, out, false); } /** * Does a human-friendly dump of this instance. * * @param out {@code non-null;} where to dump * @param prefix {@code non-null;} prefix to attach to each line of output */ public void debugPrint(PrintWriter out, String prefix) { encode(null, prefix, out, null, false); } /** {@inheritDoc} */ @Override protected void writeTo0(DexFile file, AnnotatedOutput out) { if (out.annotates()) { /* * Re-run the encoder to generate the annotations, * but write the bits from the original encode */ out.annotate(offsetString() + " debug info"); encode(file, null, null, out, true); } out.write(encoded); } /** * Performs debug info encoding. * * @param file {@code null-ok;} file to refer to during encoding * @param prefix {@code null-ok;} prefix to attach to each line of output * @param debugPrint {@code null-ok;} if specified, an alternate output for * annotations * @param out {@code null-ok;} if specified, where annotations should go * @param consume whether to claim to have consumed output for * {@code out} * @return {@code non-null;} the encoded array */ private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint, AnnotatedOutput out, boolean consume) { byte[] result = encode0(file, prefix, debugPrint, out, consume); if (ENABLE_ENCODER_SELF_CHECK && (file != null)) { try { DebugInfoDecoder.validateEncode(result, file, ref, code, isStatic); } catch (RuntimeException ex) { // Reconvert, annotating to System.err. encode0(file, "", new PrintWriter(System.err, true), null, false); throw ex; } } return result; } /** * Helper for {@link #encode} to do most of the work. * * @param file {@code null-ok;} file to refer to during encoding * @param prefix {@code null-ok;} prefix to attach to each line of output * @param debugPrint {@code null-ok;} if specified, an alternate output for * annotations * @param out {@code null-ok;} if specified, where annotations should go * @param consume whether to claim to have consumed output for * {@code out} * @return {@code non-null;} the encoded array */ private byte[] encode0(DexFile file, String prefix, PrintWriter debugPrint, AnnotatedOutput out, boolean consume) { PositionList positions = code.getPositions(); LocalList locals = code.getLocals(); DalvInsnList insns = code.getInsns(); int codeSize = insns.codeSize(); int regSize = insns.getRegistersSize(); DebugInfoEncoder encoder = new DebugInfoEncoder(positions, locals, file, codeSize, regSize, isStatic, ref); byte[] result; if ((debugPrint == null) && (out == null)) { result = encoder.convert(); } else { result = encoder.convertAndAnnotate(prefix, debugPrint, out, consume); } return result; } }