Implemented annotations display in dexdump.
Rationale:
Showing this in true dexdump style as a separate construct
under switch -a (rather than interpreting the data and showing
each annotation where it is used). Also added new test to
cover many more value encodings in static fields.
BUG=28981655
Change-Id: I6d7d44cbd358d9880aab78812471bdb0dc6b6ad8
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 1a2f2c2..9e06a7c 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -17,8 +17,8 @@
*
* This is a re-implementation of the original dexdump utility that was
* based on Dalvik functions in libdex into a new dexdump that is now
- * based on Art functions in libart instead. The output is identical to
- * the original for correct DEX files. Error messages may differ, however.
+ * based on Art functions in libart instead. The output is very similar to
+ * to the original for correct DEX files. Error messages may differ, however.
* Also, ODEX files are no longer supported.
*
* The dexdump tool is intended to mimic objdump. When possible, use
@@ -65,6 +65,8 @@
typedef uint16_t u2;
typedef uint32_t u4;
typedef uint64_t u8;
+typedef int8_t s1;
+typedef int16_t s2;
typedef int32_t s4;
typedef int64_t s8;
@@ -187,6 +189,13 @@
}
/*
+ * Returns string representing the boolean value.
+ */
+static const char* strBool(bool val) {
+ return val ? "true" : "false";
+}
+
+/*
* Returns a quoted string representing the boolean value.
*/
static const char* quotedBool(bool val) {
@@ -346,10 +355,197 @@
}
/*
+ * Dumps a string value with some escape characters.
+ */
+static void dumpEscapedString(const char* p) {
+ fputs("\"", gOutFile);
+ for (; *p; p++) {
+ switch (*p) {
+ case '\\':
+ fputs("\\\\", gOutFile);
+ break;
+ case '\"':
+ fputs("\\\"", gOutFile);
+ break;
+ case '\t':
+ fputs("\\t", gOutFile);
+ break;
+ case '\n':
+ fputs("\\n", gOutFile);
+ break;
+ case '\r':
+ fputs("\\r", gOutFile);
+ break;
+ default:
+ putc(*p, gOutFile);
+ } // switch
+ } // for
+ fputs("\"", gOutFile);
+}
+
+/*
+ * Dumps a string as an XML attribute value.
+ */
+static void dumpXmlAttribute(const char* p) {
+ for (; *p; p++) {
+ switch (*p) {
+ case '&':
+ fputs("&", gOutFile);
+ break;
+ case '<':
+ fputs("<", gOutFile);
+ break;
+ case '>':
+ fputs(">", gOutFile);
+ break;
+ case '"':
+ fputs(""", gOutFile);
+ break;
+ case '\t':
+ fputs("	", gOutFile);
+ break;
+ case '\n':
+ fputs("
", gOutFile);
+ break;
+ case '\r':
+ fputs("
", gOutFile);
+ break;
+ default:
+ putc(*p, gOutFile);
+ } // switch
+ } // for
+}
+
+/*
+ * Reads variable width value, possibly sign extended at the last defined byte.
+ */
+static u8 readVarWidth(const u1** data, u1 arg, bool sign_extend) {
+ u8 value = 0;
+ for (u4 i = 0; i <= arg; i++) {
+ value |= static_cast<u8>(*(*data)++) << (i * 8);
+ }
+ if (sign_extend) {
+ int shift = (7 - arg) * 8;
+ return (static_cast<s8>(value) << shift) >> shift;
+ }
+ return value;
+}
+
+/*
+ * Dumps encoded value.
+ */
+static void dumpEncodedValue(const DexFile* pDexFile, const u1** data); // forward
+static void dumpEncodedValue(const DexFile* pDexFile, const u1** data, u1 type, u1 arg) {
+ switch (type) {
+ case DexFile::kDexAnnotationByte:
+ fprintf(gOutFile, "%" PRId8, static_cast<s1>(readVarWidth(data, arg, false)));
+ break;
+ case DexFile::kDexAnnotationShort:
+ fprintf(gOutFile, "%" PRId16, static_cast<s2>(readVarWidth(data, arg, true)));
+ break;
+ case DexFile::kDexAnnotationChar:
+ fprintf(gOutFile, "%" PRIu16, static_cast<u2>(readVarWidth(data, arg, false)));
+ break;
+ case DexFile::kDexAnnotationInt:
+ fprintf(gOutFile, "%" PRId32, static_cast<s4>(readVarWidth(data, arg, true)));
+ break;
+ case DexFile::kDexAnnotationLong:
+ fprintf(gOutFile, "%" PRId64, static_cast<s8>(readVarWidth(data, arg, true)));
+ break;
+ case DexFile::kDexAnnotationFloat: {
+ // Fill on right.
+ union {
+ float f;
+ u4 data;
+ } conv;
+ conv.data = static_cast<u4>(readVarWidth(data, arg, false)) << (3 - arg) * 8;
+ fprintf(gOutFile, "%g", conv.f);
+ break;
+ }
+ case DexFile::kDexAnnotationDouble: {
+ // Fill on right.
+ union {
+ double d;
+ u8 data;
+ } conv;
+ conv.data = readVarWidth(data, arg, false) << (7 - arg) * 8;
+ fprintf(gOutFile, "%g", conv.d);
+ break;
+ }
+ case DexFile::kDexAnnotationString: {
+ const u4 idx = static_cast<u4>(readVarWidth(data, arg, false));
+ if (gOptions.outputFormat == OUTPUT_PLAIN) {
+ dumpEscapedString(pDexFile->StringDataByIdx(idx));
+ } else {
+ dumpXmlAttribute(pDexFile->StringDataByIdx(idx));
+ }
+ break;
+ }
+ case DexFile::kDexAnnotationType: {
+ const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
+ fputs(pDexFile->StringByTypeIdx(str_idx), gOutFile);
+ break;
+ }
+ case DexFile::kDexAnnotationField:
+ case DexFile::kDexAnnotationEnum: {
+ const u4 field_idx = static_cast<u4>(readVarWidth(data, arg, false));
+ const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
+ fputs(pDexFile->StringDataByIdx(pFieldId.name_idx_), gOutFile);
+ break;
+ }
+ case DexFile::kDexAnnotationMethod: {
+ const u4 method_idx = static_cast<u4>(readVarWidth(data, arg, false));
+ const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
+ fputs(pDexFile->StringDataByIdx(pMethodId.name_idx_), gOutFile);
+ break;
+ }
+ case DexFile::kDexAnnotationArray: {
+ fputc('{', gOutFile);
+ // Decode and display all elements.
+ const u4 size = DecodeUnsignedLeb128(data);
+ for (u4 i = 0; i < size; i++) {
+ fputc(' ', gOutFile);
+ dumpEncodedValue(pDexFile, data);
+ }
+ fputs(" }", gOutFile);
+ break;
+ }
+ case DexFile::kDexAnnotationAnnotation: {
+ const u4 type_idx = DecodeUnsignedLeb128(data);
+ fputs(pDexFile->StringByTypeIdx(type_idx), gOutFile);
+ // Decode and display all name=value pairs.
+ const u4 size = DecodeUnsignedLeb128(data);
+ for (u4 i = 0; i < size; i++) {
+ const u4 name_idx = DecodeUnsignedLeb128(data);
+ fputc(' ', gOutFile);
+ fputs(pDexFile->StringDataByIdx(name_idx), gOutFile);
+ fputc('=', gOutFile);
+ dumpEncodedValue(pDexFile, data);
+ }
+ break;
+ }
+ case DexFile::kDexAnnotationNull:
+ fputs("null", gOutFile);
+ break;
+ case DexFile::kDexAnnotationBoolean:
+ fputs(strBool(arg), gOutFile);
+ break;
+ default:
+ fputs("????", gOutFile);
+ break;
+ } // switch
+}
+
+/*
+ * Dumps encoded value with prefix.
+ */
+static void dumpEncodedValue(const DexFile* pDexFile, const u1** data) {
+ const u1 enc = *(*data)++;
+ dumpEncodedValue(pDexFile, data, enc & 0x1f, enc >> 5);
+}
+
+/*
* Dumps the file header.
- *
- * Note that some of the : are misaligned on purpose to preserve
- * the exact output of the original Dalvik dexdump.
*/
static void dumpFileHeader(const DexFile* pDexFile) {
const DexFile::Header& pHeader = pDexFile->GetHeader();
@@ -373,8 +569,8 @@
fprintf(gOutFile, "type_ids_size : %d\n", pHeader.type_ids_size_);
fprintf(gOutFile, "type_ids_off : %d (0x%06x)\n",
pHeader.type_ids_off_, pHeader.type_ids_off_);
- fprintf(gOutFile, "proto_ids_size : %d\n", pHeader.proto_ids_size_);
- fprintf(gOutFile, "proto_ids_off : %d (0x%06x)\n",
+ fprintf(gOutFile, "proto_ids_size : %d\n", pHeader.proto_ids_size_);
+ fprintf(gOutFile, "proto_ids_off : %d (0x%06x)\n",
pHeader.proto_ids_off_, pHeader.proto_ids_off_);
fprintf(gOutFile, "field_ids_size : %d\n", pHeader.field_ids_size_);
fprintf(gOutFile, "field_ids_off : %d (0x%06x)\n",
@@ -426,6 +622,99 @@
fprintf(gOutFile, "\n");
}
+/**
+ * Dumps an annotation set item.
+ */
+static void dumpAnnotationSetItem(const DexFile* pDexFile, const DexFile::AnnotationSetItem* set_item) {
+ if (set_item == nullptr || set_item->size_ == 0) {
+ fputs(" empty-annotation-set\n", gOutFile);
+ return;
+ }
+ for (u4 i = 0; i < set_item->size_; i++) {
+ const DexFile::AnnotationItem* annotation = pDexFile->GetAnnotationItem(set_item, i);
+ if (annotation == nullptr) {
+ continue;
+ }
+ fputs(" ", gOutFile);
+ switch (annotation->visibility_) {
+ case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", gOutFile); break;
+ case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", gOutFile); break;
+ case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", gOutFile); break;
+ default: fputs("VISIBILITY_UNKNOWN ", gOutFile); break;
+ } // switch
+ // Decode raw bytes in annotation.
+ const u1* rData = annotation->annotation_;
+ dumpEncodedValue(pDexFile, &rData, DexFile::kDexAnnotationAnnotation, 0);
+ fputc('\n', gOutFile);
+ }
+}
+
+/*
+ * Dumps class annotations.
+ */
+static void dumpClassAnnotations(const DexFile* pDexFile, int idx) {
+ const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
+ const DexFile::AnnotationsDirectoryItem* dir = pDexFile->GetAnnotationsDirectory(pClassDef);
+ if (dir == nullptr) {
+ return; // none
+ }
+
+ fprintf(gOutFile, "Class #%d annotations:\n", idx);
+
+ const DexFile::AnnotationSetItem* class_set_item = pDexFile->GetClassAnnotationSet(dir);
+ const DexFile::FieldAnnotationsItem* fields = pDexFile->GetFieldAnnotations(dir);
+ const DexFile::MethodAnnotationsItem* methods = pDexFile->GetMethodAnnotations(dir);
+ const DexFile::ParameterAnnotationsItem* pars = pDexFile->GetParameterAnnotations(dir);
+
+ // Annotations on the class itself.
+ if (class_set_item != nullptr) {
+ fprintf(gOutFile, "Annotations on class\n");
+ dumpAnnotationSetItem(pDexFile, class_set_item);
+ }
+
+ // Annotations on fields.
+ if (fields != nullptr) {
+ for (u4 i = 0; i < dir->fields_size_; i++) {
+ const u4 field_idx = fields[i].field_idx_;
+ const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
+ const char* field_name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
+ fprintf(gOutFile, "Annotations on field #%u '%s'\n", field_idx, field_name);
+ dumpAnnotationSetItem(pDexFile, pDexFile->GetFieldAnnotationSetItem(fields[i]));
+ }
+ }
+
+ // Annotations on methods.
+ if (methods != nullptr) {
+ for (u4 i = 0; i < dir->methods_size_; i++) {
+ const u4 method_idx = methods[i].method_idx_;
+ const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
+ const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
+ fprintf(gOutFile, "Annotations on method #%u '%s'\n", method_idx, method_name);
+ dumpAnnotationSetItem(pDexFile, pDexFile->GetMethodAnnotationSetItem(methods[i]));
+ }
+ }
+
+ // Annotations on method parameters.
+ if (pars != nullptr) {
+ for (u4 i = 0; i < dir->parameters_size_; i++) {
+ const u4 method_idx = pars[i].method_idx_;
+ const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
+ const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
+ fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
+ const DexFile::AnnotationSetRefList*
+ list = pDexFile->GetParameterAnnotationSetRefList(&pars[i]);
+ if (list != nullptr) {
+ for (u4 j = 0; j < list->size_; j++) {
+ fprintf(gOutFile, "#%u\n", j);
+ dumpAnnotationSetItem(pDexFile, pDexFile->GetSetRefItemItem(&list->list_[j]));
+ }
+ }
+ }
+ }
+
+ fputc('\n', gOutFile);
+}
+
/*
* Dumps an interface that a class declares to implement.
*/
@@ -677,27 +966,25 @@
fprintf(gOutFile, " v%d", pDecInsn->VRegA());
break;
case Instruction::k10t: // op +AA
- case Instruction::k20t: // op +AAAA
- {
- const s4 targ = (s4) pDecInsn->VRegA();
- fprintf(gOutFile, " %04x // %c%04x",
- insnIdx + targ,
- (targ < 0) ? '-' : '+',
- (targ < 0) ? -targ : targ);
- }
+ case Instruction::k20t: { // op +AAAA
+ const s4 targ = (s4) pDecInsn->VRegA();
+ fprintf(gOutFile, " %04x // %c%04x",
+ insnIdx + targ,
+ (targ < 0) ? '-' : '+',
+ (targ < 0) ? -targ : targ);
break;
+ }
case Instruction::k22x: // op vAA, vBBBB
fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
break;
- case Instruction::k21t: // op vAA, +BBBB
- {
- const s4 targ = (s4) pDecInsn->VRegB();
- fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
- insnIdx + targ,
- (targ < 0) ? '-' : '+',
- (targ < 0) ? -targ : targ);
- }
+ case Instruction::k21t: { // op vAA, +BBBB
+ const s4 targ = (s4) pDecInsn->VRegB();
+ fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
+ insnIdx + targ,
+ (targ < 0) ? '-' : '+',
+ (targ < 0) ? -targ : targ);
break;
+ }
case Instruction::k21s: // op vAA, #+BBBB
fprintf(gOutFile, " v%d, #int %d // #%x",
pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB());
@@ -727,16 +1014,15 @@
pDecInsn->VRegA(), pDecInsn->VRegB(),
(s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC());
break;
- case Instruction::k22t: // op vA, vB, +CCCC
- {
- const s4 targ = (s4) pDecInsn->VRegC();
- fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
- pDecInsn->VRegA(), pDecInsn->VRegB(),
- insnIdx + targ,
- (targ < 0) ? '-' : '+',
- (targ < 0) ? -targ : targ);
- }
+ case Instruction::k22t: { // op vA, vB, +CCCC
+ const s4 targ = (s4) pDecInsn->VRegC();
+ fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
+ pDecInsn->VRegA(), pDecInsn->VRegB(),
+ insnIdx + targ,
+ (targ < 0) ? '-' : '+',
+ (targ < 0) ? -targ : targ);
break;
+ }
case Instruction::k22s: // op vA, vB, #+CCCC
fprintf(gOutFile, " v%d, v%d, #int %d // #%04x",
pDecInsn->VRegA(), pDecInsn->VRegB(),
@@ -751,18 +1037,17 @@
case Instruction::k30t:
fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
break;
- case Instruction::k31i: // op vAA, #+BBBBBBBB
- {
- // This is often, but not always, a float.
- union {
- float f;
- u4 i;
- } conv;
- conv.i = pDecInsn->VRegB();
- fprintf(gOutFile, " v%d, #float %f // #%08x",
- pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
- }
+ case Instruction::k31i: { // op vAA, #+BBBBBBBB
+ // This is often, but not always, a float.
+ union {
+ float f;
+ u4 i;
+ } conv;
+ conv.i = pDecInsn->VRegB();
+ fprintf(gOutFile, " v%d, #float %g // #%08x",
+ pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
break;
+ }
case Instruction::k31t: // op vAA, offset +BBBBBBBB
fprintf(gOutFile, " v%d, %08x // +%08x",
pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB());
@@ -770,39 +1055,37 @@
case Instruction::k32x: // op vAAAA, vBBBB
fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
break;
- case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
+ case Instruction::k35c: { // op {vC, vD, vE, vF, vG}, thing@BBBB
// NOT SUPPORTED:
// case Instruction::k35ms: // [opt] invoke-virtual+super
// case Instruction::k35mi: // [opt] inline invoke
- {
- u4 arg[Instruction::kMaxVarArgRegs];
- pDecInsn->GetVarArgs(arg);
- fputs(" {", gOutFile);
- for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
- if (i == 0) {
- fprintf(gOutFile, "v%d", arg[i]);
- } else {
- fprintf(gOutFile, ", v%d", arg[i]);
- }
- } // for
- fprintf(gOutFile, "}, %s", indexBuf);
- }
+ u4 arg[Instruction::kMaxVarArgRegs];
+ pDecInsn->GetVarArgs(arg);
+ fputs(" {", gOutFile);
+ for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
+ if (i == 0) {
+ fprintf(gOutFile, "v%d", arg[i]);
+ } else {
+ fprintf(gOutFile, ", v%d", arg[i]);
+ }
+ } // for
+ fprintf(gOutFile, "}, %s", indexBuf);
break;
- case Instruction::k25x: // op vC, {vD, vE, vF, vG} (B: count)
- {
- u4 arg[Instruction::kMaxVarArgRegs25x];
- pDecInsn->GetAllArgs25x(arg);
- fprintf(gOutFile, " v%d, {", arg[0]);
- for (int i = 0, n = pDecInsn->VRegB(); i < n; i++) {
- if (i == 0) {
- fprintf(gOutFile, "v%d", arg[Instruction::kLambdaVirtualRegisterWidth + i]);
- } else {
- fprintf(gOutFile, ", v%d", arg[Instruction::kLambdaVirtualRegisterWidth + i]);
- }
- } // for
- fputc('}', gOutFile);
- }
+ }
+ case Instruction::k25x: { // op vC, {vD, vE, vF, vG} (B: count)
+ u4 arg[Instruction::kMaxVarArgRegs25x];
+ pDecInsn->GetAllArgs25x(arg);
+ fprintf(gOutFile, " v%d, {", arg[0]);
+ for (int i = 0, n = pDecInsn->VRegB(); i < n; i++) {
+ if (i == 0) {
+ fprintf(gOutFile, "v%d", arg[Instruction::kLambdaVirtualRegisterWidth + i]);
+ } else {
+ fprintf(gOutFile, ", v%d", arg[Instruction::kLambdaVirtualRegisterWidth + i]);
+ }
+ } // for
+ fputc('}', gOutFile);
break;
+ }
case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
// NOT SUPPORTED:
// case Instruction::k3rms: // [opt] invoke-virtual+super/range
@@ -821,18 +1104,17 @@
fprintf(gOutFile, "}, %s", indexBuf);
}
break;
- case Instruction::k51l: // op vAA, #+BBBBBBBBBBBBBBBB
- {
- // This is often, but not always, a double.
- union {
- double d;
- u8 j;
- } conv;
- conv.j = pDecInsn->WideVRegB();
- fprintf(gOutFile, " v%d, #double %f // #%016" PRIx64,
- pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
- }
+ case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
+ // This is often, but not always, a double.
+ union {
+ double d;
+ u8 j;
+ } conv;
+ conv.j = pDecInsn->WideVRegB();
+ fprintf(gOutFile, " v%d, #double %g // #%016" PRIx64,
+ pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
break;
+ }
// NOT SUPPORTED:
// case Instruction::k00x: // unknown op or breakpoint
// break;
@@ -1017,126 +1299,9 @@
}
/*
- * Dumps a string value with some escape characters.
- */
-static void dumpEscapedString(const char* p) {
- for (; *p; p++) {
- switch (*p) {
- case '\\':
- fputs("\\\\", gOutFile);
- break;
- case '\"':
- fputs("\\\"", gOutFile);
- break;
- case '\t':
- fputs("\\t", gOutFile);
- break;
- case '\n':
- fputs("\\n", gOutFile);
- break;
- case '\r':
- fputs("\\r", gOutFile);
- break;
- default:
- putc(*p, gOutFile);
- }
- }
-}
-
-/*
- * Dumps an XML attribute value between double-quotes.
- */
-static void dumpXmlAttribute(const char* p) {
- for (; *p; p++) {
- switch (*p) {
- case '&':
- fputs("&", gOutFile);
- break;
- case '<':
- fputs("<", gOutFile);
- break;
- case '"':
- fputs(""", gOutFile);
- break;
- case '\t':
- fputs("	", gOutFile);
- break;
- case '\n':
- fputs("
", gOutFile);
- break;
- case '\r':
- fputs("
", gOutFile);
- break;
- default:
- putc(*p, gOutFile);
- }
- }
-}
-
-/*
- * Dumps a value of static (class) field.
- */
-static void dumpSFieldValue(const DexFile* pDexFile,
- EncodedStaticFieldValueIterator::ValueType valueType,
- const jvalue* pValue) {
- switch (valueType) {
- case EncodedStaticFieldValueIterator::kByte:
- fprintf(gOutFile, "%" PRIu8, pValue->b);
- break;
- case EncodedStaticFieldValueIterator::kShort:
- fprintf(gOutFile, "%" PRId16, pValue->s);
- break;
- case EncodedStaticFieldValueIterator::kChar:
- fprintf(gOutFile, "%" PRIu16, pValue->c);
- break;
- case EncodedStaticFieldValueIterator::kInt:
- fprintf(gOutFile, "%" PRId32, pValue->i);
- break;
- case EncodedStaticFieldValueIterator::kLong:
- fprintf(gOutFile, "%" PRId64, pValue->j);
- break;
- case EncodedStaticFieldValueIterator::kFloat:
- fprintf(gOutFile, "%f", pValue->f);
- break;
- case EncodedStaticFieldValueIterator::kDouble:
- fprintf(gOutFile, "%f", pValue->d);
- break;
- case EncodedStaticFieldValueIterator::kString: {
- const char* str =
- pDexFile->GetStringData(pDexFile->GetStringId(pValue->i));
- if (gOptions.outputFormat == OUTPUT_PLAIN) {
- fputs("\"", gOutFile);
- dumpEscapedString(str);
- fputs("\"", gOutFile);
- } else {
- dumpXmlAttribute(str);
- }
- break;
- }
- case EncodedStaticFieldValueIterator::kNull:
- fputs("null", gOutFile);
- break;
- case EncodedStaticFieldValueIterator::kBoolean:
- fputs(pValue->z ? "true" : "false", gOutFile);
- break;
-
- case EncodedStaticFieldValueIterator::kAnnotation:
- case EncodedStaticFieldValueIterator::kArray:
- case EncodedStaticFieldValueIterator::kEnum:
- case EncodedStaticFieldValueIterator::kField:
- case EncodedStaticFieldValueIterator::kMethod:
- case EncodedStaticFieldValueIterator::kType:
- default:
- fprintf(gOutFile, "Unexpected static field type: %d", valueType);
- }
-}
-
-/*
* Dumps a static (class) field.
*/
-static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i,
- EncodedStaticFieldValueIterator::ValueType valueType,
- const jvalue* pValue) {
+static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i, const u1** data) {
// Bail for anything private if export only requested.
if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
return;
@@ -1153,9 +1318,9 @@
fprintf(gOutFile, " name : '%s'\n", name);
fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
- if (pValue != nullptr) {
+ if (data != nullptr) {
fputs(" value : ", gOutFile);
- dumpSFieldValue(pDexFile, valueType, pValue);
+ dumpEncodedValue(pDexFile, data);
fputs("\n", gOutFile);
}
} else if (gOptions.outputFormat == OUTPUT_XML) {
@@ -1170,9 +1335,9 @@
fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
// The "deprecated=" is not knowable w/o parsing annotations.
fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
- if (pValue != nullptr) {
+ if (data != nullptr) {
fputs(" value=\"", gOutFile);
- dumpSFieldValue(pDexFile, valueType, pValue);
+ dumpEncodedValue(pDexFile, data);
fputs("\"\n", gOutFile);
}
fputs(">\n</field>\n", gOutFile);
@@ -1185,8 +1350,7 @@
* Dumps an instance field.
*/
static void dumpIField(const DexFile* pDexFile, u4 idx, u4 flags, int i) {
- dumpSField(pDexFile, idx, flags, i,
- EncodedStaticFieldValueIterator::kByte, nullptr);
+ dumpSField(pDexFile, idx, flags, i, nullptr);
}
/*
@@ -1196,7 +1360,7 @@
*/
static void dumpCfg(const DexFile* dex_file,
- uint32_t dex_method_idx,
+ u4 dex_method_idx,
const DexFile::CodeItem* code_item) {
if (code_item != nullptr) {
std::ostringstream oss;
@@ -1207,7 +1371,7 @@
static void dumpCfg(const DexFile* dex_file, int idx) {
const DexFile::ClassDef& class_def = dex_file->GetClassDef(idx);
- const uint8_t* class_data = dex_file->GetClassData(class_def);
+ const u1* class_data = dex_file->GetClassData(class_def);
if (class_data == nullptr) { // empty class such as a marker interface?
return;
}
@@ -1248,7 +1412,15 @@
return;
}
- if (gOptions.cfg) {
+ if (gOptions.showSectionHeaders) {
+ dumpClassDef(pDexFile, idx);
+ }
+
+ if (gOptions.showAnnotations) {
+ dumpClassAnnotations(pDexFile, idx);
+ }
+
+ if (gOptions.showCfg) {
dumpCfg(pDexFile, idx);
return;
}
@@ -1347,33 +1519,35 @@
}
} else {
ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
+
+ // Prepare data for static fields.
+ const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef);
+ const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0;
+
+ // Static fields.
if (gOptions.outputFormat == OUTPUT_PLAIN) {
fprintf(gOutFile, " Static fields -\n");
}
- EncodedStaticFieldValueIterator staticFieldValues(*pDexFile, pClassDef);
- for (int i = 0; pClassData.HasNextStaticField(); i++, pClassData.Next()) {
- EncodedStaticFieldValueIterator::ValueType valueType =
- EncodedStaticFieldValueIterator::kByte;
- const jvalue* pValue = nullptr;
- if (staticFieldValues.HasNext()) {
- valueType = staticFieldValues.GetValueType();
- pValue = &staticFieldValues.GetJavaValue();
- }
- dumpSField(pDexFile, pClassData.GetMemberIndex(),
- pClassData.GetRawMemberAccessFlags(), i,
- valueType, pValue);
- if (staticFieldValues.HasNext()) {
- staticFieldValues.Next();
- }
+ for (u4 i = 0; pClassData.HasNextStaticField(); i++, pClassData.Next()) {
+ dumpSField(pDexFile,
+ pClassData.GetMemberIndex(),
+ pClassData.GetRawMemberAccessFlags(),
+ i,
+ i < sSize ? &sData : nullptr);
} // for
- DCHECK(!staticFieldValues.HasNext());
+
+ // Instance fields.
if (gOptions.outputFormat == OUTPUT_PLAIN) {
fprintf(gOutFile, " Instance fields -\n");
}
- for (int i = 0; pClassData.HasNextInstanceField(); i++, pClassData.Next()) {
- dumpIField(pDexFile, pClassData.GetMemberIndex(),
- pClassData.GetRawMemberAccessFlags(), i);
+ for (u4 i = 0; pClassData.HasNextInstanceField(); i++, pClassData.Next()) {
+ dumpIField(pDexFile,
+ pClassData.GetMemberIndex(),
+ pClassData.GetRawMemberAccessFlags(),
+ i);
} // for
+
+ // Direct methods.
if (gOptions.outputFormat == OUTPUT_PLAIN) {
fprintf(gOutFile, " Direct methods -\n");
}
@@ -1383,6 +1557,8 @@
pClassData.GetMethodCodeItem(),
pClassData.GetMethodCodeItemOffset(), i);
} // for
+
+ // Virtual methods.
if (gOptions.outputFormat == OUTPUT_PLAIN) {
fprintf(gOutFile, " Virtual methods -\n");
}
@@ -1434,9 +1610,6 @@
char* package = nullptr;
const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
for (u4 i = 0; i < classDefsSize; i++) {
- if (gOptions.showSectionHeaders) {
- dumpClassDef(pDexFile, i);
- }
dumpClass(pDexFile, i, &package);
} // for
@@ -1461,14 +1634,9 @@
}
// If the file is not a .dex file, the function tries .zip/.jar/.apk files,
- // all of which are Zip archives with "classes.dex" inside. The compressed
- // data needs to be extracted to a temp file, the location of which varies.
+ // all of which are Zip archives with "classes.dex" inside.
//
- // TODO(ajcbik): fix following issues
- //
- // (1) gOptions.tempFileName is not accounted for
- // (2) gOptions.ignoreBadChecksum is not accounted for
- //
+ // TODO(ajcbik): implement gOptions.ignoreBadChecksum
std::string error_msg;
std::vector<std::unique_ptr<const DexFile>> dex_files;
if (!DexFile::Open(fileName, fileName, &error_msg, &dex_files)) {