CustomInlineMethodResolver.java revision 5fa302678ce3a8e08fa8d2e8dbc5424781e751a6
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