main.java revision 3c23129eecb7127646f2901c1b0ec3b94a83c08f
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.jf.baksmali;
18
19import org.apache.commons.cli.*;
20import org.jf.dexlib.DexFile;
21import org.jf.baksmali.Renderers.*;
22import org.antlr.stringtemplate.StringTemplateGroup;
23
24import java.io.File;
25import java.io.InputStream;
26import java.io.InputStreamReader;
27import java.io.IOException;
28import java.util.Properties;
29
30public class main {
31
32    public static final String VERSION;
33
34    private static final Options options;
35
36    static {
37        options = new Options();
38        buildOptions();
39
40        InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties");
41        Properties properties = new Properties();
42        String version = "(unknown)";
43        try {
44            properties.load(templateStream);
45            version = properties.getProperty("application.version");
46        } catch (IOException ex) {
47        }
48        VERSION = version;
49    }
50
51    /**
52     * This class is uninstantiable.
53     */
54    private main() {
55    }
56
57    /**
58     * Run!
59     */
60    public static void main(String[] args) {
61        CommandLineParser parser = new PosixParser();
62        CommandLine commandLine;
63
64        try {
65            commandLine = parser.parse(options, args);
66        } catch (ParseException ex) {
67            usage();
68            return;
69        }
70
71        boolean disassemble = true;
72        boolean doDump = false;
73        boolean write = false;
74        boolean sort = false;
75        boolean fixRegisters = false;
76        boolean readOnly = false;
77        boolean noParameterRegisters = false;
78
79        String outputDirectory = "out";
80        String dumpFileName = null;
81        String outputDexFileName = null;
82        String inputDexFileName = null;
83
84        String[] remainingArgs = commandLine.getArgs();
85
86        if (commandLine.hasOption("v")) {
87            version();
88            return;
89        }
90
91        if (commandLine.hasOption("?")) {
92            usage();
93            return;
94        }
95
96        if (remainingArgs.length != 1) {
97            usage();
98            return;
99        }
100
101        inputDexFileName = remainingArgs[0];
102
103        if (commandLine.hasOption("r")) {
104            readOnly = true;
105        }
106
107        if (commandLine.hasOption("d")) {
108            doDump = true;
109            dumpFileName = commandLine.getOptionValue("d", inputDexFileName + ".dump");
110        }
111
112        if (commandLine.hasOption("D")) {
113            doDump = true;
114            disassemble = false;
115            dumpFileName = commandLine.getOptionValue("D", inputDexFileName + ".dump");
116        }
117
118        if (commandLine.hasOption("w")) {
119            write = true;
120            outputDexFileName = commandLine.getOptionValue("w");
121        }
122
123        if (commandLine.hasOption("o")) {
124            outputDirectory = commandLine.getOptionValue("o");
125        }
126
127        if (commandLine.hasOption("s")) {
128            sort = true;
129        }
130
131        if (commandLine.hasOption("f")) {
132            fixRegisters = true;
133        }
134
135        if (commandLine.hasOption("p")) {
136            noParameterRegisters = true;
137        }
138
139        try {
140            File dexFileFile = new File(inputDexFileName);
141            if (!dexFileFile.exists()) {
142                System.err.println("Can't find the file " + inputDexFileName);
143                System.exit(1);
144            }
145
146            //Read in and parse the dex file
147            DexFile dexFile = new DexFile(dexFileFile, !fixRegisters);
148
149            if (readOnly) {
150                return;
151            }
152
153            if (disassemble) {
154                baksmali.disassembleDexFile(dexFile, outputDirectory, noParameterRegisters);
155            }
156
157            if (doDump || write) {
158                try
159                {
160                    dump.dump(dexFile, dumpFileName, outputDexFileName, sort);
161                }catch (IOException ex) {
162                    System.err.println("Error occured while writing dump file");
163                    ex.printStackTrace();
164                }
165            }
166        } catch (RuntimeException ex) {
167            System.err.println("\n\nUNEXPECTED TOP-LEVEL EXCEPTION:");
168            ex.printStackTrace();
169            System.exit(1);
170        } catch (Throwable ex) {
171            System.err.println("\n\nUNEXPECTED TOP-LEVEL ERROR:");
172            ex.printStackTrace();
173            System.exit(1);
174        }
175    }
176
177    /**
178     * Prints the usage message.
179     */
180    private static void usage() {
181        HelpFormatter formatter = new HelpFormatter();
182        formatter.printHelp("java -jar baksmali.jar [options] <dex-file>",
183                "disassembles and/or dumps a dex file", options, "");
184    }
185
186    /**
187     * Prints the version message.
188     */
189    private static void version() {
190        System.out.println("baksmali " + VERSION + " (http://smali.googlecode.com)");
191        System.out.println("Copyright (C) 2009 Ben Gruver");
192        System.out.println("BSD license (http://www.opensource.org/licenses/bsd-license.php)");
193        System.exit(0);
194    }
195
196    private static void buildOptions() {
197        Option versionOption = OptionBuilder.withLongOpt("version")
198                .withDescription("prints the version then exits")
199                .create("v");
200
201        Option helpOption = OptionBuilder.withLongOpt("help")
202                .withDescription("prints the help message then exits")
203                .create("?");
204
205        Option readonlyOption = OptionBuilder.withLongOpt("read-only")
206                .withDescription("reads in the dex file and then exits")
207                .create("r");
208
209        Option dumpOption = OptionBuilder.withLongOpt("dump-to")
210                .withDescription("dumps the given dex file into a single annotated dump file named FILE (<dexfile>.dump by default), along with the normal disassembly.")
211                .hasOptionalArg()
212                .withArgName("FILE")
213                .create("d");
214
215        Option dumpOnlyOption = OptionBuilder.withLongOpt("dump-only")
216                .withDescription("dumps the given dex file into a single annotated dump file named FILE (<dexfile>.dump by default), and does not generate the disassembly")
217                .hasOptionalArg()
218                .withArgName("FILE")
219                .create("D");
220
221        Option writeDexOption = OptionBuilder.withLongOpt("write-dex")
222                .withDescription("additionally rewrites the input dex file to FILE")
223                .hasArg()
224                .withArgName("FILE")
225                .create("w");
226
227        Option outputDirOption = OptionBuilder.withLongOpt("output")
228                .withDescription("the directory where the disassembled files will be placed. The default is out")
229                .hasArg()
230                .withArgName("DIR")
231                .create("o");
232
233        Option sortOption = OptionBuilder.withLongOpt("sort")
234                .withDescription("sort the items in the dex file into a canonical order before dumping/writing")
235                .create("s");
236
237        Option fixSignedRegisterOption = OptionBuilder.withLongOpt("fix-signed-registers")
238                .withDescription("when dumping or rewriting, fix any registers in the debug info that are encoded as" +
239                        " a signed value")
240                .create("f");
241
242        Option noParameterRegistersOption = OptionBuilder.withLongOpt("no-parameter-registers")
243                .withDescription("use the v<n> syntax instead of the p<n> syntax for registers mapped to method" +
244                        " parameters")
245                .create("p");
246
247        OptionGroup dumpCommand = new OptionGroup();
248        dumpCommand.addOption(dumpOption);
249        dumpCommand.addOption(dumpOnlyOption);
250        dumpCommand.addOption(readonlyOption);
251
252        options.addOption(versionOption);
253        options.addOption(helpOption);
254        options.addOptionGroup(dumpCommand);
255        options.addOption(writeDexOption);
256        options.addOption(outputDirOption);
257        options.addOption(sortOption);
258        options.addOption(fixSignedRegisterOption);
259        options.addOption(noParameterRegistersOption);
260    }
261}