DumpFields.java revision b2ce899471be1c136aa13d502e885585fa59d460
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.analysis; 33 34import com.google.common.base.Splitter; 35import com.google.common.collect.Lists; 36import org.apache.commons.cli.*; 37import org.jf.dexlib2.DexFileFactory; 38import org.jf.dexlib2.dexbacked.DexBackedDexFile; 39import org.jf.dexlib2.iface.ClassDef; 40import org.jf.dexlib2.iface.Field; 41import org.jf.dexlib2.iface.Method; 42import org.jf.dexlib2.iface.reference.FieldReference; 43import org.jf.util.ConsoleUtil; 44import org.jf.util.SparseArray; 45 46import java.io.File; 47import java.io.FileOutputStream; 48import java.io.IOException; 49import java.util.ArrayList; 50 51public class DumpFields { 52 private static final Options options; 53 54 static { 55 options = new Options(); 56 buildOptions(); 57 } 58 59 public static void main(String[] args) { 60 CommandLineParser parser = new PosixParser(); 61 CommandLine commandLine; 62 63 try { 64 commandLine = parser.parse(options, args); 65 } catch (ParseException ex) { 66 usage(); 67 return; 68 } 69 70 String[] remainingArgs = commandLine.getArgs(); 71 72 Option[] parsedOptions = commandLine.getOptions(); 73 ArrayList<String> bootClassPathDirs = Lists.newArrayList(); 74 String outFile = "fields.txt"; 75 int apiLevel = 15; 76 77 for (int i=0; i<parsedOptions.length; i++) { 78 Option option = parsedOptions[i]; 79 String opt = option.getOpt(); 80 81 switch (opt.charAt(0)) { 82 case 'd': 83 bootClassPathDirs.add(option.getValue()); 84 break; 85 case 'o': 86 outFile = option.getValue(); 87 break; 88 case 'a': 89 apiLevel = Integer.parseInt(commandLine.getOptionValue("a")); 90 break; 91 default: 92 assert false; 93 } 94 } 95 96 if (remainingArgs.length != 1) { 97 usage(); 98 return; 99 } 100 101 String inputDexFileName = remainingArgs[0]; 102 103 File dexFileFile = new File(inputDexFileName); 104 if (!dexFileFile.exists()) { 105 System.err.println("Can't find the file " + inputDexFileName); 106 System.exit(1); 107 } 108 109 try { 110 DexBackedDexFile dexFile = DexFileFactory.loadDexFile(dexFileFile, apiLevel); 111 Iterable<String> bootClassPaths = Splitter.on(":").split("core.jar:ext.jar:framework.jar:android.policy.jar:services.jar"); 112 ClassPath classPath = ClassPath.fromClassPath(bootClassPathDirs, bootClassPaths, dexFile, apiLevel); 113 FileOutputStream outStream = new FileOutputStream(outFile); 114 115 for (ClassDef classDef: dexFile.getClasses()) { 116 ClassProto classProto = (ClassProto) classPath.getClass(classDef); 117 SparseArray<FieldReference> fields = classProto.getInstanceFields(); 118 String className = "Class " + classDef.getType() + " : " + fields.size() + " instance fields\n"; 119 outStream.write(className.getBytes()); 120 for (int i=0;i<fields.size();i++) { 121 String field = fields.keyAt(i) + ":" + fields.valueAt(i).getType() + " " + fields.valueAt(i).getName() + "\n"; 122 outStream.write(field.getBytes()); 123 } 124 outStream.write("\n".getBytes()); 125 } 126 outStream.close(); 127 } catch (IOException ex) { 128 System.out.println("IOException thrown when trying to open a dex file or write out vtables: " + ex); 129 } 130 131 } 132 133 /** 134 * Prints the usage message. 135 */ 136 private static void usage() { 137 int consoleWidth = ConsoleUtil.getConsoleWidth(); 138 if (consoleWidth <= 0) { 139 consoleWidth = 80; 140 } 141 142 System.out.println("java -cp baksmali.jar org.jf.dexlib2.analysis.DumpFields -d path/to/jar/files <dex-file>"); 143 } 144 145 private static void buildOptions() { 146 Option classPathDirOption = OptionBuilder.withLongOpt("bootclasspath-dir") 147 .withDescription("the base folder to look for the bootclasspath files in. Defaults to the current " + 148 "directory") 149 .hasArg() 150 .withArgName("DIR") 151 .create("d"); 152 153 Option outputFileOption = OptionBuilder.withLongOpt("out-file") 154 .withDescription("output file") 155 .hasArg() 156 .withArgName("FILE") 157 .create("o"); 158 159 Option apiLevelOption = OptionBuilder.withLongOpt("api-level") 160 .withDescription("The numeric api-level of the file being disassembled. If not " + 161 "specified, it defaults to 15 (ICS).") 162 .hasArg() 163 .withArgName("API_LEVEL") 164 .create("a"); 165 166 options.addOption(classPathDirOption); 167 options.addOption(outputFileOption); 168 options.addOption(apiLevelOption); 169 } 170} 171