Skip to content
This repository has been archived by the owner on Nov 15, 2022. It is now read-only.

Commit

Permalink
Add support invoke-custom to dexdump
Browse files Browse the repository at this point in the history
o Update bytecode.txt with codepoints for invoke-custom
  instructions and run opcode-gen/regen-all.

o Update dexdump to support invoke-custom with output equivalent to
  dexdump2.

Bug: 30550796,33191717,33231751
Test: manually tested with DEX files generated from ART run-tests.
Change-Id: If2cedea21875e93525c4850005d335901897484a
  • Loading branch information
ohodson committed Feb 15, 2017
1 parent e5a2644 commit fa5e510
Show file tree
Hide file tree
Showing 14 changed files with 421 additions and 27 deletions.
219 changes: 219 additions & 0 deletions dexdump/DexDump.cpp
Expand Up @@ -915,6 +915,9 @@ static char* indexString(DexFile* pDexFile, const DecodedInstruction* pDecInsn,
free(protoInfo.parameterTypes);
}
break;
case kCallSiteRef:
outSize = snprintf(buf, bufSize, "call_site@%0*x", width, index);
break;
default:
outSize = snprintf(buf, bufSize, "<?>");
break;
Expand Down Expand Up @@ -1842,6 +1845,219 @@ void dumpRegisterMaps(DexFile* pDexFile)
}
}

static const DexMapItem* findMapItem(const DexFile* pDexFile, u4 type)
{
u4 offset = pDexFile->pHeader->mapOff;
const DexMapList* list = (const DexMapList*)(pDexFile->baseAddr + offset);
for (u4 i = 0; i < list->size; ++i) {
if (list->list[i].type == type) {
return &list->list[i];
}
}
return nullptr;
}

static void dumpMethodHandles(DexFile* pDexFile)
{
const DexMapItem* item = findMapItem(pDexFile, kDexTypeMethodHandleItem);
if (item == nullptr) return;
const DexMethodHandleItem* method_handles =
(const DexMethodHandleItem*)(pDexFile->baseAddr + item->offset);
for (u4 i = 0; i < item->size; ++i) {
const DexMethodHandleItem& mh = method_handles[i];
bool is_invoke = false;
const char* type;
switch (mh.methodHandleType) {
case 0:
type = "put-static";
break;
case 1:
type = "get-static";
break;
case 2:
type = "put-instance";
break;
case 3:
type = "get-instance";
break;
case 4:
type = "invoke-static";
is_invoke = true;
break;
case 5:
type = "invoke-instance";
is_invoke = true;
break;
case 6:
type = "invoke-constructor";
is_invoke = true;
break;
}

FieldMethodInfo info;
memset(&info, 0, sizeof(info));
if (is_invoke) {
getMethodInfo(pDexFile, mh.fieldOrMethodIdx, &info);
} else {
getFieldInfo(pDexFile, mh.fieldOrMethodIdx, &info);
}

if (gOptions.outputFormat == OUTPUT_XML) {
printf("<method_handle index index=\"%u\"\n", i);
printf(" type=\"%s\"\n", type);
printf(" target_class=\"%s\"\n", info.classDescriptor);
printf(" target_member=\"%s\"\n", info.name);
printf(" target_member_type=\"%s\"\n", info.signature);
printf("</method_handle>\n");
} else {
printf("Method Handle #%u:\n", i);
printf(" type : %s\n", type);
printf(" target : %s %s\n", info.classDescriptor, info.name);
printf(" target_type : %s\n", info.signature);
}
}
}

/* Helper for dumpCallSites(), which reads a 1- to 8- byte signed
* little endian value. */
static u8 readSignedLittleEndian(const u1** pData, u4 size) {
const u1* data = *pData;
u8 result = 0;
u4 i;

for (i = 0; i < size; i++) {
result = (result >> 8) | (((int64_t)*data++) << 56);
}

result >>= (8 - size) * 8;
*pData = data;
return result;
}

/* Helper for dumpCallSites(), which reads a 1- to 8- byte unsigned
* little endian value. */
static u8 readUnsignedLittleEndian(const u1** pData, u4 size, bool fillOnRight = false) {
const u1* data = *pData;
u8 result = 0;
u4 i;

for (i = 0; i < size; i++) {
result = (result >> 8) | (((u8)*data++) << 56);
}

u8 oldResult = result;
if (!fillOnRight) {
result >>= (8u - size) * 8;
}

*pData = data;
return result;
}

