1959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/* 2959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Copyright (C) 2014 The Android Open Source Project 3959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * 4959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Licensed under the Apache License, Version 2.0 (the "License"); 5959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * you may not use this file except in compliance with the License. 6959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * You may obtain a copy of the License at 7959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * 8959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * http://www.apache.org/licenses/LICENSE-2.0 9959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * 10959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Unless required by applicable law or agreed to in writing, software 11959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * distributed under the License is distributed on an "AS IS" BASIS, 12959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * See the License for the specific language governing permissions and 14959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * limitations under the License. 15959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 16959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 17959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepackage dexfuzz.rawdex; 18959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 19959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport dexfuzz.Log; 20959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 21959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.io.IOException; 22959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.ArrayList; 23959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.HashMap; 24959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.List; 25959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyleimport java.util.Map; 26959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 27959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle/** 28959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * This class allows the recording of both Offsettable items (that is, items that can be 29959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * referred to by an offset somewhere else in the file - RawDexObjects) and Offsets. 30959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * The idea in a nutshell is that for every Offsettable item we read, we remember 31959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * its original position in the file using a map, and the order in which the Offsettables were 32959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * written out. We also remember every Offset we read in, and its value. Then, after reading 33959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the whole file, we use the map to find the Offsettable it pointed at. 34959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Then, as we write out the file, for every Offsettable we write out, we record its new position, 35959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * using the order we collected earlier. For every Offset we write out, we look at its Offsettable 36959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * to see where it was written. If it hasn't been written yet, then we write out a blank value 37959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * for the time being, remember where that blank value was written, and put the Offset into a 38959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * table for patching once everything has been written out. 39959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * There are some variables (index_after_map_list, restore_point) used for remembering certain 40959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * points to jump forward and back to, because we cannot read and write the file out in exactly 41959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the same order. 42959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * TODO: Perhaps it makes more sense to just reorder the offsettable_table once it's been read, 43959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * in preparation for the order in which the file is written out? 44959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Finally, we provide methods for adding new Offsettable items into the right place in the order 45959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * table. 46959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 47959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kylepublic class OffsetTracker { 48959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 49959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * A map from the original offset in the input DEX file to 50959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the Offsettable it points to. (That Offsettable will contain 51959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the actual item, and later on the new offset for the item when 52959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the item is written out. 53959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 54959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private Map<Integer, Offsettable> offsettableMap; 55959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 56959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 57959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * A table of all Offsettables. We need to ensure we write out 58959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * all items in the same order we read them in, to make sure we update 59959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the Offsettable.new_position field with the correct value wrt to 60959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the original_position field. 61959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 62959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private List<Offsettable> offsettableTable; 63959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 64959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 65959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * A table of all offsets that is populated as we read in the DEX file. 66959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * As the end, we find the correct Offsettable for the Offset in the above 67959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * map, and associate them. 68959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 69959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private List<Offset> needsAssociationTable; 70959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 71959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 72959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * A table of all offsets that we could not write out an updated offset for 73959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * as we write out a DEX file. Will be checked after writing is complete, 74959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * to allow specific patching of each offset's location as at that point 75959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * all Offsettables will have been updated with their new position. 76959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 77959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private List<Offset> needsUpdateTable; 78959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 79959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 80959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Tracks how far we are through the offsettable_table as we write out the file. 81959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 82959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private int offsettableTableIdx; 83959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 84959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 85959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Because we write in a slightly different order to how we read 86959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * (why? to read, we read the header, then the map list, and then use the map 87959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * list to read everything else. 88959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * when we write, we write the header, and then we cannot write the map list 89959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * because we don't know where it will go yet, so we write everything else first) 90959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * so: we remember the position in the offsettable_table after we read the map list, 91959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * so we can skip there after we write out the header. 92959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 93959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private int indexAfterMapList; 94959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 95959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 96959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Related to index_after_map_list, this is the index we save when we're jumping back to 97959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * write the map list. 98959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 99959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private int restorePoint; 100959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 101959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 102959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Create a new OffsetTracker. Should persist between parsing a DEX file, and outputting 103959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the mutated DEX file. 104959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 105959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public OffsetTracker() { 106959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettableMap = new HashMap<Integer,Offsettable>(); 107959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettableTable = new ArrayList<Offsettable>(); 108959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle needsAssociationTable = new ArrayList<Offset>(); 109959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle needsUpdateTable = new ArrayList<Offset>(); 110959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 111959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 112959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 113959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Lookup an Item by the offset it had in the input DEX file. 114959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @param offset The offset in the input DEX file. 115959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @return The corresponding Item. 116959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 117959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public RawDexObject getItemByOffset(int offset) { 118959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return offsettableMap.get(offset).getItem(); 119959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 120959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 121959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 122959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * As Items are read in, they call this function once they have word-aligned the file pointer, 123959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * to record their position and themselves into an Offsettable object, that will be tracked. 124959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @param file Used for recording position into the new Offsettable. 125959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @param item Used for recording the relevant Item into the new Offsettable. 126959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 127959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void getNewOffsettable(DexRandomAccessFile file, RawDexObject item) throws IOException { 128959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable offsettable = new Offsettable(item, false); 129959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettable.setOriginalPosition((int) file.getFilePointer()); 130959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettableMap.put(offsettable.getOriginalPosition(), offsettable); 131959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettableTable.add(offsettable); 132959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 133959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 134959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 135959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * As Items read in Offsets, they call this function with the offset they originally 136959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * read from the file, to allow later association with an Offsettable. 137959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @param originalOffset The original offset read from the input DEX file. 138959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @return An Offset that will later be associated with an Offsettable. 139959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 140959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public Offset getNewOffset(int originalOffset) throws IOException { 141959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offset offset = new Offset(false); 142959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offset.setOriginalOffset(originalOffset); 143959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle needsAssociationTable.add(offset); 144959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return offset; 145959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 146959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 147959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 148959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Only MapItem should call this method, when the MapItem that points to the header 149959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * is read. 150959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 151959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public Offset getNewHeaderOffset(int originalOffset) throws IOException { 152959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offset offset = new Offset(true); 153959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offset.setOriginalOffset(originalOffset); 154959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle needsAssociationTable.add(offset); 155959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return offset; 156959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 157959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 158959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 159959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Call this after reading, to associate Offsets with Offsettables. 160959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 161959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void associateOffsets() { 162959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (Offset offset : needsAssociationTable) { 163959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offset.getOriginalOffset() == 0 && !(offset.pointsAtHeader())) { 164959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offset.setPointsAtNull(); 165959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 166959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offset.pointTo(offsettableMap.get(offset.getOriginalOffset())); 167959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (!offset.pointsToSomething()) { 168959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.error(String.format("Couldn't find original offset 0x%x!", 169959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offset.getOriginalOffset())); 170959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 171959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 172959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 173959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle needsAssociationTable.clear(); 174959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 175959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 176959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 177959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * As Items are written out into the output DEX file, this function is called 178959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * to update the next Offsettable with the file pointer's current position. 179959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * This should allow the tracking of new offset locations. 180959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * This also requires that reading and writing of all items happens in the same order 181959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * (with the exception of the map list, see above) 182959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @param file Used for recording the new position. 183959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 184959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void updatePositionOfNextOffsettable(DexRandomAccessFile file) throws IOException { 185959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offsettableTableIdx == offsettableTable.size()) { 186959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("Not all created Offsettable items have been added to the " 187959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle + "Offsettable Table!"); 188959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 189959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable offsettable = offsettableTable.get(offsettableTableIdx); 190959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettable.setNewPosition((int) file.getFilePointer()); 191959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettableTableIdx++; 192959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 193959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 194959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 195959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * As Items are written out, any writing out of an offset must call this function, passing 196959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * in the relevant offset. This function will write out the offset, if the associated 197959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Offsettable has been updated with its new position, or else will write out a null value, and 198959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * the Offset will be stored for writing after all Items have been written, and all 199959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Offsettables MUST have been updated. 200959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @param offset The offset received from getNewOffset(). 201959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @param file Used for writing out to the file. 202959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @param useUleb128 Whether or not the offset should be written in UINT or ULEB128 form. 203959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 204959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void tryToWriteOffset(Offset offset, DexRandomAccessFile file, boolean useUleb128) 205959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle throws IOException { 206959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (!offset.isNewOffset() && (!offset.pointsToSomething())) { 207959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (useUleb128) { 208959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle file.writeUleb128(0); 209959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 210959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle file.writeUInt(0); 211959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 212959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return; 213959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 214959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 215959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offset.readyForWriting()) { 216959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (useUleb128) { 217959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle file.writeUleb128(offset.getNewPositionOfItem()); 218959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 219959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle file.writeUInt(offset.getNewPositionOfItem()); 220959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 221959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 222959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offset.setOutputLocation((int) file.getFilePointer()); 223959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (useUleb128) { 224959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle file.writeLargestUleb128(offset.getOriginalOffset()); 225959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offset.setUsesUleb128(); 226959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 227959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle file.writeUInt(offset.getOriginalOffset()); 228959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 229959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle needsUpdateTable.add(offset); 230959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 231959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 232959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 233959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 234959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * This is called after all writing has finished, to write out any Offsets 235959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * that could not be written out during the original writing phase, because their 236959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * associated Offsettables hadn't had their new positions calculated yet. 237959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * @param file Used for writing out to the file. 238959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 239959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void updateOffsets(DexRandomAccessFile file) throws IOException { 240959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offsettableTableIdx != offsettableTable.size()) { 241959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("Being asked to update dangling offsets but the " 242959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle + "correct number of offsettables has not been written out!"); 243959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 244959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (Offset offset : needsUpdateTable) { 245959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle file.seek(offset.getOutputLocation()); 246959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offset.usesUleb128()) { 247959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle file.writeLargestUleb128(offset.getNewPositionOfItem()); 248959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 249959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle file.writeUInt(offset.getNewPositionOfItem()); 250959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 251959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 252959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle needsUpdateTable.clear(); 253959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 254959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 255959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 256959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Called after writing out the header, to skip to after the map list. 257959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 258959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void skipToAfterMapList() { 259959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettableTableIdx = indexAfterMapList; 260959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 261959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 262959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 263959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Called once the map list needs to be written out, to set the 264959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * offsettable table index back to the right place. 265959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 266959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void goBackToMapList() { 267959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle restorePoint = offsettableTableIdx; 268959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettableTableIdx = (indexAfterMapList - 1); 269959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 270959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 271959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 272959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Called once the map list has been written out, to set the 273959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * offsettable table index back to where it was before. 274959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 275959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void goBackToPreviousPoint() { 276959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offsettableTableIdx != indexAfterMapList) { 277959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("Being asked to go to the point before the MapList was written out," 278959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle + " but we're not in the right place."); 279959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 280959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettableTableIdx = restorePoint; 281959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 282959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 283959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 284959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Called after reading in the map list, to remember the point to be skipped 285959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * to later. 286959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 287959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public void rememberPointAfterMapList() { 288959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle indexAfterMapList = offsettableTable.size(); 289959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 290959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 291959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private void updateHeaderOffsetIfValid(Offset offset, Offsettable previousFirst, 292959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable newFirst, String offsetName) { 293959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offset.pointsToThisOffsettable(previousFirst)) { 294959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offset.pointToNew(newFirst); 295959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else { 296959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("Header " + offsetName + " offset not pointing at first element?"); 297959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 298959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 299959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 300959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private void addTypeListsToMapFile(RawDexFile rawDexFile, Offsettable typeListOffsettable) { 301959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Create a MapItem for the TypeLists 302959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MapItem typeListMapItem = new MapItem(); 303959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle typeListMapItem.offset = new Offset(false); 304959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle typeListMapItem.offset.pointToNew(typeListOffsettable); 305959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle typeListMapItem.type = MapItem.TYPE_TYPE_LIST; 306959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle typeListMapItem.size = 1; 307959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 308959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Insert into the MapList. 309959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // (first, find the MapItem that points to StringDataItems...) 310959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int idx = 0; 311959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MapItem mapItem : rawDexFile.mapList.mapItems) { 312959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (mapItem.type == MapItem.TYPE_STRING_DATA_ITEM) { 313959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 314959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 315959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle idx++; 316959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 317959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // (now insert the TypeList MapItem just before the StringDataItem one...) 318959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle rawDexFile.mapList.mapItems.add(idx, typeListMapItem); 319959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 320959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 321959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private void addFieldIdsToHeaderAndMapFile(RawDexFile rawDexFile, 322959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable fieldOffsettable) { 323959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Add the field IDs to the header. 324959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle rawDexFile.header.fieldIdsOff.unsetNullAndPointTo(fieldOffsettable); 325959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle rawDexFile.header.fieldIdsSize = 1; 326959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 327959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Create a MapItem for the field IDs. 328959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle MapItem fieldMapItem = new MapItem(); 329959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle fieldMapItem.offset = new Offset(false); 330959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle fieldMapItem.offset.pointToNew(fieldOffsettable); 331959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle fieldMapItem.type = MapItem.TYPE_FIELD_ID_ITEM; 332959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle fieldMapItem.size = 1; 333959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 334959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Insert into the MapList. 335959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // (first, find the MapItem that points to MethodIdItems...) 336959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int idx = 0; 337959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MapItem mapItem : rawDexFile.mapList.mapItems) { 338959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (mapItem.type == MapItem.TYPE_METHOD_ID_ITEM) { 339959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 340959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 341959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle idx++; 342959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 343959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // (now insert the FieldIdItem MapItem just before the MethodIdItem one...) 344959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle rawDexFile.mapList.mapItems.add(idx, fieldMapItem); 345959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 346959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 347959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 348959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private void updateOffsetsInHeaderAndMapFile(RawDexFile rawDexFile, 349959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable newFirstOffsettable) { 350959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable prevFirstOffsettable = null; 351959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int i = 0; i < offsettableTable.size(); i++) { 352959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offsettableTable.get(i) == newFirstOffsettable) { 353959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle prevFirstOffsettable = offsettableTable.get(i + 1); 354959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle break; 355959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 356959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 357959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (prevFirstOffsettable == null) { 358959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("When calling updateMapListOffsets, could not find new " 359959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle + "first offsettable?"); 360959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 361959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 362959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Based on the type of the item we just added, check the relevant Offset in the header 363959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // and if it pointed at the prev_first_offsettable, make it point at the new one. 364959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // NB: if it isn't pointing at the prev one, something is wrong. 365959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle HeaderItem header = rawDexFile.header; 366959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (newFirstOffsettable.getItem() instanceof StringIdItem) { 367959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateHeaderOffsetIfValid(header.stringIdsOff, prevFirstOffsettable, 368959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle newFirstOffsettable, "StringID"); 369959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (newFirstOffsettable.getItem() instanceof TypeIdItem) { 370959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateHeaderOffsetIfValid(header.typeIdsOff, prevFirstOffsettable, 371959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle newFirstOffsettable, "TypeID"); 372959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (newFirstOffsettable.getItem() instanceof ProtoIdItem) { 373959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateHeaderOffsetIfValid(header.protoIdsOff, prevFirstOffsettable, 374959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle newFirstOffsettable, "ProtoID"); 375959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (newFirstOffsettable.getItem() instanceof FieldIdItem) { 376959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateHeaderOffsetIfValid(header.fieldIdsOff, prevFirstOffsettable, 377959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle newFirstOffsettable, "FieldID"); 378959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (newFirstOffsettable.getItem() instanceof MethodIdItem) { 379959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateHeaderOffsetIfValid(header.methodIdsOff, prevFirstOffsettable, 380959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle newFirstOffsettable, "MethodID"); 381959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } else if (newFirstOffsettable.getItem() instanceof ClassDefItem) { 382959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateHeaderOffsetIfValid(header.classDefsOff, prevFirstOffsettable, 383959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle newFirstOffsettable, "ClassDef"); 384959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 385959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 386959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // Now iterate through the MapList's MapItems, and see if their Offsets pointed at the 387959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // prev_first_offsettable, and if so, make them now point at the new_first_offsettable. 388959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (MapItem mapItem : rawDexFile.mapList.mapItems) { 389959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (mapItem.offset.pointsToThisOffsettable(prevFirstOffsettable)) { 390959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.info("Updating offset in MapItem (type: " + mapItem.type + ") after " 391959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle + "we called insertNewOffsettableAsFirstOfType()"); 392959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle mapItem.offset.pointToNew(newFirstOffsettable); 393959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 394959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 395959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 396959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 397959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private void insertOffsettableAt(int idx, Offsettable offsettable) { 398959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle offsettableTable.add(idx, offsettable); 399959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (indexAfterMapList > idx) { 400959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle indexAfterMapList++; 401959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 402959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (restorePoint > idx) { 403959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle restorePoint++; 404959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 405959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 406959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 407959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 408959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * If we're creating our first TypeList, then IdCreator has to call this method to 409959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * ensure it gets put into the correct place in the offsettable table. 410959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * This assumes TypeLists always come before StringDatas. 411959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 412959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public Offsettable insertNewOffsettableAsFirstEverTypeList(RawDexObject item, 413959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle RawDexFile rawDexFile) { 414959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // We find the first StringDataItem, the type lists will come before this. 415959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.info("Calling insertNewOffsettableAsFirstEverTypeList()"); 416959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int i = 0; i < offsettableTable.size(); i++) { 417959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offsettableTable.get(i).getItem() instanceof StringDataItem) { 418959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable offsettable = new Offsettable(item, true); 419959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle insertOffsettableAt(i, offsettable); 420959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle addTypeListsToMapFile(rawDexFile, offsettable); 421959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return offsettable; 422959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 423959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 424959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("Could not find any StringDataItems to insert the type list before."); 425959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return null; 426959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 427959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 428959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 429959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * If we're creating our first FieldId, then IdCreator has to call this method to 430959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * ensure it gets put into the correct place in the offsettable table. 431959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * This assumes FieldIds always come before MethodIds. 432959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 433959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public Offsettable insertNewOffsettableAsFirstEverField(RawDexObject item, 434959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle RawDexFile rawDexFile) { 435959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle // We find the first MethodIdItem, the fields will come before this. 436959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.info("Calling insertNewOffsettableAsFirstEverField()"); 437959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int i = 0; i < offsettableTable.size(); i++) { 438959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offsettableTable.get(i).getItem() instanceof MethodIdItem) { 439959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable offsettable = new Offsettable(item, true); 440959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle insertOffsettableAt(i, offsettable); 441959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle addFieldIdsToHeaderAndMapFile(rawDexFile, offsettable); 442959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return offsettable; 443959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 444959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 445959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("Could not find any MethodIdItems to insert the field before."); 446959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return null; 447959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 448959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 449959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 450959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * If we're creating a new Item (such as FieldId, MethodId) that is placed into the 451959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * first position of the relevant ID table, then IdCreator has to call this method to 452959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * ensure it gets put into the correct place in the offsettable table. 453959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 454959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public Offsettable insertNewOffsettableAsFirstOfType(RawDexObject item, 455959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle RawDexFile rawDexFile) { 456959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Calling insertNewOffsettableAsFirstOfType()"); 457959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int index = getOffsettableIndexForFirstItemType(item); 458959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (index == -1) { 459959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("Could not find any object of class: " + item.getClass()); 460959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 461959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable offsettable = new Offsettable(item, true); 462959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle insertOffsettableAt(index, offsettable); 463959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle updateOffsetsInHeaderAndMapFile(rawDexFile, offsettable); 464959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return offsettable; 465959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 466959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 467959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 468959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * IdCreator has to call this method when it creates a new IdItem, to make sure it 469959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * gets put into the correct place in the offsettable table. IdCreator should 470959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * provide the IdItem that should come before this new IdItem. 471959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 472959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public Offsettable insertNewOffsettableAfter(RawDexObject item, RawDexObject itemBefore) { 473959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.debug("Calling insertNewOffsettableAfter()"); 474959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle int index = getOffsettableIndexForItem(itemBefore); 475959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (index == -1) { 476959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Log.errorAndQuit("Did not find specified 'after' object in offsettable table."); 477959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 478959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Offsettable offsettable = new Offsettable(item, true); 479959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle insertOffsettableAt(index + 1, offsettable); 480959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return offsettable; 481959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 482959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 483959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private int getOffsettableIndexForFirstItemType(RawDexObject item) { 484959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle Class<?> itemClass = item.getClass(); 485959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int i = 0; i < offsettableTable.size(); i++) { 486959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offsettableTable.get(i).getItem().getClass().equals(itemClass)) { 487959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return i; 488959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 489959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 490959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return -1; 491959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 492959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 493959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle private int getOffsettableIndexForItem(RawDexObject item) { 494959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int i = 0; i < offsettableTable.size(); i++) { 495959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offsettableTable.get(i).getItem() == item) { 496959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return i; 497959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 498959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 499959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return -1; 500959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 501959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle 502959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle /** 503959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle * Given a RawDexObject, get the Offsettable that contains it. 504959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle */ 505959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle public Offsettable getOffsettableForItem(RawDexObject item) { 506959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle for (int i = 0; i < offsettableTable.size(); i++) { 507959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle if (offsettableTable.get(i).getItem() == item) { 508959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return offsettableTable.get(i); 509959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 510959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 511959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle return null; 512959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle } 513959ffdf65f280ee90b7944a8dd610564e7f99e69Stephen Kyle} 514