main.java revision a53706985479f8e0a1019fdbd3731ed6063a1627
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
78        String outputDirectory = "out";
79        String dumpFileName = null;
80        String outputDexFileName = null;
81        String inputDexFileName = null;
82
83        String[] remainingArgs = commandLine.getArgs();
84
85        if (commandLine.hasOption("v")) {
86            version();
87            return;
88        }
89
90        if (commandLine.hasOption("?")) {
91            usage();
92            return;
93        }
94
95        if (remainingArgs.length != 1) {
96            usage();
97            return;
98        }
99
100        inputDexFileName = remainingArgs[0];
101
102        if (commandLine.hasOption("r")) {
103            readOnly = true;
104        }
105
106        if (commandLine.hasOption("d")) {
107            doDump = true;
108            dumpFileName = commandLine.getOptionValue("d", inputDexFileName + ".dump");
109        }
110
111        if (commandLine.hasOption("D")) {
112            doDump = true;
113            disassemble = false;
114            dumpFileName = commandLine.getOptionValue("D", inputDexFileName + ".dump");
115        }
116
117        if (commandLine.hasOption("w")) {
118            write = true;
119            outputDexFileName = commandLine.getOptionValue("w");
120        }
121
122        if (commandLine.hasOption("o")) {
123            outputDirectory = commandLine.getOptionValue("o");
124        }
125
126        if (commandLine.hasOption("s")) {
127            sort = true;
128        }
129
130        if (commandLine.hasOption("f")) {
131            fixRegisters = true;
132        }
133
134        try {
135            File dexFileFile = new File(inputDexFileName);
136            if (!dexFileFile.exists()) {
137                System.err.println("Can't find the file " + inputDexFileName);
138                System.exit(1);
139            }
140
141            //Read in and parse the dex file
142            DexFile dexFile = new DexFile(dexFileFile, !fixRegisters);
143
144            if (readOnly) {
145                return;
146            }
147
148            if (disassemble) {
149                baksmali.disassembleDexFile(dexFile, outputDirectory);
150            }
151
152            if (doDump || write) {
153                try
154                {
155                    dump.dump(dexFile, dumpFileName, outputDexFileName, sort);
156                }catch (IOException ex) {
157                    System.err.println("Error occured while writing dump file");
158                    ex.printStackTrace();
159                }
160            }
161        } catch (RuntimeException ex) {
162            System.err.println("\n\nUNEXPECTED TOP-LEVEL EXCEPTION:");
163            ex.printStackTrace();
164            System.exit(1);
165        } catch (Throwable ex) {
166            System.err.println("\n\nUNEXPECTED TOP-LEVEL ERROR:");
167            ex.printStackTrace();
168            System.exit(1);
169        }
170    }
171
172    /**
173     * Prints the usage message.
174     */
175    private static void usage() {
176        HelpFormatter formatter = new HelpFormatter();
177        formatter.printHelp("java -jar baksmali.jar [options] <dex-file>",
178                "disassembles and/or dumps a dex file", options, "");
179    }
180
181    /**
182     * Prints the version message.
183     */
184    private static void version() {
185        System.out.println("baksmali " + VERSION + " (http://smali.googlecode.com)");
186        System.out.println("Copyright (C) 2009 Ben Gruver");
187        System.out.println("BSD license (http://www.opensource.org/licenses/bsd-license.php)");
188        System.exit(0);
189    }
190
191    private static void buildOptions() {
192        Option versionOption = OptionBuilder.withLongOpt("version")
193                .withDescription("prints the version then exits")
194                .create("v");
195
196        Option helpOption = OptionBuilder.withLongOpt("help")
197                .withDescription("prints the help message then exits")
198                .create("?");
199
200        Option readonlyOption = OptionBuilder.withLongOpt("read-only")
201                .withDescription("reads in the dex file and then exits")
202                .create("r");
203
204        Option dumpOption = OptionBuilder.withLongOpt("dump-to")
205                .withDescription("dumps the given dex file into a single annotated dump file named FILE (<dexfile>.dump by default), along with the normal disassembly.")
206                .hasOptionalArg()
207                .withArgName("FILE")
208                .create("d");
209
210        Option dumpOnlyOption = OptionBuilder.withLongOpt("dump-only")
211                .withDescription("dumps the given dex file into a single annotated dump file named FILE (<dexfile>.dump by default), and does not generate the disassembly")
212                .hasOptionalArg()
213                .withArgName("FILE")
214                .create("D");
215
216        Option writeDexOption = OptionBuilder.withLongOpt("write-dex")
217                .withDescription("additionally rewrites the input dex file to FILE")
218                .hasArg()
219                .withArgName("FILE")
220                .create("w");
221
222        Option outputDirOption = OptionBuilder.withLongOpt("output")
223                .withDescription("the directory where the disassembled files will be placed. The default is out")
224                .hasArg()
225                .withArgName("DIR")
226                .create("o");
227
228        Option sortOption = OptionBuilder.withLongOpt("sort")
229                .withDescription("sort the items in the dex file into a canonical order before dumping/writing")
230                .create("s");
231
232        Option fixSignedRegisterOption = OptionBuilder.withLongOpt("fix-signed-registers")
233                .withDescription("when dumping or rewriting, fix any registers in the debug info that are encoded as a signed value")
234                .create("f");
235
236        OptionGroup dumpCommand = new OptionGroup();
237        dumpCommand.addOption(dumpOption);
238        dumpCommand.addOption(dumpOnlyOption);
239        dumpCommand.addOption(readonlyOption);
240
241        options.addOption(versionOption);
242        options.addOption(helpOption);
243        options.addOptionGroup(dumpCommand);
244        options.addOption(writeDexOption);
245        options.addOption(outputDirOption);
246        options.addOption(sortOption);
247        options.addOption(fixSignedRegisterOption);
248    }
249}