static void dumpCallSites(DexFile* pDexFile)
{
const DexMapItem* item = findMapItem(pDexFile, kDexTypeCallSiteIdItem);
if (item == nullptr) return;
const DexCallSiteId* ids = (const DexCallSiteId*)(pDexFile->baseAddr + item->offset);
for (u4 index = 0; index < item->size; ++index) {
bool doXml = (gOptions.outputFormat == OUTPUT_XML);
printf(doXml ? "<call_site index=\"%u\">\n" : "Call Site #%u\n", index);
const u1* data = pDexFile->baseAddr + ids[index].callSiteOff;
u4 count = readUnsignedLeb128(&data);
for (u4 i = 0; i < count; ++i) {
printf(doXml ? "<link_argument index=\"%u\" " : " link_argument[%u] : ", i);
u1 headerByte = *data++;
u4 valueType = headerByte & kDexAnnotationValueTypeMask;
u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
switch (valueType) {
case kDexAnnotationByte: {
printf(doXml ? "type=\"byte\" value=\"%d\"/>" : "%d (byte)", (int)*data++);
break;
}
case kDexAnnotationShort: {
printf(doXml ? "type=\"short\" value=\"%d\"/>" : "%d (short)",
(int)readSignedLittleEndian(&data, valueArg + 1));
break;
}
case kDexAnnotationChar: {
printf(doXml ? "type=\"short\" value=\"%u\"/>" : "%u (char)",
(u2)readUnsignedLittleEndian(&data, valueArg + 1));
break;
}
case kDexAnnotationInt: {
printf(doXml ? "type=\"int\" value=\"%d\"/>" : "%d (int)",
(int)readSignedLittleEndian(&data, valueArg + 1));
break;
}
case kDexAnnotationLong: {
printf(doXml ? "type=\"long\" value=\"%" PRId64 "\"/>" : "%" PRId64 " (long)",
(int64_t)readSignedLittleEndian(&data, valueArg + 1));
break;
}
case kDexAnnotationFloat: {
u4 rawValue = (u4)(readUnsignedLittleEndian(&data, valueArg + 1, true) >> 32);
printf(doXml ? "type=\"float\" value=\"%g\"/>" : "%g (float)",
*((float*)&rawValue));
break;
}
case kDexAnnotationDouble: {
u8 rawValue = readUnsignedLittleEndian(&data, valueArg + 1, true);
printf(doXml ? "type=\"double\" value=\"%g\"/>" : "%g (double)",
*((double*)&rawValue));
break;
}
case kDexAnnotationMethodType: {
u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
ProtoInfo protoInfo;
memset(&protoInfo, 0, sizeof(protoInfo));
getProtoInfo(pDexFile, idx, &protoInfo);
printf(doXml ? "type=\"MethodType\" value=\"(%s)%s\"/>" : "(%s)%s (MethodType)",
protoInfo.parameterTypes, protoInfo.returnType);
free(protoInfo.parameterTypes);
break;
}
case kDexAnnotationMethodHandle: {
u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
printf(doXml ? "type=\"MethodHandle\" value=\"%u\"/>" : "%u (MethodHandle)",
idx);
break;
}
case kDexAnnotationString: {
u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
printf(doXml ? "type=\"String\" value=\"%s\"/>" : "%s (String)",
dexStringById(pDexFile, idx));
break;
}
case kDexAnnotationType: {
u4 idx = (u4) readUnsignedLittleEndian(&data, valueArg + 1);
printf(doXml ? "type=\"Class\" value=\"%s\"/>" : "%s (Class)",
dexStringByTypeIdx(pDexFile, idx));
break;
}
case kDexAnnotationNull: {
printf(doXml ? "type=\"null\" value=\"null\"/>" : "null (null)");
break;
}
case kDexAnnotationBoolean: {
printf(doXml ? "type=\"boolean\" value=\"%s\"/>" : "%s (boolean)",
(valueArg & 1) == 0 ? "false" : "true");
break;
}
default:
// Other types are not anticipated being reached here.
printf("Unexpected type found, bailing on call site info.\n");
i = count;
break;
}
printf("\n");
}

if (doXml) {
printf("</callsite>\n");
}
}
}

