1/*
2 * Copyright 2013, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 *     * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *     * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32package org.jf.dexlib2.dexbacked.raw;
33
34import com.google.common.base.Joiner;
35import org.jf.dexlib2.AccessFlags;
36import org.jf.dexlib2.dexbacked.DexReader;
37import org.jf.dexlib2.dexbacked.raw.util.DexAnnotator;
38import org.jf.dexlib2.util.AnnotatedBytes;
39
40import javax.annotation.Nonnull;
41import javax.annotation.Nullable;
42
43public class ClassDataItem {
44    @Nonnull
45    public static SectionAnnotator makeAnnotator(@Nonnull DexAnnotator annotator, @Nonnull MapItem mapItem) {
46        return new SectionAnnotator(annotator, mapItem) {
47            private SectionAnnotator codeItemAnnotator = null;
48
49            @Override public void annotateSection(@Nonnull AnnotatedBytes out) {
50                codeItemAnnotator = annotator.getAnnotator(ItemType.CODE_ITEM);
51                super.annotateSection(out);
52            }
53
54
55            @Nonnull @Override public String getItemName() {
56                return "class_data_item";
57            }
58
59            @Override
60            protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) {
61                DexReader reader = dexFile.readerAt(out.getCursor());
62
63                int staticFieldsSize = reader.readSmallUleb128();
64                out.annotateTo(reader.getOffset(), "static_fields_size = %d", staticFieldsSize);
65
66                int instanceFieldsSize = reader.readSmallUleb128();
67                out.annotateTo(reader.getOffset(), "instance_fields_size = %d", instanceFieldsSize);
68
69                int directMethodsSize = reader.readSmallUleb128();
70                out.annotateTo(reader.getOffset(), "direct_methods_size = %d", directMethodsSize);
71
72                int virtualMethodsSize = reader.readSmallUleb128();
73                out.annotateTo(reader.getOffset(), "virtual_methods_size = %d", virtualMethodsSize);
74
75                int previousIndex = 0;
76                if (staticFieldsSize > 0) {
77                    out.annotate(0, "static_fields:");
78                    out.indent();
79                    for (int i=0; i<staticFieldsSize; i++) {
80                        out.annotate(0, "static_field[%d]", i);
81                        out.indent();
82                        previousIndex = annotateEncodedField(out, dexFile, reader, previousIndex);
83                        out.deindent();
84                    }
85                    out.deindent();
86                }
87
88                if (instanceFieldsSize > 0) {
89                    out.annotate(0, "instance_fields:");
90                    out.indent();
91                    previousIndex = 0;
92                    for (int i=0; i<instanceFieldsSize; i++) {
93                        out.annotate(0, "instance_field[%d]", i);
94                        out.indent();
95                        previousIndex = annotateEncodedField(out, dexFile, reader, previousIndex);
96                        out.deindent();
97                    }
98                    out.deindent();
99                }
100
101                if (directMethodsSize > 0) {
102                    out.annotate(0, "direct_methods:");
103                    out.indent();
104                    previousIndex = 0;
105                    for (int i=0; i<directMethodsSize; i++) {
106                        out.annotate(0, "direct_method[%d]", i);
107                        out.indent();
108                        previousIndex = annotateEncodedMethod(out, dexFile, reader, previousIndex);
109                        out.deindent();
110                    }
111                    out.deindent();
112                }
113
114                if (virtualMethodsSize > 0) {
115                    out.annotate(0, "virtual_methods:");
116                    out.indent();
117                    previousIndex = 0;
118                    for (int i=0; i<virtualMethodsSize; i++) {
119                        out.annotate(0, "virtual_method[%d]", i);
120                        out.indent();
121                        previousIndex = annotateEncodedMethod(out, dexFile, reader, previousIndex);
122                        out.deindent();
123                    }
124                    out.deindent();
125                }
126            }
127
128            private int annotateEncodedField(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile,
129                                             @Nonnull DexReader reader, int previousIndex) {
130                // large values may be used for the index delta, which cause the cumulative index to overflow upon
131                // addition, effectively allowing out of order entries.
132                int indexDelta = reader.readLargeUleb128();
133                int fieldIndex = previousIndex + indexDelta;
134                out.annotateTo(reader.getOffset(), "field_idx_diff = %d: %s", indexDelta,
135                        FieldIdItem.getReferenceAnnotation(dexFile, fieldIndex));
136
137                int accessFlags = reader.readSmallUleb128();
138                out.annotateTo(reader.getOffset(), "access_flags = 0x%x: %s", accessFlags,
139                        Joiner.on('|').join(AccessFlags.getAccessFlagsForField(accessFlags)));
140
141                return fieldIndex;
142            }
143
144            private int annotateEncodedMethod(@Nonnull AnnotatedBytes out, @Nonnull RawDexFile dexFile,
145                                              @Nonnull DexReader reader, int previousIndex) {
146                // large values may be used for the index delta, which cause the cumulative index to overflow upon
147                // addition, effectively allowing out of order entries.
148                int indexDelta = reader.readLargeUleb128();
149                int methodIndex = previousIndex + indexDelta;
150                out.annotateTo(reader.getOffset(), "method_idx_diff = %d: %s", indexDelta,
151                        MethodIdItem.getReferenceAnnotation(dexFile, methodIndex));
152
153                int accessFlags = reader.readSmallUleb128();
154                out.annotateTo(reader.getOffset(), "access_flags = 0x%x: %s", accessFlags,
155                        Joiner.on('|').join(AccessFlags.getAccessFlagsForMethod(accessFlags)));
156
157                int codeOffset = reader.readSmallUleb128();
158                if (codeOffset == 0) {
159                    out.annotateTo(reader.getOffset(), "code_off = code_item[NO_OFFSET]");
160                } else {
161                    out.annotateTo(reader.getOffset(), "code_off = code_item[0x%x]", codeOffset);
162                    addCodeItemIdentity(codeOffset, MethodIdItem.asString(dexFile, methodIndex));
163                }
164
165                return methodIndex;
166            }
167
168            private void addCodeItemIdentity(int codeItemOffset, String methodString) {
169                if (codeItemAnnotator != null) {
170                    codeItemAnnotator.setItemIdentity(codeItemOffset, methodString);
171                }
172            }
173        };
174    }
175}
176