From c639d229c699c20bd5bf5b10527b74b3248911d9 Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Wed, 7 Aug 2019 11:33:37 -0700 Subject: [PATCH] Add support for the new debug offset table for cdex files --- .../dexlib2/dexbacked/CDexBackedDexFile.java | 12 ++ .../CDexBackedMethodImplementation.java | 28 ++++- .../dexbacked/raw/CdexDebugOffsetTable.java | 111 ++++++++++++++++++ .../dexlib2/dexbacked/raw/CdexHeaderItem.java | 16 +++ .../jf/dexlib2/dexbacked/raw/HeaderItem.java | 5 + .../dexbacked/raw/util/DexAnnotator.java | 7 ++ 6 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CdexDebugOffsetTable.java diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/CDexBackedDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/CDexBackedDexFile.java index 15df46bc..956d64c0 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/CDexBackedDexFile.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/CDexBackedDexFile.java @@ -90,6 +90,18 @@ public class CDexBackedDexFile extends DexBackedDexFile { return getBuffer().readSmallUint(HeaderItem.DATA_START_OFFSET); } + public int getDebugInfoOffsetsPos() { + return getBuffer().readSmallUint(CdexHeaderItem.DEBUG_INFO_OFFSETS_POS_OFFSET); + } + + public int getDebugInfoOffsetsTableOffset() { + return getBuffer().readSmallUint(CdexHeaderItem.DEBUG_INFO_OFFSETS_TABLE_OFFSET); + } + + public int getDebugInfoBase() { + return getBuffer().readSmallUint(CdexHeaderItem.DEBUG_INFO_BASE); + } + @Override protected DexBackedMethodImplementation createMethodImplementation( @Nonnull DexBackedDexFile dexFile, @Nonnull DexBackedMethod method, int codeOffset) { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/CDexBackedMethodImplementation.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/CDexBackedMethodImplementation.java index 85378bde..62d529eb 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/CDexBackedMethodImplementation.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/CDexBackedMethodImplementation.java @@ -113,7 +113,31 @@ public class CDexBackedMethodImplementation extends DexBackedMethodImplementatio @Override protected int getDebugOffset() { - // TODO: figure out the new debug stuff in cdex - return 0; + CDexBackedDexFile cdexFile = ((CDexBackedDexFile) dexFile); + + int debugTableItemOffset = (method.methodIndex / 16) * 4; + int bitIndex = method.methodIndex % 16; + + int debugInfoOffsetsPos = cdexFile.getDebugInfoOffsetsPos(); + int debugTableOffset = debugInfoOffsetsPos + cdexFile.getDebugInfoOffsetsTableOffset(); + + int debugOffsetsOffset = cdexFile.getDataBuffer().readSmallUint(debugTableOffset + debugTableItemOffset); + + DexReader reader = cdexFile.getDataBuffer().readerAt(debugInfoOffsetsPos + debugOffsetsOffset); + + int bitMask = reader.readUbyte() << 8; + bitMask += reader.readUbyte(); + + if ((bitMask & (1 << bitIndex)) == 0) { + return 0; + } + + int offsetCount = Integer.bitCount(bitMask & 0xFFFF >> (16-bitIndex)); + int baseDebugOffset = cdexFile.getDebugInfoBase(); + for (int i=0; i> i) & 1); + } + annotator.annotate(2, "bitmask: 0b%s", sb.reverse()); + + int debugOffset = ((CDexBackedDexFile) annotator.dexFile).getDebugInfoBase(); + for (int i=0; i<16; i++) { + if ((bitmask & 1) != 0) { + int offsetDelta = reader.readBigUleb128(); + + debugOffset += offsetDelta; + + annotator.annotateTo(reader.getOffset(), "[method_id: %d]: offset_delta: %d (offset=0x%x)", + methodIndex + i, + offsetDelta, debugOffset); + + debugInfoAnnotator.setItemIdentity(debugOffset, + annotator.dexFile.getMethodSection().get(methodIndex + i).toString()); + } + + bitmask >>= 1; + } + + annotator.deindent(); + } + + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CdexHeaderItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CdexHeaderItem.java index 6e7c1d61..e8d566eb 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CdexHeaderItem.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CdexHeaderItem.java @@ -31,11 +31,20 @@ package org.jf.dexlib2.dexbacked.raw; +import org.jf.dexlib2.dexbacked.DexBuffer; +import org.jf.dexlib2.util.AnnotatedBytes; + +import javax.annotation.Nonnull; + public class CdexHeaderItem { private static final byte[] MAGIC_VALUE = new byte[] { 0x63, 0x64, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00 }; private static final int[] SUPPORTED_CDEX_VERSIONS = new int[] { 1 }; + public static final int FEATURE_FLAGS_OFFSET = 112; + public static final int DEBUG_INFO_OFFSETS_POS_OFFSET = 116; + public static final int DEBUG_INFO_OFFSETS_TABLE_OFFSET = 120; + public static final int DEBUG_INFO_BASE = 124; /** * Verifies the magic value at the beginning of a cdex file @@ -98,4 +107,11 @@ public class CdexHeaderItem { } return false; } + + public static void annotateCdexHeaderFields(@Nonnull AnnotatedBytes out, DexBuffer buf) { + out.annotate(4, "feature_flags: 0x%x", buf.readInt(out.getCursor())); + out.annotate(4, "debug_info_offsets_pos: 0x%x", buf.readInt(out.getCursor())); + out.annotate(4, "debug_info_offsets_table_offset: 0x%x", buf.readInt(out.getCursor())); + out.annotate(4, "debug_info_base: 0x%x", buf.readInt(out.getCursor())); + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HeaderItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HeaderItem.java index 06b058be..99150618 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HeaderItem.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/HeaderItem.java @@ -32,6 +32,7 @@ package org.jf.dexlib2.dexbacked.raw; import org.jf.dexlib2.VersionMap; +import org.jf.dexlib2.dexbacked.CDexBackedDexFile; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.dexbacked.DexBuffer; import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator; @@ -211,6 +212,10 @@ public class HeaderItem { out.annotate(4, "data_size: %d", dexFile.getBuffer().readInt(out.getCursor())); out.annotate(4, "data_off: 0x%x", dexFile.getBuffer().readInt(out.getCursor())); + if (annotator.dexFile instanceof CDexBackedDexFile) { + CdexHeaderItem.annotateCdexHeaderFields(out, dexFile.getBuffer()); + } + if (headerSize > ITEM_SIZE) { out.annotateTo(headerSize, "header padding"); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java index 3b3195d2..0f570cb4 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/util/DexAnnotator.java @@ -34,6 +34,7 @@ package org.jf.dexlib2.dexbacked.raw.util; import com.google.common.collect.Maps; import com.google.common.collect.Ordering; import com.google.common.primitives.Ints; +import org.jf.dexlib2.dexbacked.CDexBackedDexFile; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.dexbacked.raw.*; import org.jf.dexlib2.util.AnnotatedBytes; @@ -170,6 +171,12 @@ public class DexAnnotator extends AnnotatedBytes { mapItems = ordering.immutableSortedCopy(mapItems); try { + // Need to annotate the debug info offset table first, to propagate the debug info identities + if (dexFile instanceof CDexBackedDexFile) { + moveTo(dexFile.getBaseDataOffset() + ((CDexBackedDexFile) dexFile).getDebugInfoOffsetsPos()); + CdexDebugOffsetTable.annotate(this, dexFile.getBuffer()); + } + for (MapItem mapItem: mapItems) { try { SectionAnnotator annotator = annotators.get(mapItem.getType());