• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013, Google LLC
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google LLC nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 package com.android.tools.smali.dexlib2.dexbacked.raw.util;
32 
33 import com.android.tools.smali.dexlib2.dexbacked.raw.AnnotationDirectoryItem;
34 import com.android.tools.smali.dexlib2.dexbacked.raw.AnnotationItem;
35 import com.android.tools.smali.dexlib2.dexbacked.raw.AnnotationSetItem;
36 import com.android.tools.smali.dexlib2.dexbacked.raw.AnnotationSetRefList;
37 import com.android.tools.smali.dexlib2.dexbacked.raw.CallSiteIdItem;
38 import com.android.tools.smali.dexlib2.dexbacked.raw.CdexDebugOffsetTable;
39 import com.android.tools.smali.dexlib2.dexbacked.raw.ClassDataItem;
40 import com.android.tools.smali.dexlib2.dexbacked.raw.ClassDefItem;
41 import com.android.tools.smali.dexlib2.dexbacked.raw.CodeItem;
42 import com.android.tools.smali.dexlib2.dexbacked.raw.DebugInfoItem;
43 import com.android.tools.smali.dexlib2.dexbacked.raw.EncodedArrayItem;
44 import com.android.tools.smali.dexlib2.dexbacked.raw.FieldIdItem;
45 import com.android.tools.smali.dexlib2.dexbacked.raw.HeaderItem;
46 import com.android.tools.smali.dexlib2.dexbacked.raw.HiddenApiClassDataItem;
47 import com.android.tools.smali.dexlib2.dexbacked.raw.ItemType;
48 import com.android.tools.smali.dexlib2.dexbacked.raw.MapItem;
49 import com.android.tools.smali.dexlib2.dexbacked.raw.MethodHandleItem;
50 import com.android.tools.smali.dexlib2.dexbacked.raw.MethodIdItem;
51 import com.android.tools.smali.dexlib2.dexbacked.raw.ProtoIdItem;
52 import com.android.tools.smali.dexlib2.dexbacked.raw.SectionAnnotator;
53 import com.android.tools.smali.dexlib2.dexbacked.raw.StringDataItem;
54 import com.android.tools.smali.dexlib2.dexbacked.raw.StringIdItem;
55 import com.android.tools.smali.dexlib2.dexbacked.raw.TypeIdItem;
56 import com.android.tools.smali.dexlib2.dexbacked.raw.TypeListItem;
57 import com.android.tools.smali.dexlib2.util.AnnotatedBytes;
58 
59 import com.android.tools.smali.dexlib2.dexbacked.CDexBackedDexFile;
60 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
61 
62 import javax.annotation.Nonnull;
63 import javax.annotation.Nullable;
64 import java.io.IOException;
65 import java.io.Writer;
66 import java.util.Arrays;
67 import java.util.Comparator;
68 import java.util.HashMap;
69 import java.util.List;
70 import java.util.Map;
71 
72 public class DexAnnotator extends AnnotatedBytes {
73     @Nonnull public final DexBackedDexFile dexFile;
74 
75     private final Map<Integer, SectionAnnotator> annotators = new HashMap<>();
76     private static final Map<Integer, Integer> sectionAnnotationOrder = new HashMap<>();
77 
78     static {
79         int[] sectionOrder = new int[] {
80                 ItemType.MAP_LIST,
81 
82                 ItemType.HEADER_ITEM,
83                 ItemType.STRING_ID_ITEM,
84                 ItemType.TYPE_ID_ITEM,
85                 ItemType.PROTO_ID_ITEM,
86                 ItemType.FIELD_ID_ITEM,
87                 ItemType.METHOD_ID_ITEM,
88                 ItemType.CALL_SITE_ID_ITEM,
89                 ItemType.METHOD_HANDLE_ITEM,
90 
91                 // these need to be ordered like this, so the item identities can be propagated
92                 ItemType.CLASS_DEF_ITEM,
93                 ItemType.CLASS_DATA_ITEM,
94                 ItemType.CODE_ITEM,
95                 ItemType.DEBUG_INFO_ITEM,
96 
97                 ItemType.TYPE_LIST,
98                 ItemType.ANNOTATION_SET_REF_LIST,
99                 ItemType.ANNOTATION_SET_ITEM,
100                 ItemType.STRING_DATA_ITEM,
101                 ItemType.ANNOTATION_ITEM,
102                 ItemType.ENCODED_ARRAY_ITEM,
103                 ItemType.ANNOTATION_DIRECTORY_ITEM,
104 
105                 ItemType.HIDDENAPI_CLASS_DATA_ITEM
106         };
107 
108         for (int i=0; i<sectionOrder.length; i++) {
sectionAnnotationOrder.put(sectionOrder[i], i)109             sectionAnnotationOrder.put(sectionOrder[i], i);
110         }
111     }
112 
DexAnnotator(@onnull DexBackedDexFile dexFile, int width)113     public DexAnnotator(@Nonnull DexBackedDexFile dexFile, int width) {
114         super(width);
115 
116         this.dexFile = dexFile;
117 
118         for (MapItem mapItem: dexFile.getMapItems()) {
119             switch (mapItem.getType()) {
120                 case ItemType.HEADER_ITEM:
121                     annotators.put(mapItem.getType(), HeaderItem.makeAnnotator(this, mapItem));
122                     break;
123                 case ItemType.STRING_ID_ITEM:
124                     annotators.put(mapItem.getType(), StringIdItem.makeAnnotator(this, mapItem));
125                     break;
126                 case ItemType.TYPE_ID_ITEM:
127                     annotators.put(mapItem.getType(), TypeIdItem.makeAnnotator(this, mapItem));
128                     break;
129                 case ItemType.PROTO_ID_ITEM:
130                     annotators.put(mapItem.getType(), ProtoIdItem.makeAnnotator(this, mapItem));
131                     break;
132                 case ItemType.FIELD_ID_ITEM:
133                     annotators.put(mapItem.getType(), FieldIdItem.makeAnnotator(this, mapItem));
134                     break;
135                 case ItemType.METHOD_ID_ITEM:
136                     annotators.put(mapItem.getType(), MethodIdItem.makeAnnotator(this, mapItem));
137                     break;
138                 case ItemType.CLASS_DEF_ITEM:
139                     annotators.put(mapItem.getType(), ClassDefItem.makeAnnotator(this, mapItem));
140                     break;
141                 case ItemType.MAP_LIST:
142                     annotators.put(mapItem.getType(), MapItem.makeAnnotator(this, mapItem));
143                     break;
144                 case ItemType.TYPE_LIST:
145                     annotators.put(mapItem.getType(), TypeListItem.makeAnnotator(this, mapItem));
146                     break;
147                 case ItemType.ANNOTATION_SET_REF_LIST:
148                     annotators.put(mapItem.getType(), AnnotationSetRefList.makeAnnotator(this, mapItem));
149                     break;
150                 case ItemType.ANNOTATION_SET_ITEM:
151                     annotators.put(mapItem.getType(), AnnotationSetItem.makeAnnotator(this, mapItem));
152                     break;
153                 case ItemType.CLASS_DATA_ITEM:
154                     annotators.put(mapItem.getType(), ClassDataItem.makeAnnotator(this, mapItem));
155                     break;
156                 case ItemType.CODE_ITEM:
157                     annotators.put(mapItem.getType(), CodeItem.makeAnnotator(this, mapItem));
158                     break;
159                 case ItemType.STRING_DATA_ITEM:
160                     annotators.put(mapItem.getType(), StringDataItem.makeAnnotator(this, mapItem));
161                     break;
162                 case ItemType.DEBUG_INFO_ITEM:
163                     annotators.put(mapItem.getType(), DebugInfoItem.makeAnnotator(this, mapItem));
164                     break;
165                 case ItemType.ANNOTATION_ITEM:
166                     annotators.put(mapItem.getType(), AnnotationItem.makeAnnotator(this, mapItem));
167                     break;
168                 case ItemType.ENCODED_ARRAY_ITEM:
169                     annotators.put(mapItem.getType(), EncodedArrayItem.makeAnnotator(this, mapItem));
170                     break;
171                 case ItemType.ANNOTATION_DIRECTORY_ITEM:
172                     annotators.put(mapItem.getType(), AnnotationDirectoryItem.makeAnnotator(this, mapItem));
173                     break;
174                 case ItemType.CALL_SITE_ID_ITEM:
175                     annotators.put(mapItem.getType(), CallSiteIdItem.makeAnnotator(this, mapItem));
176                     break;
177                 case ItemType.METHOD_HANDLE_ITEM:
178                     annotators.put(mapItem.getType(), MethodHandleItem.makeAnnotator(this, mapItem));
179                     break;
180                 case ItemType.HIDDENAPI_CLASS_DATA_ITEM:
181                     annotators.put(mapItem.getType(), HiddenApiClassDataItem.makeAnnotator(this, mapItem));
182                     break;
183                 default:
184                     throw new RuntimeException(String.format("Unrecognized item type: 0x%x", mapItem.getType()));
185             }
186         }
187     }
188 
writeAnnotations(Writer out)189     public void writeAnnotations(Writer out) throws IOException {
190         List<MapItem> mapItems = dexFile.getMapItems();
191         // sort the map items based on the order defined by sectionAnnotationOrder
192         Comparator<MapItem> comparator = new Comparator<MapItem>() {
193             @Override public int compare(MapItem o1, MapItem o2) {
194                 return Integer.compare(sectionAnnotationOrder.get(o1.getType()), sectionAnnotationOrder.get(o2.getType()));
195             }
196         };
197 
198         MapItem[] mapItemsArray = mapItems.toArray(new MapItem[mapItems.size()]);
199         Arrays.sort(mapItemsArray, comparator);
200 
201         try {
202             // Need to annotate the debug info offset table first, to propagate the debug info identities
203             if (dexFile instanceof CDexBackedDexFile) {
204                 moveTo(dexFile.getBaseDataOffset() + ((CDexBackedDexFile) dexFile).getDebugInfoOffsetsPos());
205                 CdexDebugOffsetTable.annotate(this, dexFile.getBuffer());
206             }
207 
208             for (MapItem mapItem: mapItemsArray) {
209                 try {
210                     SectionAnnotator annotator = annotators.get(mapItem.getType());
211                     annotator.annotateSection(this);
212                 } catch (Exception ex) {
213                     System.err.println(String.format("There was an error while dumping the %s section",
214                             ItemType.getItemTypeName(mapItem.getType())));
215                     ex.printStackTrace(System.err);
216                 }
217             }
218         } finally {
219             writeAnnotations(out, dexFile.getBuffer().getBuf(), dexFile.getBuffer().getBaseOffset());
220         }
221     }
222 
223     @Nullable
getAnnotator(int itemType)224     public SectionAnnotator getAnnotator(int itemType) {
225         return annotators.get(itemType);
226     }
227 }
228