15fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver/* 25fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * Copyright 2013, Google Inc. 35fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * All rights reserved. 45fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * 55fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * Redistribution and use in source and binary forms, with or without 65fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * modification, are permitted provided that the following conditions are 75fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * met: 85fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * 95fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * * Redistributions of source code must retain the above copyright 105fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * notice, this list of conditions and the following disclaimer. 115fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * * Redistributions in binary form must reproduce the above 125fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * copyright notice, this list of conditions and the following disclaimer 135fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * in the documentation and/or other materials provided with the 145fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * distribution. 155fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * * Neither the name of Google Inc. nor the names of its 165fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * contributors may be used to endorse or promote products derived from 175fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * this software without specific prior written permission. 185fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * 195fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 205fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 215fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 225fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 235fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 245fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 255fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 265fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 275fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 285fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 295fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 305fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver */ 315fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 325fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverpackage org.jf.dexlib2.analysis; 335fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 345fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport com.google.common.io.Files; 355fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport org.jf.dexlib2.iface.ClassDef; 365fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport org.jf.dexlib2.iface.Method; 375fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport org.jf.dexlib2.iface.instruction.InlineIndexInstruction; 385fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport org.jf.dexlib2.immutable.ImmutableMethod; 395fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport org.jf.dexlib2.immutable.ImmutableMethodParameter; 405fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport org.jf.dexlib2.immutable.reference.ImmutableMethodReference; 415fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport org.jf.dexlib2.immutable.util.ParamUtil; 425fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 435fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport javax.annotation.Nonnull; 445fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport java.io.*; 455fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport java.nio.charset.Charset; 465fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport java.util.ArrayList; 475fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport java.util.List; 485fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport java.util.regex.Matcher; 495fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverimport java.util.regex.Pattern; 505fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 515fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruverpublic class CustomInlineMethodResolver extends InlineMethodResolver { 525fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver @Nonnull private final ClassPath classPath; 535fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver @Nonnull private final Method[] inlineMethods; 545fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 555fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver public CustomInlineMethodResolver(@Nonnull ClassPath classPath, @Nonnull String inlineTable) { 565fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver this.classPath = classPath; 575fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 585fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver StringReader reader = new StringReader(inlineTable); 595fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver List<String> lines = new ArrayList<String>(); 605fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 615fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver BufferedReader br = new BufferedReader(reader); 625fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 635fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver try { 645fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver String line = br.readLine(); 655fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 665fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver while (line != null) { 675fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver if (line.length() > 0) { 685fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver lines.add(line); 695fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 705fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 715fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver line = br.readLine(); 725fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 735fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } catch (IOException ex) { 745fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver throw new RuntimeException("Error while parsing inline table", ex); 755fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 765fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 775fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver inlineMethods = new Method[lines.size()]; 785fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 795fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver for (int i=0; i<inlineMethods.length; i++) { 805fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver inlineMethods[i] = parseAndResolveInlineMethod(lines.get(i)); 815fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 825fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 835fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 845fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver public CustomInlineMethodResolver(@Nonnull ClassPath classPath, @Nonnull File inlineTable) throws IOException { 855fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver this(classPath, Files.toString(inlineTable, Charset.forName("UTF-8"))); 865fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 875fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 885fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver @Override 895fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver @Nonnull 905fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver public Method resolveExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) { 915fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver InlineIndexInstruction instruction = (InlineIndexInstruction)analyzedInstruction.instruction; 925fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver int methodIndex = instruction.getInlineIndex(); 935fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 945fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver if (methodIndex < 0 || methodIndex >= inlineMethods.length) { 955fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver throw new RuntimeException("Invalid method index: " + methodIndex); 965fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 975fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver return inlineMethods[methodIndex]; 985fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 995fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 1005fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver private static final Pattern longMethodPattern = Pattern.compile("(L[^;]+;)->([^(]+)\\(([^)]*)\\)(.+)"); 1015fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 1025fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver @Nonnull 1035fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver private Method parseAndResolveInlineMethod(@Nonnull String inlineMethod) { 1045fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver Matcher m = longMethodPattern.matcher(inlineMethod); 1055fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver if (!m.matches()) { 1065fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver assert false; 1075fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver throw new RuntimeException("Invalid method descriptor: " + inlineMethod); 1085fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 1095fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 1105fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver String className = m.group(1); 1115fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver String methodName = m.group(2); 1125fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver Iterable<ImmutableMethodParameter> methodParams = ParamUtil.parseParamString(m.group(3)); 1135fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver String methodRet = m.group(4); 1145fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver ImmutableMethodReference methodRef = new ImmutableMethodReference(className, methodName, methodParams, 1155fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver methodRet); 1165fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 1175fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver int accessFlags = 0; 1185fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 1195fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver boolean resolved = false; 1205fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver TypeProto typeProto = classPath.getClass(className); 1215fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver if (typeProto instanceof ClassProto) { 1225fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver ClassDef classDef = ((ClassProto)typeProto).getClassDef(); 1235fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver for (Method method: classDef.getMethods()) { 1245fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver if (method.equals(methodRef)) { 1255fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver resolved = true; 1265fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver accessFlags = method.getAccessFlags(); 1275fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver break; 1285fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 1295fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 1305fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 1315fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 1325fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver if (!resolved) { 1335fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver throw new RuntimeException("Cannot resolve inline method: " + inlineMethod); 1345fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 1355fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver 1365fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver return new ImmutableMethod(className, methodName, methodParams, methodRet, accessFlags, null, null); 1375fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver } 1385fa302678ce3a8e08fa8d2e8dbc5424781e751a6Ben Gruver} 139