main.java revision fbea4e751fa6f1748ded4379a4b64601cb53ba7b
158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)/*
258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * [The "BSD licence"]
358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * Copyright (c) 2010 Ben Gruver (JesusFreke)
458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * All rights reserved.
558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *
658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * modification, are permitted provided that the following conditions
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * are met:
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer.
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright
1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer in the
1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *    documentation and/or other materials provided with the distribution.
1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * 3. The name of the author may not be used to endorse or promote products
1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *    derived from this software without specific prior written permission.
1658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) *
1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) */
2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)package org.jf.baksmali;
3058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import org.apache.commons.cli.*;
3258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import org.jf.dexlib.DexFile;
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import org.jf.util.ConsoleUtil;
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import org.jf.util.smaliHelpFormatter;
3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import java.io.File;
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import java.io.IOException;
3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import java.io.InputStream;
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import java.util.ArrayList;
4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import java.util.List;
4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)import java.util.Properties;
4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)public class main {
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    public static final String VERSION;
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final Options basicOptions;
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final Options debugOptions;
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private static final Options options;
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    public static final int ALL = 1;
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    public static final int ALLPRE = 2;
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    public static final int ALLPOST = 4;
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    public static final int ARGS = 8;
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    public static final int DEST = 16;
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    public static final int MERGE = 32;
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    public static final int FULLMERGE = 64;
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    static {
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        options = new Options();
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        basicOptions = new Options();
6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        debugOptions = new Options();
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        buildOptions();
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        InputStream templateStream = baksmali.class.getClassLoader().getResourceAsStream("baksmali.properties");
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        Properties properties = new Properties();
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        String version = "(unknown)";
6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        try {
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            properties.load(templateStream);
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            version = properties.getProperty("application.version");
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        } catch (IOException ex) {
7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        VERSION = version;
7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    /**
7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)     * This class is uninstantiable.
7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)     */
7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    private main() {
8058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
8158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    /**
8358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)     * Run!
8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)     */
8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    public static void main(String[] args) {
8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        CommandLineParser parser = new PosixParser();
8758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        CommandLine commandLine;
8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
8958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        try {
9058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            commandLine = parser.parse(options, args);
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        } catch (ParseException ex) {
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            usage();
9358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            return;
9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean disassemble = true;
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean doDump = false;
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean write = false;
9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean sort = false;
10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean fixRegisters = false;
10158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean noParameterRegisters = false;
10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean useLocalsDirective = false;
10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean useSequentialLabels = false;
10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean outputDebugInfo = true;
10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean addCodeOffsets = false;
10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean deodex = false;
10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean verify = false;
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean ignoreErrors = false;
10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        int registerInfo = 0;
11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        String outputDirectory = "out";
11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        String dumpFileName = null;
11458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        String outputDexFileName = null;
11558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        String inputDexFileName = null;
11658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        String bootClassPath = null;
11758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        StringBuffer extraBootClassPathEntries = new StringBuffer();
11858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        List<String> bootClassPathDirs = new ArrayList<String>();
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        bootClassPathDirs.add(".");
12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        String[] remainingArgs = commandLine.getArgs();
12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
12458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        Option[] options = commandLine.getOptions();
12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        for (int i=0; i<options.length; i++) {
12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            Option option = options[i];
12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            String opt = option.getOpt();
12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            switch (opt.charAt(0)) {
13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                case 'v':
13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    version();
13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    return;
13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                case '?':
13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    while (++i < options.length) {
13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                        if (options[i].getOpt().charAt(0) == '?') {
13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            usage(true);
13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            return;
13958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                        }
14058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    }
14158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    usage(false);
14258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    return;
14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                case 'o':
14458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    outputDirectory = commandLine.getOptionValue("o");
14558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    break;
14658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                case 'p':
14758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    noParameterRegisters = true;
14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    break;
14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                case 'l':
15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    useLocalsDirective = true;
151                    break;
152                case 's':
153                    useSequentialLabels = true;
154                    break;
155                case 'b':
156                    outputDebugInfo = false;
157                    break;
158                case 'd':
159                    bootClassPathDirs.add(option.getValue());
160                    break;
161                case 'f':
162                    addCodeOffsets = true;
163                    break;
164                case 'r':
165                    String[] values = commandLine.getOptionValues('r');
166
167                    if (values == null || values.length == 0) {
168                        registerInfo = ARGS | DEST;
169                    } else {
170                        for (String value: values) {
171                            if (value.equalsIgnoreCase("ALL")) {
172                                registerInfo |= ALL;
173                            } else if (value.equalsIgnoreCase("ALLPRE")) {
174                                registerInfo |= ALLPRE;
175                            } else if (value.equalsIgnoreCase("ALLPOST")) {
176                                registerInfo |= ALLPOST;
177                            } else if (value.equalsIgnoreCase("ARGS")) {
178                                registerInfo |= ARGS;
179                            } else if (value.equalsIgnoreCase("DEST")) {
180                                registerInfo |= DEST;
181                            } else if (value.equalsIgnoreCase("MERGE")) {
182                                registerInfo |= MERGE;
183                            } else if (value.equalsIgnoreCase("FULLMERGE")) {
184                                registerInfo |= FULLMERGE;
185                            } else {
186                                usage();
187                                return;
188                            }
189                        }
190
191                        if ((registerInfo & FULLMERGE) != 0) {
192                            registerInfo &= ~MERGE;
193                        }
194                    }
195                    break;
196                case 'c':
197                    String bcp = commandLine.getOptionValue("c");
198                    if (bcp != null && bcp.charAt(0) == ':') {
199                        extraBootClassPathEntries.append(bcp);
200                    } else {
201                        bootClassPath = bcp;
202                    }
203                    break;
204                case 'x':
205                    deodex = true;
206                    break;
207                case 'N':
208                    disassemble = false;
209                    break;
210                case 'D':
211                    doDump = true;
212                    dumpFileName = commandLine.getOptionValue("D", inputDexFileName + ".dump");
213                    break;
214                case 'I':
215                    ignoreErrors = true;
216                    break;
217                case 'W':
218                    write = true;
219                    outputDexFileName = commandLine.getOptionValue("W");
220                    break;
221                case 'S':
222                    sort = true;
223                    break;
224                case 'F':
225                    fixRegisters = true;
226                    break;
227                case 'V':
228                    verify = true;
229                    break;
230                default:
231                    assert false;
232            }
233        }
234
235        if (remainingArgs.length != 1) {
236            usage();
237            return;
238        }
239
240        inputDexFileName = remainingArgs[0];
241
242        try {
243            File dexFileFile = new File(inputDexFileName);
244            if (!dexFileFile.exists()) {
245                System.err.println("Can't find the file " + inputDexFileName);
246                System.exit(1);
247            }
248
249            //Read in and parse the dex file
250            DexFile dexFile = new DexFile(dexFileFile, !fixRegisters, false);
251
252            if (dexFile.isOdex()) {
253                if (doDump) {
254                    System.err.println("-D cannot be used with on odex file. Ignoring -D");
255                }
256                if (write) {
257                    System.err.println("-W cannot be used with an odex file. Ignoring -W");
258                }
259                if (!deodex) {
260                    System.err.println("Warning: You are disassembling an odex file without deodexing it. You");
261                    System.err.println("won't be able to re-assemble the results unless you deodex it with the -x");
262                    System.err.println("option");
263                }
264            } else {
265                deodex = false;
266
267                if (bootClassPath == null) {
268                    bootClassPath = "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar";
269                }
270            }
271
272            if (disassemble) {
273                String[] bootClassPathDirsArray = new String[bootClassPathDirs.size()];
274                for (int i=0; i<bootClassPathDirsArray.length; i++) {
275                    bootClassPathDirsArray[i] = bootClassPathDirs.get(i);
276                }
277
278                baksmali.disassembleDexFile(dexFileFile.getPath(), dexFile, deodex, outputDirectory,
279                        bootClassPathDirsArray, bootClassPath, extraBootClassPathEntries.toString(),
280                        noParameterRegisters, useLocalsDirective, useSequentialLabels, outputDebugInfo, addCodeOffsets,
281                        registerInfo, verify, ignoreErrors);
282            }
283
284            if ((doDump || write) && !dexFile.isOdex()) {
285                try
286                {
287                    dump.dump(dexFile, dumpFileName, outputDexFileName, sort);
288                }catch (IOException ex) {
289                    System.err.println("Error occured while writing dump file");
290                    ex.printStackTrace();
291                }
292            }
293        } catch (RuntimeException ex) {
294            System.err.println("\n\nUNEXPECTED TOP-LEVEL EXCEPTION:");
295            ex.printStackTrace();
296            System.exit(1);
297        } catch (Throwable ex) {
298            System.err.println("\n\nUNEXPECTED TOP-LEVEL ERROR:");
299            ex.printStackTrace();
300            System.exit(1);
301        }
302    }
303
304    /**
305     * Prints the usage message.
306     */
307    private static void usage(boolean printDebugOptions) {
308        smaliHelpFormatter formatter = new smaliHelpFormatter();
309        formatter.setWidth(ConsoleUtil.getConsoleWidth());
310
311        formatter.printHelp("java -jar baksmali.jar [options] <dex-file>",
312                "disassembles and/or dumps a dex file", basicOptions, "");
313
314        if (printDebugOptions) {
315            System.out.println();
316            System.out.println("Debug Options:");
317
318            StringBuffer sb = new StringBuffer();
319            formatter.renderOptions(sb, debugOptions);
320            System.out.println(sb.toString());
321        }
322    }
323
324    private static void usage() {
325        usage(false);
326    }
327
328    /**
329     * Prints the version message.
330     */
331    protected static void version() {
332        System.out.println("baksmali " + VERSION + " (http://smali.googlecode.com)");
333        System.out.println("Copyright (C) 2010 Ben Gruver (JesusFreke@JesusFreke.com)");
334        System.out.println("BSD license (http://www.opensource.org/licenses/bsd-license.php)");
335        System.exit(0);
336    }
337
338    private static void buildOptions() {
339        Option versionOption = OptionBuilder.withLongOpt("version")
340                .withDescription("prints the version then exits")
341                .create("v");
342
343        Option helpOption = OptionBuilder.withLongOpt("help")
344                .withDescription("prints the help message then exits. Specify twice for debug options")
345                .create("?");
346
347        Option outputDirOption = OptionBuilder.withLongOpt("output")
348                .withDescription("the directory where the disassembled files will be placed. The default is out")
349                .hasArg()
350                .withArgName("DIR")
351                .create("o");
352
353        Option noParameterRegistersOption = OptionBuilder.withLongOpt("no-parameter-registers")
354                .withDescription("use the v<n> syntax instead of the p<n> syntax for registers mapped to method " +
355                        "parameters")
356                .create("p");
357
358        Option deodexerantOption = OptionBuilder.withLongOpt("deodex")
359                .withDescription("deodex the given odex file. This option is ignored if the input file is not an " +
360                        "odex file")
361                .create("x");
362
363        Option useLocalsOption = OptionBuilder.withLongOpt("use-locals")
364                .withDescription("output the .locals directive with the number of non-parameter registers, rather" +
365                        " than the .register directive with the total number of register")
366                .create("l");
367
368        Option sequentialLabelsOption = OptionBuilder.withLongOpt("sequential-labels")
369                .withDescription("create label names using a sequential numbering scheme per label type, rather than " +
370                        "using the bytecode address")
371                .create("s");
372
373        Option noDebugInfoOption = OptionBuilder.withLongOpt("no-debug-info")
374                .withDescription("don't write out debug info (.local, .param, .line, etc.)")
375                .create("b");
376
377        Option registerInfoOption = OptionBuilder.withLongOpt("register-info")
378                .hasOptionalArgs()
379                .withArgName("REGISTER_INFO_TYPES")
380                .withValueSeparator(',')
381                .withDescription("print the specificed type(s) of register information for each instruction. " +
382                        "\"ARGS,DEST\" is the default if no types are specified.\nValid values are:\nALL: all " +
383                        "pre- and post-instruction registers.\nALLPRE: all pre-instruction registers\nALLPOST: all " +
384                        "post-instruction registers\nARGS: any pre-instruction registers used as arguments to the " +
385                        "instruction\nDEST: the post-instruction destination register, if any\nMERGE: Any " +
386                        "pre-instruction register has been merged from more than 1 different post-instruction " +
387                        "register from its predecessors\nFULLMERGE: For each register that would be printed by " +
388                        "MERGE, also show the incoming register types that were merged")
389                .create("r");
390
391        Option classPathOption = OptionBuilder.withLongOpt("bootclasspath")
392                .withDescription("the bootclasspath jars to use, for analysis. Defaults to " +
393                        "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar. If the value begins with a " +
394                        ":, it will be appended to the default bootclasspath instead of replacing it")
395                .hasOptionalArg()
396                .withArgName("BOOTCLASSPATH")
397                .create("c");
398
399        Option classPathDirOption = OptionBuilder.withLongOpt("bootclasspath-dir")
400                .withDescription("the base folder to look for the bootclasspath files in. Defaults to the current " +
401                        "directory")
402                .hasArg()
403                .withArgName("DIR")
404                .create("d");
405
406        Option codeOffsetOption = OptionBuilder.withLongOpt("code-offsets")
407                .withDescription("add comments to the disassembly containing the code offset for each address")
408                .create("f");
409
410
411
412        Option dumpOption = OptionBuilder.withLongOpt("dump-to")
413                .withDescription("dumps the given dex file into a single annotated dump file named FILE" +
414                        " (<dexfile>.dump by default), along with the normal disassembly")
415                .hasOptionalArg()
416                .withArgName("FILE")
417                .create("D");
418
419        Option ignoreErrorsOption = OptionBuilder.withLongOpt("ignore-errors")
420                .withDescription("ignores any non-fatal errors that occur while disassembling/deodexing," +
421                        " ignoring the class if needed, and continuing with the next class. The default" +
422                        " behavior is to stop disassembling and exit once an error is encountered")
423                .create("I");
424
425        Option noDisassemblyOption = OptionBuilder.withLongOpt("no-disassembly")
426                .withDescription("suppresses the output of the disassembly")
427                .create("N");
428
429        Option writeDexOption = OptionBuilder.withLongOpt("write-dex")
430                .withDescription("additionally rewrites the input dex file to FILE")
431                .hasArg()
432                .withArgName("FILE")
433                .create("W");
434
435        Option sortOption = OptionBuilder.withLongOpt("sort")
436                .withDescription("sort the items in the dex file into a canonical order before dumping/writing")
437                .create("S");
438
439        Option fixSignedRegisterOption = OptionBuilder.withLongOpt("fix-signed-registers")
440                .withDescription("when dumping or rewriting, fix any registers in the debug info that are encoded as" +
441                        " a signed value")
442                .create("F");
443
444        Option verifyDexOption = OptionBuilder.withLongOpt("verify")
445                .withDescription("perform bytecode verification")
446                .create("V");
447
448        basicOptions.addOption(versionOption);
449        basicOptions.addOption(helpOption);
450        basicOptions.addOption(outputDirOption);
451        basicOptions.addOption(noParameterRegistersOption);
452        basicOptions.addOption(deodexerantOption);
453        basicOptions.addOption(useLocalsOption);
454        basicOptions.addOption(sequentialLabelsOption);
455        basicOptions.addOption(noDebugInfoOption);
456        basicOptions.addOption(registerInfoOption);
457        basicOptions.addOption(classPathOption);
458        basicOptions.addOption(classPathDirOption);
459        basicOptions.addOption(codeOffsetOption);
460
461        debugOptions.addOption(dumpOption);
462        debugOptions.addOption(ignoreErrorsOption);
463        debugOptions.addOption(noDisassemblyOption);
464        debugOptions.addOption(writeDexOption);
465        debugOptions.addOption(sortOption);
466        debugOptions.addOption(fixSignedRegisterOption);
467        debugOptions.addOption(verifyDexOption);
468
469
470        for (Object option: basicOptions.getOptions()) {
471            options.addOption((Option)option);
472        }
473        for (Object option: debugOptions.getOptions()) {
474            options.addOption((Option)option);
475        }
476    }
477}