main.java revision 81ab1aa726c16abfea0b9b2550e3123190d98343
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.dexlib.Util.Deodexerant;
22
23import java.io.File;
24import java.io.InputStream;
25import java.io.IOException;
26import java.util.Properties;
27
28public class main {
29
30    public static final String VERSION;
31
32    private static final Options options;
33
34    static {
35        options = new Options();
36        buildOptions();
37
38        InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties");
39        Properties properties = new Properties();
40        String version = "(unknown)";
41        try {
42            properties.load(templateStream);
43            version = properties.getProperty("application.version");
44        } catch (IOException ex) {
45        }
46        VERSION = version;
47    }
48
49    /**
50     * This class is uninstantiable.
51     */
52    private main() {
53    }
54
55    /**
56     * Run!
57     */
58    public static void main(String[] args) {
59        CommandLineParser parser = new PosixParser();
60        CommandLine commandLine;
61
62        try {
63            commandLine = parser.parse(options, args);
64        } catch (ParseException ex) {
65            usage();
66            return;
67        }
68
69        boolean disassemble = true;
70        boolean doDump = false;
71        boolean write = false;
72        boolean sort = false;
73        boolean fixRegisters = false;
74        boolean noParameterRegisters = false;
75        boolean useLocalsDirective = false;
76        boolean useSequentialLabels = false;
77        boolean outputDebugInfo = true;
78
79
80        String outputDirectory = "out";
81        String dumpFileName = null;
82        String outputDexFileName = null;
83        String inputDexFileName = null;
84        String deodexerantHost = null;
85        int deodexerantPort = 0;
86
87        String[] remainingArgs = commandLine.getArgs();
88
89        if (commandLine.hasOption("v")) {
90            version();
91            return;
92        }
93
94        if (commandLine.hasOption("?")) {
95            usage();
96            return;
97        }
98
99        if (remainingArgs.length != 1) {
100            usage();
101            return;
102        }
103
104        inputDexFileName = remainingArgs[0];
105
106        if (commandLine.hasOption("n")) {
107            disassemble = false;
108        }
109
110        if (commandLine.hasOption("d")) {
111            doDump = true;
112            dumpFileName = commandLine.getOptionValue("d", inputDexFileName + ".dump");
113        }
114
115        if (commandLine.hasOption("w")) {
116            write = true;
117            outputDexFileName = commandLine.getOptionValue("w");
118        }
119
120        if (commandLine.hasOption("o")) {
121            outputDirectory = commandLine.getOptionValue("o");
122        }
123
124        if (commandLine.hasOption("s")) {
125            sort = true;
126        }
127
128        if (commandLine.hasOption("f")) {
129            fixRegisters = true;
130        }
131
132        if (commandLine.hasOption("p")) {
133            noParameterRegisters = true;
134        }
135
136        if (commandLine.hasOption("l")) {
137            useLocalsDirective = true;
138        }
139
140        if (commandLine.hasOption("i")) {
141            useSequentialLabels = true;
142        }
143
144        if (commandLine.hasOption("b")) {
145            outputDebugInfo = false;
146        }
147
148        if (commandLine.hasOption("x")) {
149            String deodexerantAddress = commandLine.getOptionValue("x");
150            String[] parts = deodexerantAddress.split(":");
151            if (parts.length != 2) {
152                System.err.println("Invalid deodexerant address. Expecting :<port> or <host>:<port>");
153                System.exit(1);
154            }
155
156            deodexerantHost = parts[0];
157            if (deodexerantHost.length() == 0) {
158                deodexerantHost = "localhost";
159            }
160            try {
161                deodexerantPort = Integer.parseInt(parts[1]);
162            } catch (NumberFormatException ex) {
163                System.err.println("Invalid port \"" + deodexerantPort + "\" for deodexerant address");
164                System.exit(1);
165            }
166        }
167
168        try {
169            File dexFileFile = new File(inputDexFileName);
170            if (!dexFileFile.exists()) {
171                System.err.println("Can't find the file " + inputDexFileName);
172                System.exit(1);
173            }
174
175            //Read in and parse the dex file
176            DexFile dexFile = new DexFile(dexFileFile, !fixRegisters);
177
178            Deodexerant deodexerant = null;
179
180
181            if (deodexerantHost != null) {
182                if (!dexFile.isOdex()) {
183                    System.err.println("-x cannot be used with a normal dex file. Ignoring -x");
184                }
185                deodexerant = new Deodexerant(dexFile, deodexerantHost, deodexerantPort);
186            }
187
188            if (dexFile.isOdex()) {
189                if (doDump) {
190                    System.err.println("-d cannot be used with on odex file. Ignoring -d");
191                }
192                if (write) {
193                    System.err.println("-w cannot be used with an odex file. Ignoring -w");
194                }
195                if (deodexerant == null) {
196                    System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
197                    System.err.println("won't be able to re-assemble the results unless you use deodexerant, and");
198                    System.err.println("the -x option for baksmali");
199                }
200            }
201
202            if (disassemble) {
203                baksmali.disassembleDexFile(dexFile, deodexerant, outputDirectory, noParameterRegisters,
204                        useLocalsDirective, useSequentialLabels, outputDebugInfo);
205            }
206
207            if ((doDump || write) && !dexFile.isOdex()) {
208                try
209                {
210                    dump.dump(dexFile, dumpFileName, outputDexFileName, sort);
211                }catch (IOException ex) {
212                    System.err.println("Error occured while writing dump file");
213                    ex.printStackTrace();
214                }
215            }
216        } catch (RuntimeException ex) {
217            System.err.println("\n\nUNEXPECTED TOP-LEVEL EXCEPTION:");
218            ex.printStackTrace();
219            System.exit(1);
220        } catch (Throwable ex) {
221            System.err.println("\n\nUNEXPECTED TOP-LEVEL ERROR:");
222            ex.printStackTrace();
223            System.exit(1);
224        }
225    }
226
227    /**
228     * Prints the usage message.
229     */
230    private static void usage() {
231        HelpFormatter formatter = new HelpFormatter();
232        formatter.printHelp("java -jar baksmali.jar [options] <dex-file>",
233                "disassembles and/or dumps a dex file", options, "");
234    }
235
236    /**
237     * Prints the version message.
238     */
239    private static void version() {
240        System.out.println("baksmali " + VERSION + " (http://smali.googlecode.com)");
241        System.out.println("Copyright (C) 2009 Ben Gruver");
242        System.out.println("BSD license (http://www.opensource.org/licenses/bsd-license.php)");
243        System.exit(0);
244    }
245
246    private static void buildOptions() {
247        Option versionOption = OptionBuilder.withLongOpt("version")
248                .withDescription("prints the version then exits")
249                .create("v");
250
251        Option helpOption = OptionBuilder.withLongOpt("help")
252                .withDescription("prints the help message then exits")
253                .create("?");
254
255        Option noDisassemblyOption = OptionBuilder.withLongOpt("no-disassembly")
256                .withDescription("suppresses the output of the disassembly")
257                .create("n");
258
259        Option dumpOption = OptionBuilder.withLongOpt("dump-to")
260                .withDescription("dumps the given dex file into a single annotated dump file named FILE" +
261                        " (<dexfile>.dump by default), along with the normal disassembly.")
262                .hasOptionalArg()
263                .withArgName("FILE")
264                .create("d");
265
266        Option writeDexOption = OptionBuilder.withLongOpt("write-dex")
267                .withDescription("additionally rewrites the input dex file to FILE")
268                .hasArg()
269                .withArgName("FILE")
270                .create("w");
271
272        Option outputDirOption = OptionBuilder.withLongOpt("output")
273                .withDescription("the directory where the disassembled files will be placed. The default is out")
274                .hasArg()
275                .withArgName("DIR")
276                .create("o");
277
278        Option sortOption = OptionBuilder.withLongOpt("sort")
279                .withDescription("sort the items in the dex file into a canonical order before dumping/writing")
280                .create("s");
281
282        Option fixSignedRegisterOption = OptionBuilder.withLongOpt("fix-signed-registers")
283                .withDescription("when dumping or rewriting, fix any registers in the debug info that are encoded as" +
284                        " a signed value")
285                .create("f");
286
287        Option noParameterRegistersOption = OptionBuilder.withLongOpt("no-parameter-registers")
288                .withDescription("use the v<n> syntax instead of the p<n> syntax for registers mapped to method" +
289                        " parameters")
290                .create("p");
291
292        Option deodexerantOption = OptionBuilder.withLongOpt("deodexerant")
293                .withDescription("connect to deodexerant on the specified HOST:PORT, and deodex the input odex"
294                        + " file. This option is ignored if the input file is a dex file instead of an odex file")
295                .hasArg()
296                .withArgName("HOST:PORT")
297                .create("x");
298
299        Option useLocalsOption = OptionBuilder.withLongOpt("use-locals")
300                .withDescription("output the .locals directive with the number of non-parameter registers, rather" +
301                        " than the .register directive with the total number of register")
302                .create("l");
303
304        Option sequentialLabelsOption = OptionBuilder.withLongOpt("sequential-labels")
305                .withDescription("create label names using a sequential numbering scheme per label type, rather than " +
306                        "using the bytecode offset")
307                .create("q");
308
309        Option noDebugInfoOption = OptionBuilder.withLongOpt("no-debug-info")
310                .withDescription("don't write out debug info (.local, .param, .line, etc.)")
311                .create("b");
312
313        options.addOption(versionOption);
314        options.addOption(helpOption);
315        options.addOption(dumpOption);
316        options.addOption(noDisassemblyOption);
317        options.addOption(writeDexOption);
318        options.addOption(outputDirOption);
319        options.addOption(sortOption);
320        options.addOption(fixSignedRegisterOption);
321        options.addOption(noParameterRegistersOption);
322        options.addOption(deodexerantOption);
323        options.addOption(useLocalsOption);
324        options.addOption(sequentialLabelsOption);
325        options.addOption(noDebugInfoOption);
326    }
327}