diff options
| -rw-r--r-- | dexdump/dexdump.cc | 150 | ||||
| -rw-r--r-- | runtime/dex_file.cc | 22 | ||||
| -rw-r--r-- | runtime/dex_file.h | 9 | ||||
| -rwxr-xr-x | test/dexdump/bytecodes.txt | 1 | ||||
| -rwxr-xr-x | test/dexdump/bytecodes.xml | 1 | ||||
| -rw-r--r-- | test/dexdump/staticfields.dex | bin | 0 -> 1264 bytes | |||
| -rw-r--r-- | test/dexdump/staticfields.lst | 2 | ||||
| -rw-r--r-- | test/dexdump/staticfields.txt | 126 | ||||
| -rw-r--r-- | test/dexdump/staticfields.xml | 129 |
9 files changed, 430 insertions, 10 deletions
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index 52e6c023fe..d38772659b 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -27,7 +27,6 @@ * Differences between XML output and the "current.xml" file: * - classes in same package are not all grouped together; nothing is sorted * - no "deprecated" on fields and methods - * - no "value" on fields * - no parameter names * - no generic signatures on parameters, e.g. type="java.lang.Class<?>" * - class shows declared fields and methods; does not show inherited fields @@ -1019,9 +1018,126 @@ static void dumpMethod(const DexFile* pDexFile, u4 idx, u4 flags, } /* + * 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) { +static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i, + EncodedStaticFieldValueIterator::ValueType valueType, + const jvalue* pValue) { // Bail for anything private if export only requested. if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) { return; @@ -1038,6 +1154,11 @@ static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { fprintf(gOutFile, " name : '%s'\n", name); fprintf(gOutFile, " type : '%s'\n", typeDescriptor); fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr); + if (pValue != nullptr) { + fputs(" value : ", gOutFile); + dumpSFieldValue(pDexFile, valueType, pValue); + fputs("\n", gOutFile); + } } else if (gOptions.outputFormat == OUTPUT_XML) { fprintf(gOutFile, "<field name=\"%s\"\n", name); char *tmp = descriptorToDot(typeDescriptor); @@ -1050,7 +1171,12 @@ static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { 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)); - fprintf(gOutFile, ">\n</field>\n"); + if (pValue != nullptr) { + fputs(" value=\"", gOutFile); + dumpSFieldValue(pDexFile, valueType, pValue); + fputs("\"\n", gOutFile); + } + fputs(">\n</field>\n", gOutFile); } free(accessStr); @@ -1060,7 +1186,8 @@ static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { * Dumps an instance field. */ static void dumpIField(const DexFile* pDexFile, u4 idx, u4 flags, int i) { - dumpSField(pDexFile, idx, flags, i); + dumpSField(pDexFile, idx, flags, i, + EncodedStaticFieldValueIterator::kByte, nullptr); } /* @@ -1222,10 +1349,23 @@ static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) { 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); + pClassData.GetRawMemberAccessFlags(), i, + valueType, pValue); + if (staticFieldValues.HasNext()) { + staticFieldValues.Next(); + } } // for + DCHECK(!staticFieldValues.HasNext()); if (gOptions.outputFormat == OUTPUT_PLAIN) { fprintf(gOutFile, " Instance fields -\n"); } diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 30d921afe6..4e15e808f2 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -2208,14 +2208,24 @@ void ClassDataItemIterator::ReadClassDataMethod() { } EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator( + const DexFile& dex_file, + const DexFile::ClassDef& class_def) + : EncodedStaticFieldValueIterator(dex_file, nullptr, nullptr, + nullptr, class_def) { +} + +EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator( const DexFile& dex_file, Handle<mirror::DexCache>* dex_cache, Handle<mirror::ClassLoader>* class_loader, ClassLinker* linker, const DexFile::ClassDef& class_def) - : dex_file_(dex_file), dex_cache_(dex_cache), class_loader_(class_loader), linker_(linker), - array_size_(), pos_(-1), type_(kByte) { - DCHECK(dex_cache != nullptr); - DCHECK(class_loader != nullptr); - ptr_ = dex_file.GetEncodedStaticFieldValuesArray(class_def); + : dex_file_(dex_file), + dex_cache_(dex_cache), + class_loader_(class_loader), + linker_(linker), + array_size_(), + pos_(-1), + type_(kByte) { + ptr_ = dex_file_.GetEncodedStaticFieldValuesArray(class_def); if (ptr_ == nullptr) { array_size_ = 0; } else { @@ -2288,6 +2298,8 @@ void EncodedStaticFieldValueIterator::Next() { template<bool kTransactionActive> void EncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) const { + DCHECK(dex_cache_ != nullptr); + DCHECK(class_loader_ != nullptr); switch (type_) { case kBoolean: field->SetBoolean<kTransactionActive>(field->GetDeclaringClass(), jval_.z); break; diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 1e44f509f1..6b019f1140 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -1510,6 +1510,12 @@ class ClassDataItemIterator { class EncodedStaticFieldValueIterator { public: + // A constructor for static tools. You cannot call + // ReadValueToField() for an object created by this. + EncodedStaticFieldValueIterator(const DexFile& dex_file, + const DexFile::ClassDef& class_def); + + // A constructor meant to be called from runtime code. EncodedStaticFieldValueIterator(const DexFile& dex_file, Handle<mirror::DexCache>* dex_cache, Handle<mirror::ClassLoader>* class_loader, ClassLinker* linker, const DexFile::ClassDef& class_def) @@ -1541,6 +1547,9 @@ class EncodedStaticFieldValueIterator { kBoolean = 0x1f }; + ValueType GetValueType() const { return type_; } + const jvalue& GetJavaValue() const { return jval_; } + private: static constexpr uint8_t kEncodedValueTypeMask = 0x1f; // 0b11111 static constexpr uint8_t kEncodedValueArgShift = 5; diff --git a/test/dexdump/bytecodes.txt b/test/dexdump/bytecodes.txt index d14c47c886..4c8b79b7dd 100755 --- a/test/dexdump/bytecodes.txt +++ b/test/dexdump/bytecodes.txt @@ -196,6 +196,7 @@ Class #4 - name : 'icon' type : 'I' access : 0x0019 (PUBLIC STATIC FINAL) + value : 2130837504 Instance fields - Direct methods - #0 : (in Lcom/google/android/test/R$drawable;) diff --git a/test/dexdump/bytecodes.xml b/test/dexdump/bytecodes.xml index 0581677f6a..8e54dd33ce 100755 --- a/test/dexdump/bytecodes.xml +++ b/test/dexdump/bytecodes.xml @@ -97,6 +97,7 @@ static="true" final="true" visibility="public" + value="2130837504" > </field> <constructor name="R.drawable" diff --git a/test/dexdump/staticfields.dex b/test/dexdump/staticfields.dex Binary files differnew file mode 100644 index 0000000000..a07c46ef59 --- /dev/null +++ b/test/dexdump/staticfields.dex diff --git a/test/dexdump/staticfields.lst b/test/dexdump/staticfields.lst new file mode 100644 index 0000000000..5375b8e0dc --- /dev/null +++ b/test/dexdump/staticfields.lst @@ -0,0 +1,2 @@ +#staticfields.dex +0x000001bc 8 StaticFields <init> ()V StaticFields.java 24 diff --git a/test/dexdump/staticfields.txt b/test/dexdump/staticfields.txt new file mode 100644 index 0000000000..022605f90d --- /dev/null +++ b/test/dexdump/staticfields.txt @@ -0,0 +1,126 @@ +Processing 'staticfields.dex'... +Opened 'staticfields.dex', DEX version '035' +DEX file header: +magic : 'dex\n035\0' +checksum : 52d4fc6d +signature : 6e82...2f27 +file_size : 1264 +header_size : 112 +link_size : 0 +link_off : 0 (0x000000) +string_ids_size : 28 +string_ids_off : 112 (0x000070) +type_ids_size : 12 +type_ids_off : 224 (0x0000e0) +proto_ids_size : 1 +proto_ids_off : 272 (0x000110) +field_ids_size : 12 +field_ids_off : 284 (0x00011c) +method_ids_size : 2 +method_ids_off : 380 (0x00017c) +class_defs_size : 1 +class_defs_off : 396 (0x00018c) +data_size : 836 +data_off : 428 (0x0001ac) + +Class #0 header: +class_idx : 6 +access_flags : 1 (0x0001) +superclass_idx : 7 +interfaces_off : 0 (0x000000) +source_file_idx : 11 +annotations_off : 0 (0x000000) +class_data_off : 1067 (0x00042b) +static_fields_size : 12 +instance_fields_size: 0 +direct_methods_size : 1 +virtual_methods_size: 0 + +Class #0 - + Class descriptor : 'LStaticFields;' + Access flags : 0x0001 (PUBLIC) + Superclass : 'Ljava/lang/Object;' + Interfaces - + Static fields - + #0 : (in LStaticFields;) + name : 'test00_public_static_final_byte_42' + type : 'B' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 42 + #1 : (in LStaticFields;) + name : 'test01_public_static_final_short_43' + type : 'S' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 43 + #2 : (in LStaticFields;) + name : 'test02_public_static_final_char_X' + type : 'C' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 88 + #3 : (in LStaticFields;) + name : 'test03_public_static_final_int_44' + type : 'I' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 44 + #4 : (in LStaticFields;) + name : 'test04_public_static_final_long_45' + type : 'J' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 45 + #5 : (in LStaticFields;) + name : 'test05_public_static_final_float_46_47' + type : 'F' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 46.470001 + #6 : (in LStaticFields;) + name : 'test06_public_static_final_double_48_49' + type : 'D' + access : 0x0019 (PUBLIC STATIC FINAL) + value : 48.490000 + #7 : (in LStaticFields;) + name : 'test07_public_static_final_string' + type : 'Ljava/lang/String;' + access : 0x0019 (PUBLIC STATIC FINAL) + value : "abc \\><\"'&\t\r\n" + #8 : (in LStaticFields;) + name : 'test08_public_static_final_object_null' + type : 'Ljava/lang/Object;' + access : 0x0019 (PUBLIC STATIC FINAL) + value : null + #9 : (in LStaticFields;) + name : 'test09_public_static_final_boolean_true' + type : 'Z' + access : 0x0019 (PUBLIC STATIC FINAL) + value : true + #10 : (in LStaticFields;) + name : 'test10_private_static_final_int_50' + type : 'I' + access : 0x001a (PRIVATE STATIC FINAL) + value : 50 + #11 : (in LStaticFields;) + name : 'test99_empty_value' + type : 'I' + access : 0x0019 (PUBLIC STATIC FINAL) + Instance fields - + Direct methods - + #0 : (in LStaticFields;) + name : '<init>' + type : '()V' + access : 0x10001 (PUBLIC CONSTRUCTOR) + code - + registers : 1 + ins : 1 + outs : 1 + insns size : 4 16-bit code units +0001ac: |[0001ac] StaticFields.<init>:()V +0001bc: 7010 0100 0000 |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0001 +0001c2: 0e00 |0003: return-void + catches : (none) + positions : + 0x0000 line=24 + locals : + 0x0000 - 0x0004 reg=0 this LStaticFields; + + Virtual methods - + source_file_idx : 11 (StaticFields.java) + diff --git a/test/dexdump/staticfields.xml b/test/dexdump/staticfields.xml new file mode 100644 index 0000000000..6cff71b69f --- /dev/null +++ b/test/dexdump/staticfields.xml @@ -0,0 +1,129 @@ +<api> +<package name="" +> +<class name="StaticFields" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + visibility="public" +> +<field name="test00_public_static_final_byte_42" + type="byte" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="42" +> +</field> +<field name="test01_public_static_final_short_43" + type="short" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="43" +> +</field> +<field name="test02_public_static_final_char_X" + type="char" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="88" +> +</field> +<field name="test03_public_static_final_int_44" + type="int" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="44" +> +</field> +<field name="test04_public_static_final_long_45" + type="long" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="45" +> +</field> +<field name="test05_public_static_final_float_46_47" + type="float" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="46.470001" +> +</field> +<field name="test06_public_static_final_double_48_49" + type="double" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="48.490000" +> +</field> +<field name="test07_public_static_final_string" + type="java.lang.String" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="abc \><"'&	
" +> +</field> +<field name="test08_public_static_final_object_null" + type="java.lang.Object" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="null" +> +</field> +<field name="test09_public_static_final_boolean_true" + type="boolean" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" + value="true" +> +</field> +<field name="test99_empty_value" + type="int" + transient="false" + volatile="false" + static="true" + final="true" + visibility="public" +> +</field> +<constructor name="StaticFields" + type="StaticFields" + static="false" + final="false" + visibility="public" +> +</constructor> +</class> +</package> +</api> |