1/* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32package org.jf.dexlib2.analysis; 33 34import com.google.common.io.Files; 35import org.jf.dexlib2.iface.ClassDef; 36import org.jf.dexlib2.iface.Method; 37import org.jf.dexlib2.iface.instruction.InlineIndexInstruction; 38import org.jf.dexlib2.immutable.ImmutableMethod; 39import org.jf.dexlib2.immutable.ImmutableMethodParameter; 40import org.jf.dexlib2.immutable.reference.ImmutableMethodReference; 41import org.jf.dexlib2.immutable.util.ParamUtil; 42 43import javax.annotation.Nonnull; 44import java.io.*; 45import java.nio.charset.Charset; 46import java.util.ArrayList; 47import java.util.List; 48import java.util.regex.Matcher; 49import java.util.regex.Pattern; 50 51public class CustomInlineMethodResolver extends InlineMethodResolver { 52 @Nonnull private final ClassPath classPath; 53 @Nonnull private final Method[] inlineMethods; 54 55 public CustomInlineMethodResolver(@Nonnull ClassPath classPath, @Nonnull String inlineTable) { 56 this.classPath = classPath; 57 58 StringReader reader = new StringReader(inlineTable); 59 List<String> lines = new ArrayList<String>(); 60 61 BufferedReader br = new BufferedReader(reader); 62 63 try { 64 String line = br.readLine(); 65 66 while (line != null) { 67 if (line.length() > 0) { 68 lines.add(line); 69 } 70 71 line = br.readLine(); 72 } 73 } catch (IOException ex) { 74 throw new RuntimeException("Error while parsing inline table", ex); 75 } 76 77 inlineMethods = new Method[lines.size()]; 78 79 for (int i=0; i<inlineMethods.length; i++) { 80 inlineMethods[i] = parseAndResolveInlineMethod(lines.get(i)); 81 } 82 } 83 84 public CustomInlineMethodResolver(@Nonnull ClassPath classPath, @Nonnull File inlineTable) throws IOException { 85 this(classPath, Files.toString(inlineTable, Charset.forName("UTF-8"))); 86 } 87 88 @Override 89 @Nonnull 90 public Method resolveExecuteInline(@Nonnull AnalyzedInstruction analyzedInstruction) { 91 InlineIndexInstruction instruction = (InlineIndexInstruction)analyzedInstruction.instruction; 92 int methodIndex = instruction.getInlineIndex(); 93 94 if (methodIndex < 0 || methodIndex >= inlineMethods.length) { 95 throw new RuntimeException("Invalid method index: " + methodIndex); 96 } 97 return inlineMethods[methodIndex]; 98 } 99 100 private static final Pattern longMethodPattern = Pattern.compile("(L[^;]+;)->([^(]+)\\(([^)]*)\\)(.+)"); 101 102 @Nonnull 103 private Method parseAndResolveInlineMethod(@Nonnull String inlineMethod) { 104 Matcher m = longMethodPattern.matcher(inlineMethod); 105 if (!m.matches()) { 106 assert false; 107 throw new RuntimeException("Invalid method descriptor: " + inlineMethod); 108 } 109 110 String className = m.group(1); 111 String methodName = m.group(2); 112 Iterable<ImmutableMethodParameter> methodParams = ParamUtil.parseParamString(m.group(3)); 113 String methodRet = m.group(4); 114 ImmutableMethodReference methodRef = new ImmutableMethodReference(className, methodName, methodParams, 115 methodRet); 116 117 int accessFlags = 0; 118 119 boolean resolved = false; 120 TypeProto typeProto = classPath.getClass(className); 121 if (typeProto instanceof ClassProto) { 122 ClassDef classDef = ((ClassProto)typeProto).getClassDef(); 123 for (Method method: classDef.getMethods()) { 124 if (method.equals(methodRef)) { 125 resolved = true; 126 accessFlags = method.getAccessFlags(); 127 break; 128 } 129 } 130 } 131 132 if (!resolved) { 133 throw new RuntimeException("Cannot resolve inline method: " + inlineMethod); 134 } 135 136 return new ImmutableMethod(className, methodName, methodParams, methodRet, accessFlags, null, null); 137 } 138} 139