1735746595fc623181546a08f415efd5215d88657Ben Gruver/* 2735746595fc623181546a08f415efd5215d88657Ben Gruver * Copyright 2016, Google Inc. 3735746595fc623181546a08f415efd5215d88657Ben Gruver * All rights reserved. 4735746595fc623181546a08f415efd5215d88657Ben Gruver * 5735746595fc623181546a08f415efd5215d88657Ben Gruver * Redistribution and use in source and binary forms, with or without 6735746595fc623181546a08f415efd5215d88657Ben Gruver * modification, are permitted provided that the following conditions are 7735746595fc623181546a08f415efd5215d88657Ben Gruver * met: 8735746595fc623181546a08f415efd5215d88657Ben Gruver * 9735746595fc623181546a08f415efd5215d88657Ben Gruver * Redistributions of source code must retain the above copyright 10735746595fc623181546a08f415efd5215d88657Ben Gruver * notice, this list of conditions and the following disclaimer. 11735746595fc623181546a08f415efd5215d88657Ben Gruver * Redistributions in binary form must reproduce the above 12735746595fc623181546a08f415efd5215d88657Ben Gruver * copyright notice, this list of conditions and the following disclaimer 13735746595fc623181546a08f415efd5215d88657Ben Gruver * in the documentation and/or other materials provided with the 14735746595fc623181546a08f415efd5215d88657Ben Gruver * distribution. 15735746595fc623181546a08f415efd5215d88657Ben Gruver * Neither the name of Google Inc. nor the names of its 16735746595fc623181546a08f415efd5215d88657Ben Gruver * contributors may be used to endorse or promote products derived from 17735746595fc623181546a08f415efd5215d88657Ben Gruver * this software without specific prior written permission. 18735746595fc623181546a08f415efd5215d88657Ben Gruver * 19735746595fc623181546a08f415efd5215d88657Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20735746595fc623181546a08f415efd5215d88657Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21735746595fc623181546a08f415efd5215d88657Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22735746595fc623181546a08f415efd5215d88657Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23735746595fc623181546a08f415efd5215d88657Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24735746595fc623181546a08f415efd5215d88657Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25735746595fc623181546a08f415efd5215d88657Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26735746595fc623181546a08f415efd5215d88657Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27735746595fc623181546a08f415efd5215d88657Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28735746595fc623181546a08f415efd5215d88657Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29735746595fc623181546a08f415efd5215d88657Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30735746595fc623181546a08f415efd5215d88657Ben Gruver */ 31735746595fc623181546a08f415efd5215d88657Ben Gruver 32735746595fc623181546a08f415efd5215d88657Ben Gruverpackage org.jf.smali; 33735746595fc623181546a08f415efd5215d88657Ben Gruver 34735746595fc623181546a08f415efd5215d88657Ben Gruverimport com.google.common.collect.Lists; 35735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.CommonTokenStream; 36735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.Token; 37735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.TokenSource; 38735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.tree.CommonTree; 39735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.antlr.runtime.tree.CommonTreeNodeStream; 40735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.jf.dexlib2.Opcodes; 41735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.jf.dexlib2.writer.builder.DexBuilder; 42735746595fc623181546a08f415efd5215d88657Ben Gruverimport org.jf.dexlib2.writer.io.FileDataStore; 43735746595fc623181546a08f415efd5215d88657Ben Gruver 44735746595fc623181546a08f415efd5215d88657Ben Gruverimport javax.annotation.Nonnull; 45735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.io.File; 46735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.io.FileInputStream; 47735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.io.IOException; 48735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.io.InputStreamReader; 49735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.Arrays; 50735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.LinkedHashSet; 51735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.List; 52735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.Set; 53735746595fc623181546a08f415efd5215d88657Ben Gruverimport java.util.concurrent.*; 54735746595fc623181546a08f415efd5215d88657Ben Gruver 55735746595fc623181546a08f415efd5215d88657Ben Gruverpublic class Smali { 56735746595fc623181546a08f415efd5215d88657Ben Gruver 57735746595fc623181546a08f415efd5215d88657Ben Gruver /** 58735746595fc623181546a08f415efd5215d88657Ben Gruver * Assemble the specified files, using the given options 59735746595fc623181546a08f415efd5215d88657Ben Gruver * 60735746595fc623181546a08f415efd5215d88657Ben Gruver * @param options a SmaliOptions object with the options to run smali with 61735746595fc623181546a08f415efd5215d88657Ben Gruver * @param input The files/directories to process 62735746595fc623181546a08f415efd5215d88657Ben Gruver * @return true if assembly completed with no errors, or false if errors were encountered 63735746595fc623181546a08f415efd5215d88657Ben Gruver */ 64735746595fc623181546a08f415efd5215d88657Ben Gruver public static boolean assemble(final SmaliOptions options, String... input) throws IOException { 65735746595fc623181546a08f415efd5215d88657Ben Gruver return assemble(options, Arrays.asList(input)); 66735746595fc623181546a08f415efd5215d88657Ben Gruver } 67735746595fc623181546a08f415efd5215d88657Ben Gruver 68735746595fc623181546a08f415efd5215d88657Ben Gruver /** 69735746595fc623181546a08f415efd5215d88657Ben Gruver * Assemble the specified files, using the given options 70735746595fc623181546a08f415efd5215d88657Ben Gruver * 71735746595fc623181546a08f415efd5215d88657Ben Gruver * @param options a SmaliOptions object with the options to run smali with 72735746595fc623181546a08f415efd5215d88657Ben Gruver * @param input The files/directories to process 73735746595fc623181546a08f415efd5215d88657Ben Gruver * @return true if assembly completed with no errors, or false if errors were encountered 74735746595fc623181546a08f415efd5215d88657Ben Gruver */ 75735746595fc623181546a08f415efd5215d88657Ben Gruver public static boolean assemble(final SmaliOptions options, List<String> input) throws IOException { 76735746595fc623181546a08f415efd5215d88657Ben Gruver LinkedHashSet<File> filesToProcessSet = new LinkedHashSet<File>(); 77735746595fc623181546a08f415efd5215d88657Ben Gruver 78735746595fc623181546a08f415efd5215d88657Ben Gruver for (String fileToProcess: input) { 79735746595fc623181546a08f415efd5215d88657Ben Gruver File argFile = new File(fileToProcess); 80735746595fc623181546a08f415efd5215d88657Ben Gruver 81735746595fc623181546a08f415efd5215d88657Ben Gruver if (!argFile.exists()) { 82735746595fc623181546a08f415efd5215d88657Ben Gruver throw new IllegalArgumentException("Cannot find file or directory \"" + fileToProcess + "\""); 83735746595fc623181546a08f415efd5215d88657Ben Gruver } 84735746595fc623181546a08f415efd5215d88657Ben Gruver 85735746595fc623181546a08f415efd5215d88657Ben Gruver if (argFile.isDirectory()) { 86735746595fc623181546a08f415efd5215d88657Ben Gruver getSmaliFilesInDir(argFile, filesToProcessSet); 87735746595fc623181546a08f415efd5215d88657Ben Gruver } else if (argFile.isFile()) { 88735746595fc623181546a08f415efd5215d88657Ben Gruver filesToProcessSet.add(argFile); 89735746595fc623181546a08f415efd5215d88657Ben Gruver } 90735746595fc623181546a08f415efd5215d88657Ben Gruver } 91735746595fc623181546a08f415efd5215d88657Ben Gruver 92735746595fc623181546a08f415efd5215d88657Ben Gruver boolean errors = false; 93735746595fc623181546a08f415efd5215d88657Ben Gruver 945189797292086a051666cf8c96cf44c6a23321b6Ben Gruver final DexBuilder dexBuilder = new DexBuilder(Opcodes.forApi(options.apiLevel)); 95735746595fc623181546a08f415efd5215d88657Ben Gruver 96735746595fc623181546a08f415efd5215d88657Ben Gruver ExecutorService executor = Executors.newFixedThreadPool(options.jobs); 97735746595fc623181546a08f415efd5215d88657Ben Gruver List<Future<Boolean>> tasks = Lists.newArrayList(); 98735746595fc623181546a08f415efd5215d88657Ben Gruver 99735746595fc623181546a08f415efd5215d88657Ben Gruver for (final File file: filesToProcessSet) { 100735746595fc623181546a08f415efd5215d88657Ben Gruver tasks.add(executor.submit(new Callable<Boolean>() { 101735746595fc623181546a08f415efd5215d88657Ben Gruver @Override public Boolean call() throws Exception { 102735746595fc623181546a08f415efd5215d88657Ben Gruver return assembleSmaliFile(file, dexBuilder, options); 103735746595fc623181546a08f415efd5215d88657Ben Gruver } 104735746595fc623181546a08f415efd5215d88657Ben Gruver })); 105735746595fc623181546a08f415efd5215d88657Ben Gruver } 106735746595fc623181546a08f415efd5215d88657Ben Gruver 107735746595fc623181546a08f415efd5215d88657Ben Gruver for (Future<Boolean> task: tasks) { 108735746595fc623181546a08f415efd5215d88657Ben Gruver while(true) { 109735746595fc623181546a08f415efd5215d88657Ben Gruver try { 110735746595fc623181546a08f415efd5215d88657Ben Gruver try { 111735746595fc623181546a08f415efd5215d88657Ben Gruver if (!task.get()) { 112735746595fc623181546a08f415efd5215d88657Ben Gruver errors = true; 113735746595fc623181546a08f415efd5215d88657Ben Gruver } 114735746595fc623181546a08f415efd5215d88657Ben Gruver } catch (ExecutionException ex) { 115735746595fc623181546a08f415efd5215d88657Ben Gruver throw new RuntimeException(ex); 116735746595fc623181546a08f415efd5215d88657Ben Gruver } 117735746595fc623181546a08f415efd5215d88657Ben Gruver } catch (InterruptedException ex) { 118735746595fc623181546a08f415efd5215d88657Ben Gruver continue; 119735746595fc623181546a08f415efd5215d88657Ben Gruver } 120735746595fc623181546a08f415efd5215d88657Ben Gruver break; 121735746595fc623181546a08f415efd5215d88657Ben Gruver } 122735746595fc623181546a08f415efd5215d88657Ben Gruver } 123735746595fc623181546a08f415efd5215d88657Ben Gruver 124735746595fc623181546a08f415efd5215d88657Ben Gruver executor.shutdown(); 125735746595fc623181546a08f415efd5215d88657Ben Gruver 126735746595fc623181546a08f415efd5215d88657Ben Gruver if (errors) { 127735746595fc623181546a08f415efd5215d88657Ben Gruver return false; 128735746595fc623181546a08f415efd5215d88657Ben Gruver } 129735746595fc623181546a08f415efd5215d88657Ben Gruver 130735746595fc623181546a08f415efd5215d88657Ben Gruver dexBuilder.writeTo(new FileDataStore(new File(options.outputDexFile))); 131735746595fc623181546a08f415efd5215d88657Ben Gruver 132735746595fc623181546a08f415efd5215d88657Ben Gruver return true; 133735746595fc623181546a08f415efd5215d88657Ben Gruver } 134735746595fc623181546a08f415efd5215d88657Ben Gruver 135735746595fc623181546a08f415efd5215d88657Ben Gruver private static void getSmaliFilesInDir(@Nonnull File dir, @Nonnull Set<File> smaliFiles) { 136735746595fc623181546a08f415efd5215d88657Ben Gruver File[] files = dir.listFiles(); 137735746595fc623181546a08f415efd5215d88657Ben Gruver if (files != null) { 138735746595fc623181546a08f415efd5215d88657Ben Gruver for(File file: files) { 139735746595fc623181546a08f415efd5215d88657Ben Gruver if (file.isDirectory()) { 140735746595fc623181546a08f415efd5215d88657Ben Gruver getSmaliFilesInDir(file, smaliFiles); 141735746595fc623181546a08f415efd5215d88657Ben Gruver } else if (file.getName().endsWith(".smali")) { 142735746595fc623181546a08f415efd5215d88657Ben Gruver smaliFiles.add(file); 143735746595fc623181546a08f415efd5215d88657Ben Gruver } 144735746595fc623181546a08f415efd5215d88657Ben Gruver } 145735746595fc623181546a08f415efd5215d88657Ben Gruver } 146735746595fc623181546a08f415efd5215d88657Ben Gruver } 147735746595fc623181546a08f415efd5215d88657Ben Gruver 148735746595fc623181546a08f415efd5215d88657Ben Gruver private static boolean assembleSmaliFile(File smaliFile, DexBuilder dexBuilder, SmaliOptions options) 149735746595fc623181546a08f415efd5215d88657Ben Gruver throws Exception { 15043669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski FileInputStream fis = null; 15143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski try { 15243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski fis = new FileInputStream(smaliFile); 15343669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski InputStreamReader reader = new InputStreamReader(fis, "UTF-8"); 15443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski 15543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski LexerErrorInterface lexer = new smaliFlexLexer(reader); 15643669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski ((smaliFlexLexer)lexer).setSourceFile(smaliFile); 15743669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski CommonTokenStream tokens = new CommonTokenStream((TokenSource)lexer); 15843669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski 15943669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski if (options.printTokens) { 16043669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski tokens.getTokens(); 16143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski 16243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski for (int i=0; i<tokens.size(); i++) { 16343669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski Token token = tokens.get(i); 16443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski if (token.getChannel() == smaliParser.HIDDEN) { 16543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski continue; 16643669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski } 167735746595fc623181546a08f415efd5215d88657Ben Gruver 16843669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski System.out.println(smaliParser.tokenNames[token.getType()] + ": " + token.getText()); 169735746595fc623181546a08f415efd5215d88657Ben Gruver } 170735746595fc623181546a08f415efd5215d88657Ben Gruver 17143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski System.out.flush(); 172735746595fc623181546a08f415efd5215d88657Ben Gruver } 173735746595fc623181546a08f415efd5215d88657Ben Gruver 17443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski smaliParser parser = new smaliParser(tokens); 17543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski parser.setVerboseErrors(options.verboseErrors); 17643669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski parser.setAllowOdex(options.allowOdexOpcodes); 17743669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski parser.setApiLevel(options.apiLevel); 178735746595fc623181546a08f415efd5215d88657Ben Gruver 17943669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski smaliParser.smali_file_return result = parser.smali_file(); 180735746595fc623181546a08f415efd5215d88657Ben Gruver 18143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski if (parser.getNumberOfSyntaxErrors() > 0 || lexer.getNumberOfSyntaxErrors() > 0) { 18243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski return false; 18343669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski } 184735746595fc623181546a08f415efd5215d88657Ben Gruver 18543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski CommonTree t = result.getTree(); 186735746595fc623181546a08f415efd5215d88657Ben Gruver 18743669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t); 18843669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski treeStream.setTokenStream(tokens); 189735746595fc623181546a08f415efd5215d88657Ben Gruver 19043669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski if (options.printTokens) { 19143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski System.out.println(t.toStringTree()); 19243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski } 193735746595fc623181546a08f415efd5215d88657Ben Gruver 19443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski smaliTreeWalker dexGen = new smaliTreeWalker(treeStream); 19543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski dexGen.setApiLevel(options.apiLevel); 196735746595fc623181546a08f415efd5215d88657Ben Gruver 19743669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski dexGen.setVerboseErrors(options.verboseErrors); 19843669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski dexGen.setDexBuilder(dexBuilder); 19943669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski dexGen.smali_file(); 200735746595fc623181546a08f415efd5215d88657Ben Gruver 20143669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski return dexGen.getNumberOfSyntaxErrors() == 0; 20243669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski } finally { 20343669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski if (fis != null) { 20443669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski fis.close(); 20543669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski } 20643669ecc6e3f5d95ef1653fb7ba0c0445040fd3cAlbert Gorski } 207735746595fc623181546a08f415efd5215d88657Ben Gruver } 208735746595fc623181546a08f415efd5215d88657Ben Gruver} 209