| /* |
| * 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; |
| } |
| } |