/*
* Dump the requested sections of the file.
*/
Expand Down Expand Up @@ -1875,6 +2091,9 @@ void processDexFile(const char* fileName, DexFile* pDexFile)
dumpClass(pDexFile, i, &package);
}

dumpMethodHandles(pDexFile);
dumpCallSites(pDexFile);

/* free the last one allocated */
if (package != NULL) {
printf("</package>\n");
Expand Down
26 changes: 18 additions & 8 deletions dx/src/com/android/dx/dex/code/Dops.java
Expand Up @@ -501,10 +501,6 @@ public final class Dops {
new Dop(Opcodes.INVOKE_INTERFACE, Opcodes.INVOKE_INTERFACE,
Opcodes.INVOKE_INTERFACE_RANGE, Form35c.THE_ONE, false);

public static final Dop INVOKE_POLYMORPHIC =
new Dop(Opcodes.INVOKE_POLYMORPHIC, Opcodes.INVOKE_POLYMORPHIC,
Opcodes.INVOKE_POLYMORPHIC_RANGE, Form45cc.THE_ONE, false);

public static final Dop INVOKE_VIRTUAL_RANGE =
new Dop(Opcodes.INVOKE_VIRTUAL_RANGE, Opcodes.INVOKE_VIRTUAL,
Opcodes.NO_NEXT, Form3rc.THE_ONE, false);
Expand All @@ -525,10 +521,6 @@ public final class Dops {
new Dop(Opcodes.INVOKE_INTERFACE_RANGE, Opcodes.INVOKE_INTERFACE,
Opcodes.NO_NEXT, Form3rc.THE_ONE, false);

public static final Dop INVOKE_POLYMORPHIC_RANGE =
new Dop(Opcodes.INVOKE_POLYMORPHIC_RANGE, Opcodes.INVOKE_POLYMORPHIC,
Opcodes.NO_NEXT, Form4rcc.THE_ONE, false);

public static final Dop NEG_INT =
new Dop(Opcodes.NEG_INT, Opcodes.NEG_INT,
Opcodes.NO_NEXT, Form12x.THE_ONE, true);
Expand Down Expand Up @@ -945,6 +937,22 @@ public final class Dops {
new Dop(Opcodes.USHR_INT_LIT8, Opcodes.USHR_INT,
Opcodes.NO_NEXT, Form22b.THE_ONE, true);

public static final Dop INVOKE_POLYMORPHIC =
new Dop(Opcodes.INVOKE_POLYMORPHIC, Opcodes.INVOKE_POLYMORPHIC,
Opcodes.INVOKE_POLYMORPHIC_RANGE, Form45cc.THE_ONE, true);

public static final Dop INVOKE_POLYMORPHIC_RANGE =
new Dop(Opcodes.INVOKE_POLYMORPHIC_RANGE, Opcodes.INVOKE_POLYMORPHIC,
Opcodes.NO_NEXT, Form4rcc.THE_ONE, true);

public static final Dop INVOKE_CUSTOM =
new Dop(Opcodes.INVOKE_CUSTOM, Opcodes.INVOKE_CUSTOM,
Opcodes.INVOKE_CUSTOM_RANGE, Form35c.THE_ONE, true);

public static final Dop INVOKE_CUSTOM_RANGE =
new Dop(Opcodes.INVOKE_CUSTOM_RANGE, Opcodes.INVOKE_CUSTOM,
Opcodes.NO_NEXT, Form3rc.THE_ONE, true);

// END(dops)

// Static initialization.
Expand Down Expand Up @@ -1174,6 +1182,8 @@ public final class Dops {
set(USHR_INT_LIT8);
set(INVOKE_POLYMORPHIC);
set(INVOKE_POLYMORPHIC_RANGE);
set(INVOKE_CUSTOM);
set(INVOKE_CUSTOM_RANGE);
// END(dops-init)
}

Expand Down
1 change: 1 addition & 0 deletions dx/src/com/android/dx/dex/code/RopToDop.java
Expand Up @@ -214,6 +214,7 @@ private RopToDop() {
// Opcodes.SHR_INT_LIT8
// Opcodes.USHR_INT_LIT8
// Opcodes.INVOKE_POLYMORPHIC
// Opcodes.INVOKE_CUSTOM
// END(first-opcodes)

static {
Expand Down
3 changes: 3 additions & 0 deletions dx/src/com/android/dx/io/IndexType.java
Expand Up @@ -44,6 +44,9 @@ public enum IndexType {
/** method index and a proto index */
METHOD_AND_PROTO_REF,

/** call site reference index */
CALL_SITE_REF,

/** inline method index (for inline linked method invocations) */
INLINE_METHOD,

Expand Down
10 changes: 10 additions & 0 deletions dx/src/com/android/dx/io/OpcodeInfo.java
Expand Up @@ -939,6 +939,14 @@ public final class OpcodeInfo {
new Info(Opcodes.INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range",
InstructionCodec.FORMAT_4RCC, IndexType.METHOD_AND_PROTO_REF);

public static final Info INVOKE_CUSTOM =
new Info(Opcodes.INVOKE_CUSTOM, "invoke-custom",
InstructionCodec.FORMAT_35C, IndexType.CALL_SITE_REF);

public static final Info INVOKE_CUSTOM_RANGE =
new Info(Opcodes.INVOKE_CUSTOM_RANGE, "invoke-custom/range",
InstructionCodec.FORMAT_3RC, IndexType.CALL_SITE_REF);

// END(opcode-info-defs)

// Static initialization.
Expand Down Expand Up @@ -1174,6 +1182,8 @@ public final class OpcodeInfo {
set(USHR_INT_LIT8);
set(INVOKE_POLYMORPHIC);
set(INVOKE_POLYMORPHIC_RANGE);
set(INVOKE_CUSTOM);
set(INVOKE_CUSTOM_RANGE);
// END(opcode-info-init)
}

Expand Down
2 changes: 2 additions & 0 deletions dx/src/com/android/dx/io/Opcodes.java
Expand Up @@ -261,6 +261,8 @@ public final class Opcodes {
public static final int USHR_INT_LIT8 = 0xe2;
public static final int INVOKE_POLYMORPHIC = 0xfa;
public static final int INVOKE_POLYMORPHIC_RANGE = 0xfb;
public static final int INVOKE_CUSTOM = 0xfc;
public static final int INVOKE_CUSTOM_RANGE = 0xfd;
// END(opcodes)

// TODO: Generate these payload opcodes with opcode-gen.
Expand Down
26 changes: 26 additions & 0 deletions libdex/DexFile.h
Expand Up @@ -92,6 +92,11 @@ typedef int64_t s8;
*/
#define DEX_MAGIC_VERS_37 "037\0"

/* The version for android O, encoded in 4 bytes of ASCII. This differentiates dex files that may
* contain invoke-custom, invoke-polymorphic, call-sites, and method handles.
*/
#define DEX_MAGIC_VERS_38 "038\0"

/* current version, encoded in 4 bytes of ASCII */
#define DEX_MAGIC_VERS "036\0"

Expand Down Expand Up @@ -191,6 +196,8 @@ enum {
kDexAnnotationLong = 0x06,
kDexAnnotationFloat = 0x10,
kDexAnnotationDouble = 0x11,
kDexAnnotationMethodType = 0x15,
kDexAnnotationMethodHandle = 0x16,
kDexAnnotationString = 0x17,
kDexAnnotationType = 0x18,
kDexAnnotationField = 0x19,
Expand All @@ -214,6 +221,8 @@ enum {
kDexTypeFieldIdItem = 0x0004,
kDexTypeMethodIdItem = 0x0005,
kDexTypeClassDefItem = 0x0006,
kDexTypeCallSiteIdItem = 0x0007,
kDexTypeMethodHandleItem = 0x0008,
kDexTypeMapList = 0x1000,
kDexTypeTypeList = 0x1001,
kDexTypeAnnotationSetRefList = 0x1002,
Expand Down Expand Up @@ -354,6 +363,23 @@ struct DexClassDef {
u4 staticValuesOff; /* file offset to DexEncodedArray */
};

/*
* Direct-mapped "call_site_id_item"
*/
struct DexCallSiteId {
u4 callSiteOff; /* file offset to DexEncodedArray */
};

/*
* Direct-mapped "method_handle_item"
*/
struct DexMethodHandleItem {
u2 methodHandleType; /* type of method handle */
u2 reserved1; /* reserved for future use */
u2 fieldOrMethodIdx; /* index of associated field or method */
u2 reserved2; /* reserved for future use */
};

/*
* Direct-mapped "type_item".
*/
Expand Down

0 comments on commit fa5e510

Please sign in to comment.