Don't load the instructions in a code item when loading the BOOTCLASSPATH dex files

git-svn-id: https://smali.googlecode.com/svn/trunk@623 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com
2010-02-14 20:04:20 +00:00
parent 1ed567427b
commit db385ec3fd
4 changed files with 98 additions and 54 deletions

View File

@ -58,7 +58,7 @@ public class ClassPath {
DexFile dexFile;
try {
dexFile = new DexFile(file);
dexFile = new DexFile(file, false, true);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading ClassPath entry \"" +
bootClassPathEntry + "\".");

View File

@ -148,57 +148,80 @@ public class CodeItem extends Item<CodeItem> {
if (this.debugInfo != null) {
this.debugInfo.setParent(this);
}
int instructionCount = in.readInt();
final ArrayList<Instruction> instructionList = new ArrayList<Instruction>();
if (dexFile.skipInstructions()) {
in.skipBytes(instructionCount * 2);
byte[] encodedInstructions = in.readBytes(instructionCount * 2);
InstructionIterator.IterateInstructions(dexFile, encodedInstructions,
new InstructionIterator.ProcessInstructionDelegate() {
public void ProcessInstruction(int codeAddress, Instruction instruction) {
instructionList.add(instruction);
if (triesCount > 0) {
in.alignTo(4);
in.skipBytes(8 * triesCount);
int handlerCount = in.readUnsignedLeb128();
for (int i=0; i<handlerCount; i++) {
int size = in.readSignedLeb128();
int absSize = Math.abs(size);
for (int j=0; j<absSize; j++) {
in.readUnsignedLeb128();
in.readUnsignedLeb128();
}
if (size <= 0) {
in.readUnsignedLeb128();
}
});
this.instructions = new Instruction[instructionList.size()];
instructionList.toArray(instructions);
if (triesCount > 0) {
in.alignTo(4);
//we need to read in the catch handlers first, so save the offset to the try items for future reference
int triesOffset = in.getCursor();
in.setCursor(triesOffset + 8 * triesCount);
//read in the encoded catch handlers
int encodedHandlerStart = in.getCursor();
int handlerCount = in.readUnsignedLeb128();
SparseArray<EncodedCatchHandler> handlerMap = new SparseArray<EncodedCatchHandler>(handlerCount);
encodedCatchHandlers = new EncodedCatchHandler[handlerCount];
for (int i=0; i<handlerCount; i++) {
try {
int position = in.getCursor() - encodedHandlerStart;
encodedCatchHandlers[i] = new EncodedCatchHandler(dexFile, in);
handlerMap.append(position, encodedCatchHandlers[i]);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading EncodedCatchHandler at index " + i);
}
}
int codeItemEnd = in.getCursor();
} else {
final ArrayList<Instruction> instructionList = new ArrayList<Instruction>();
//now go back and read the tries
in.setCursor(triesOffset);
tries = new TryItem[triesCount];
for (int i=0; i<triesCount; i++) {
try {
tries[i] = new TryItem(in, handlerMap);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading TryItem at index " + i);
byte[] encodedInstructions = in.readBytes(instructionCount * 2);
InstructionIterator.IterateInstructions(dexFile, encodedInstructions,
new InstructionIterator.ProcessInstructionDelegate() {
public void ProcessInstruction(int codeAddress, Instruction instruction) {
instructionList.add(instruction);
}
});
this.instructions = new Instruction[instructionList.size()];
instructionList.toArray(instructions);
if (triesCount > 0) {
in.alignTo(4);
//we need to read in the catch handlers first, so save the offset to the try items for future reference
int triesOffset = in.getCursor();
in.setCursor(triesOffset + 8 * triesCount);
//read in the encoded catch handlers
int encodedHandlerStart = in.getCursor();
int handlerCount = in.readUnsignedLeb128();
SparseArray<EncodedCatchHandler> handlerMap = new SparseArray<EncodedCatchHandler>(handlerCount);
encodedCatchHandlers = new EncodedCatchHandler[handlerCount];
for (int i=0; i<handlerCount; i++) {
try {
int position = in.getCursor() - encodedHandlerStart;
encodedCatchHandlers[i] = new EncodedCatchHandler(dexFile, in);
handlerMap.append(position, encodedCatchHandlers[i]);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading EncodedCatchHandler at index " + i);
}
}
}
int codeItemEnd = in.getCursor();
//and now back to the end of the code item
in.setCursor(codeItemEnd);
//now go back and read the tries
in.setCursor(triesOffset);
tries = new TryItem[triesCount];
for (int i=0; i<triesCount; i++) {
try {
tries[i] = new TryItem(in, handlerMap);
} catch (Exception ex) {
throw ExceptionWithContext.withContext(ex, "Error while reading TryItem at index " + i);
}
}
//and now back to the end of the code item
in.setCursor(codeItemEnd);
}
}
}
@ -867,7 +890,7 @@ public class CodeItem extends Item<CodeItem> {
/**
* @return the "Catch All" handler address for this <code>EncodedCatchHandler</code>, or -1 if there
* is no "Catch All" handler
* is no "Catch All" handler
*/
public int getCatchAllHandlerAddress() {
return catchAllHandlerAddress;

View File

@ -30,7 +30,7 @@ package org.jf.dexlib;
import org.jf.dexlib.Util.*;
import org.jf.dexlib.*;
import org.jf.dexlib.Item;
import org.jf.dexlib.Item;
import org.jf.dexlib.StringDataItem;
import java.io.*;
@ -139,6 +139,13 @@ public class DexFile
*/
private final boolean preserveSignedRegisters;
/**
* When true, any instructions in a code item are skipped over instead of being read in. This is useful when
* you only need the information about the classes and their methods, for example, when loading the BOOTCLASSPATH
* jars in order to analyze a dex file
*/
private final boolean skipInstructions;
/**
* When true, this prevents any sorting of the items during placement of the dex file. This
* should *only* be set to true when this dex file was read in from an existing (valid) dex file,
@ -184,11 +191,13 @@ public class DexFile
/**
* A private constructor containing common code to initialize the section maps and lists
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
* @param skipInstructions If true, skip the instructions in any code item.
* that are signed, so they will be written in the same format. See
* <code>getPreserveSignedRegisters()</code>
*/
private DexFile(boolean preserveSignedRegisters) {
private DexFile(boolean preserveSignedRegisters, boolean skipInstructions) {
this.preserveSignedRegisters = preserveSignedRegisters;
this.skipInstructions = skipInstructions;
sectionsByType = new Section[] {
StringIdsSection,
@ -242,7 +251,7 @@ public class DexFile
*/
public DexFile(String file)
throws IOException {
this(new File(file), true);
this(new File(file), true, false);
}
/**
@ -252,12 +261,13 @@ public class DexFile
* @param file The dex file to read in
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
* that are signed, so they will be written in the same format. See
* @param skipInstructions If true, skip the instructions in any code item.
* <code>getPreserveSignedRegisters()</code>
* @throws IOException if an IOException occurs
*/
public DexFile(String file, boolean preserveSignedRegisters)
public DexFile(String file, boolean preserveSignedRegisters, boolean skipInstructions)
throws IOException {
this(new File(file), preserveSignedRegisters);
this(new File(file), preserveSignedRegisters, skipInstructions);
}
/**
@ -267,7 +277,7 @@ public class DexFile
*/
public DexFile(File file)
throws IOException {
this(file, true);
this(file, true, false);
}
/**
@ -277,12 +287,13 @@ public class DexFile
* @param file The dex file to read in
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
* that are signed, so they will be written in the same format.
* @param skipInstructions If true, skip the instructions in any code item.
* @see #getPreserveSignedRegisters
* @throws IOException if an IOException occurs
*/
public DexFile(File file, boolean preserveSignedRegisters)
public DexFile(File file, boolean preserveSignedRegisters, boolean skipInstructions)
throws IOException {
this(preserveSignedRegisters);
this(preserveSignedRegisters, skipInstructions);
long fileLength;
byte[] magic = FileUtils.readFile(file, 0, 8);
@ -415,7 +426,7 @@ public class DexFile
* the <code>Section.intern()</code> method of <code>ClassDefsSection</code>
*/
public DexFile() {
this(true);
this(true, false);
}
/**
@ -457,6 +468,16 @@ public class DexFile
return preserveSignedRegisters;
}
/**
* Get a boolean value indicating whether to skip any instructions in a code item while reading in the dex file.
* This is useful when you only need the information about the classes and their methods, for example, when
* loading the BOOTCLASSPATH jars in order to analyze a dex file
* @return a boolean value indicating whether to skip any instructions in a code item
*/
public boolean skipInstructions() {
return skipInstructions;
}
/**
* Get a boolean value indicating whether all items should be placed into a
* (possibly arbitrary) "canonical" ordering. If false, then only the items