mirror of
https://github.com/pxb1988/dex2jar.git
synced 2024-11-27 07:00:51 +00:00
merge 0.0.9.9 to default
This commit is contained in:
commit
ba5fbc23bb
@ -100,7 +100,6 @@ public class Cfg {
|
||||
public static boolean notThrow(Stmt s) {
|
||||
switch (s.st) {
|
||||
case LABEL:
|
||||
case RETURN:
|
||||
case RETURN_VOID:
|
||||
case GOTO:
|
||||
case NOP:
|
||||
@ -111,8 +110,7 @@ public class Cfg {
|
||||
return notThrow(e2.op1.value) && notThrow(e2.op2.value);
|
||||
case TABLE_SWITCH:
|
||||
case LOOKUP_SWITCH:
|
||||
E1Stmt s1 = (E1Stmt) s;
|
||||
return notThrow(s1.op.value);
|
||||
case RETURN:
|
||||
case IF:
|
||||
return notThrow(((E1Stmt) s).op.value);
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ public class LocalSplit implements Transformer {
|
||||
if (v.vt == VT.LOCAL) {
|
||||
Phi p = frame[((Local) v)._ls_index];
|
||||
if (p.value == null) {
|
||||
Local local = new Local("a_" + localId[0]++);
|
||||
Local local = new Local("a" + localId[0]++);
|
||||
ValueBox nvb = new ValueBox(local);
|
||||
local._ls_vb = nvb;
|
||||
p.setLocal(local);
|
||||
@ -255,7 +255,7 @@ public class LocalSplit implements Transformer {
|
||||
Phi p = targetF[index];
|
||||
|
||||
if (p.value == null) {
|
||||
Local local = new Local("a_" + localId[0]++);
|
||||
Local local = new Local("a" + localId[0]++);
|
||||
ValueBox nvb = new ValueBox(local);
|
||||
local._ls_vb = nvb;
|
||||
p.setLocal(local);
|
||||
|
@ -172,6 +172,7 @@ public class LocalType implements Transformer {
|
||||
case LENGTH: {
|
||||
UnopExpr te = (UnopExpr) v;
|
||||
exec(te.op.value);
|
||||
type(te.op.value, Type.getType(Object.class));
|
||||
type(tb, Type.INT_TYPE);
|
||||
}
|
||||
break;
|
||||
|
@ -34,7 +34,7 @@
|
||||
<dependency>
|
||||
<groupId>pxb.bc</groupId>
|
||||
<artifactId>p-rename</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
|
23
dex-tools/src/main/bin/d2j-jar-access.bat
Normal file
23
dex-tools/src/main/bin/d2j-jar-access.bat
Normal file
@ -0,0 +1,23 @@
|
||||
@echo off
|
||||
|
||||
REM
|
||||
REM dex2jar - Tools to work with android .dex and java .class files
|
||||
REM Copyright (c) 2009-2012 Panxiaobo
|
||||
REM
|
||||
REM Licensed under the Apache License, Version 2.0 (the "License");
|
||||
REM you may not use this file except in compliance with the License.
|
||||
REM You may obtain a copy of the License at
|
||||
REM
|
||||
REM http://www.apache.org/licenses/LICENSE-2.0
|
||||
REM
|
||||
REM Unless required by applicable law or agreed to in writing, software
|
||||
REM distributed under the License is distributed on an "AS IS" BASIS,
|
||||
REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
REM See the License for the specific language governing permissions and
|
||||
REM limitations under the License.
|
||||
REM
|
||||
|
||||
set CLASSPATH=
|
||||
FOR %%i IN ("%~dp0lib\*.jar") DO CALL "%~dp0setclasspath.bat" %%i
|
||||
|
||||
java -Xms512m -Xmx1024m -cp "%CLASSPATH%" "com.googlecode.dex2jar.tools.JarAccessCmd" %*
|
40
dex-tools/src/main/bin/d2j-jar-access.sh
Normal file
40
dex-tools/src/main/bin/d2j-jar-access.sh
Normal file
@ -0,0 +1,40 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# dex2jar - Tools to work with android .dex and java .class files
|
||||
# Copyright (c) 2009-2012 Panxiaobo
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# copy from $Tomcat/bin/startup.sh
|
||||
# resolve links - $0 may be a softlink
|
||||
PRG="$0"
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`/"$link"
|
||||
fi
|
||||
done
|
||||
PRGDIR=`dirname "$PRG"`
|
||||
#
|
||||
|
||||
_classpath="."
|
||||
for k in "$PRGDIR"/lib/*.jar
|
||||
do
|
||||
_classpath="${_classpath}:${k}"
|
||||
done
|
||||
java -Xms512m -Xmx1024m -classpath "${_classpath}" "com.googlecode.dex2jar.tools.JarAccessCmd" $@
|
@ -32,6 +32,11 @@ public class DeObfInitCmd extends BaseCmd {
|
||||
@Opt(opt = "o", longOpt = "output", description = "output .jar file, default is $current_dir/[file-name]-deobf-init.txt", argName = "out-file")
|
||||
private File output;
|
||||
|
||||
@Opt(opt = "min", longOpt = "min-length", description = "do the rename if the length < MIN, default is 2", argName = "MIN")
|
||||
private int min = 2;
|
||||
@Opt(opt = "max", longOpt = "max-length", description = "do the rename if the length > MIN, default is 40", argName = "MAX")
|
||||
private int max = 40;
|
||||
|
||||
public DeObfInitCmd() {
|
||||
super("d2j-init-deobf [options] <jar>", "generate an init config file for deObfuscate a jar");
|
||||
}
|
||||
@ -63,7 +68,7 @@ public class DeObfInitCmd extends BaseCmd {
|
||||
return;
|
||||
}
|
||||
System.out.println("generate " + jar + " -> " + output);
|
||||
new InitOut().from(jar).to(output);
|
||||
new InitOut().from(jar).maxLength(max).minLength(min).to(output);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -52,6 +52,12 @@ public class Dex2jarCmd extends BaseCmd {
|
||||
@Opt(opt = "d", longOpt = "debug-info", hasArg = false, description = "translate debug info")
|
||||
private boolean debugInfo = false;
|
||||
|
||||
@Opt(opt = "p", longOpt = "print-ir", hasArg = false, description = "print ir to Syste.out")
|
||||
private boolean printIR = false;
|
||||
|
||||
@Opt(opt = "os", longOpt = "optmize-synchronized", hasArg = false, description = "optmize-synchronized")
|
||||
private boolean optmizeSynchronized = false;
|
||||
|
||||
public Dex2jarCmd() {
|
||||
super("d2j-dex2jar [options] <file0> [file1 ... fileN]", "convert dex to jar");
|
||||
}
|
||||
@ -93,14 +99,14 @@ public class Dex2jarCmd extends BaseCmd {
|
||||
|
||||
for (String fileName : remainingArgs) {
|
||||
File file = output == null ? new File(FilenameUtils.getBaseName(fileName) + "-dex2jar.jar") : output;
|
||||
System.out.println("dex2jar " + fileName + " -> " + file);
|
||||
System.err.println("dex2jar " + fileName + " -> " + file);
|
||||
|
||||
DexFileReader reader = new DexFileReader(new File(fileName));
|
||||
DexExceptionHandlerImpl handler = notHandleException ? null : new DexExceptionHandlerImpl()
|
||||
.skipDebug(!debugInfo);
|
||||
|
||||
Dex2jar.from(reader).withExceptionHandler(handler).reUseReg(reuseReg).topoLogicalSort(topologicalSort)
|
||||
.skipDebug(!debugInfo).to(file);
|
||||
.skipDebug(!debugInfo).optimizeSynchronized(this.optmizeSynchronized).printIR(printIR).to(file);
|
||||
|
||||
if (!notHandleException) {
|
||||
Map<Method, Exception> exceptions = handler.getExceptions();
|
||||
|
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* dex2jar - Tools to work with android .dex and java .class files
|
||||
* Copyright (c) 2009-2012 Panxiaobo
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.googlecode.dex2jar.tools;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.objectweb.asm.ClassAdapter;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import p.rn.util.FileOut;
|
||||
import p.rn.util.FileOut.OutHandler;
|
||||
import p.rn.util.FileWalker;
|
||||
import p.rn.util.FileWalker.StreamHandler;
|
||||
import p.rn.util.FileWalker.StreamOpener;
|
||||
|
||||
public class JarAccessCmd extends BaseCmd {
|
||||
public static void main(String[] args) {
|
||||
new JarAccessCmd().doMain(args);
|
||||
}
|
||||
|
||||
public JarAccessCmd() {
|
||||
super("d2j-jar-access [options] <jar>", "add or remove class/method/field access in jar file");
|
||||
}
|
||||
|
||||
@Opt(opt = "f", longOpt = "force", hasArg = false, description = "force overwrite")
|
||||
private boolean forceOverwrite = false;
|
||||
@Opt(opt = "o", longOpt = "output", description = "output dir of .j files, default is $current_dir/[jar-name]-access.jar", argName = "out-dir")
|
||||
private File output;
|
||||
|
||||
@Opt(opt = "rd", longOpt = "remove-debug", hasArg = false, description = "remove debug info")
|
||||
private boolean removeDebug = false;
|
||||
|
||||
@Opt(opt = "rf", longOpt = "remove-field-access", description = "remove access from field", argName = "ACC")
|
||||
private String removeFieldAccess;
|
||||
@Opt(opt = "rm", longOpt = "remove-method-access", description = "remove access from method", argName = "ACC")
|
||||
private String removeMethodAccess;
|
||||
@Opt(opt = "rc", longOpt = "remove-class-access", description = "remove access from class", argName = "ACC")
|
||||
private String removeClassAccess;
|
||||
@Opt(opt = "af", longOpt = "add-field-access", description = "add access from field", argName = "ACC")
|
||||
private String addFieldAccess;
|
||||
@Opt(opt = "am", longOpt = "add-method-access", description = "add access from method", argName = "ACC")
|
||||
private String addMethodAccess;
|
||||
@Opt(opt = "ac", longOpt = "add-class-access", description = "add access from class", argName = "ACC")
|
||||
private String addClassAccess;
|
||||
|
||||
static int str2acc(String s) {
|
||||
if (s == null) {
|
||||
return 0;
|
||||
}
|
||||
int result = 0;
|
||||
s = s.toLowerCase();
|
||||
if (s.contains("public")) {
|
||||
result |= Opcodes.ACC_PUBLIC;
|
||||
}
|
||||
if (s.contains("private")) {
|
||||
result |= Opcodes.ACC_PRIVATE;
|
||||
}
|
||||
if (s.contains("protected")) {
|
||||
result |= Opcodes.ACC_PROTECTED;
|
||||
}
|
||||
if (s.contains("final")) {
|
||||
result |= Opcodes.ACC_FINAL;
|
||||
}
|
||||
if (s.contains("static")) {
|
||||
result |= Opcodes.ACC_STATIC;
|
||||
}
|
||||
if (s.contains("super")) {
|
||||
result |= Opcodes.ACC_SUPER;
|
||||
}
|
||||
if (s.contains("synchronized")) {
|
||||
result |= Opcodes.ACC_SYNCHRONIZED;
|
||||
}
|
||||
if (s.contains("volatile")) {
|
||||
result |= Opcodes.ACC_VOLATILE;
|
||||
}
|
||||
if (s.contains("bridge")) {
|
||||
result |= Opcodes.ACC_BRIDGE;
|
||||
}
|
||||
if (s.contains("transient")) {
|
||||
result |= Opcodes.ACC_TRANSIENT;
|
||||
}
|
||||
if (s.contains("varargs")) {
|
||||
result |= Opcodes.ACC_VARARGS;
|
||||
}
|
||||
if (s.contains("native")) {
|
||||
result |= Opcodes.ACC_NATIVE;
|
||||
}
|
||||
if (s.contains("strict")) {
|
||||
result |= Opcodes.ACC_STRICT;
|
||||
}
|
||||
if (s.contains("interface")) {
|
||||
result |= Opcodes.ACC_INTERFACE;
|
||||
}
|
||||
if (s.contains("abstract")) {
|
||||
result |= Opcodes.ACC_ABSTRACT;
|
||||
}
|
||||
if (s.contains("synthetic")) {
|
||||
result |= Opcodes.ACC_SYNTHETIC;
|
||||
}
|
||||
if (s.contains("annotation")) {
|
||||
result |= Opcodes.ACC_ANNOTATION;
|
||||
}
|
||||
if (s.contains("enum")) {
|
||||
result |= Opcodes.ACC_ENUM;
|
||||
}
|
||||
if (s.contains("deprecated")) {
|
||||
result |= Opcodes.ACC_DEPRECATED;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doCommandLine() throws Exception {
|
||||
if (remainingArgs.length != 1) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
File jar = new File(remainingArgs[0]);
|
||||
if (!jar.exists()) {
|
||||
System.err.println(jar + " is not exists");
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (output == null) {
|
||||
if (jar.isDirectory()) {
|
||||
output = new File(jar.getName() + "-access.jar");
|
||||
} else {
|
||||
output = new File(FilenameUtils.getBaseName(jar.getName()) + "-access.jar");
|
||||
}
|
||||
}
|
||||
|
||||
if (output.exists() && !forceOverwrite) {
|
||||
System.err.println(output + " exists, use --force to overwrite");
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
final int rf = ~str2acc(removeFieldAccess);
|
||||
final int rm = ~str2acc(removeMethodAccess);
|
||||
final int rc = ~str2acc(removeClassAccess);
|
||||
|
||||
final int af = str2acc(addFieldAccess);
|
||||
final int am = str2acc(addMethodAccess);
|
||||
final int ac = str2acc(addClassAccess);
|
||||
|
||||
final int flags = removeDebug ? ClassReader.SKIP_DEBUG : 0;
|
||||
final OutHandler fo = FileOut.create(output, true);
|
||||
try {
|
||||
new FileWalker().withStreamHandler(new StreamHandler() {
|
||||
|
||||
@Override
|
||||
public void handle(boolean isDir, String name, StreamOpener current, Object nameObject)
|
||||
throws IOException {
|
||||
if (isDir || !name.endsWith(".class")) {
|
||||
fo.write(isDir, name, current == null ? null : current.get(), nameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
OutputStream os = null;
|
||||
try {
|
||||
InputStream is = current.get();
|
||||
final ClassReader r = new ClassReader(is);
|
||||
ClassWriter cr = new ClassWriter(0);
|
||||
r.accept(new ClassAdapter(cr) {
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName,
|
||||
String[] interfaces) {
|
||||
int na = (access & rc) | ac;
|
||||
if (access != na) {
|
||||
System.out.println("c " + name);
|
||||
}
|
||||
super.visit(version, na, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature,
|
||||
Object value) {
|
||||
int na = (access & rf) | af;
|
||||
if (na != access) {
|
||||
System.out.println("f " + r.getClassName() + "." + name);
|
||||
}
|
||||
return super.visitField(na, name, desc, signature, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
|
||||
String[] exceptions) {
|
||||
int na = (access & rm) | am;
|
||||
if (na != access) {
|
||||
System.out.println("m " + r.getClassName() + "." + name + desc);
|
||||
}
|
||||
return super.visitMethod(na, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
}, flags | ClassReader.EXPAND_FRAMES);
|
||||
fo.write(isDir, name, cr.toByteArray(), nameObject);
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("error in " + name);
|
||||
ioe.printStackTrace(System.err);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(os);
|
||||
}
|
||||
}
|
||||
}).walk(jar);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(fo);
|
||||
}
|
||||
}
|
||||
}
|
@ -333,7 +333,7 @@ public class JasminifierClassAdapter extends ClassAdapter {
|
||||
for (int j = 0; j < mn.tryCatchBlocks.size(); ++j) {
|
||||
TryCatchBlockNode tcb = (TryCatchBlockNode) mn.tryCatchBlocks.get(j);
|
||||
pw.print(".catch ");
|
||||
pw.print(tcb.type);
|
||||
pw.print(tcb.type == null ? "all" : tcb.type);
|
||||
pw.print(" from ");
|
||||
print(tcb.start);
|
||||
pw.print(" to ");
|
||||
|
@ -17,4 +17,5 @@ d2j-apk-sign=com.googlecode.dex2jar.tools.ApkSign
|
||||
|
||||
d2j-init-deobf=com.googlecode.dex2jar.tools.DeObfInitCmd
|
||||
d2j-jar-remap=com.googlecode.dex2jar.tools.JarRemap
|
||||
d2j-jar-access=com.googlecode.dex2jar.tools.JarAccessCmd
|
||||
#EOF
|
||||
|
@ -132,11 +132,39 @@ public class Dex2jar {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Dex2jar optimizeSynchronized(boolean b) {
|
||||
if (b) {
|
||||
this.v3Config |= V3.OPTIMIZE_SYNCHRONIZED;
|
||||
} else {
|
||||
this.v3Config &= ~V3.OPTIMIZE_SYNCHRONIZED;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Dex2jar printIR(boolean b) {
|
||||
if (b) {
|
||||
this.v3Config |= V3.PRINT_IR;
|
||||
} else {
|
||||
this.v3Config &= ~V3.PRINT_IR;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Dex2jar reUseReg() {
|
||||
this.v3Config |= V3.REUSE_REGISTER;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Dex2jar optimizeSynchronized() {
|
||||
this.v3Config |= V3.OPTIMIZE_SYNCHRONIZED;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Dex2jar printIR() {
|
||||
this.v3Config |= V3.PRINT_IR;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Dex2jar topoLogicalSort() {
|
||||
this.v3Config |= V3.TOPOLOGICAL_SORT;
|
||||
return this;
|
||||
|
@ -4,7 +4,9 @@ import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
@ -14,8 +16,8 @@ import org.objectweb.asm.Type;
|
||||
import com.googlecode.dex2jar.DexException;
|
||||
import com.googlecode.dex2jar.ir.Constant;
|
||||
import com.googlecode.dex2jar.ir.IrMethod;
|
||||
import com.googlecode.dex2jar.ir.LocalVar;
|
||||
import com.googlecode.dex2jar.ir.Local;
|
||||
import com.googlecode.dex2jar.ir.LocalVar;
|
||||
import com.googlecode.dex2jar.ir.Trap;
|
||||
import com.googlecode.dex2jar.ir.Value;
|
||||
import com.googlecode.dex2jar.ir.Value.E1Expr;
|
||||
@ -49,16 +51,28 @@ import com.googlecode.dex2jar.ir.ts.LocalType;
|
||||
public class IrMethod2AsmMethod implements Opcodes {
|
||||
|
||||
private boolean reuseReg = false;
|
||||
private boolean optimizeSynchronized = false;
|
||||
|
||||
public IrMethod2AsmMethod() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #IrMethod2AsmMethod(int)} instead
|
||||
*
|
||||
* @param reuseReg
|
||||
*/
|
||||
public IrMethod2AsmMethod(boolean reuseReg) {
|
||||
super();
|
||||
this.reuseReg = reuseReg;
|
||||
}
|
||||
|
||||
public IrMethod2AsmMethod(int config) {
|
||||
super();
|
||||
this.reuseReg = 0 != (config & V3.REUSE_REGISTER);
|
||||
this.optimizeSynchronized = 0 != (config & V3.OPTIMIZE_SYNCHRONIZED);
|
||||
}
|
||||
|
||||
private void reIndexLocalReuseReg(IrMethod ir) {
|
||||
|
||||
if (V3.DEBUG) {
|
||||
@ -358,6 +372,38 @@ public class IrMethod2AsmMethod implements Opcodes {
|
||||
}
|
||||
|
||||
private void reBuildInstructions(IrMethod ir, MethodVisitor asm) {
|
||||
Map<String, Integer> lockMap = new HashMap<String, Integer>();
|
||||
int maxLocalIndex;
|
||||
{
|
||||
if (ir.locals.size() == 0) {
|
||||
maxLocalIndex = 0;
|
||||
} else {
|
||||
Local maxLoale = Collections.max(ir.locals, new Comparator<Local>() {
|
||||
|
||||
@Override
|
||||
public int compare(Local o1, Local o2) {
|
||||
int i = o1._ls_index - o2._ls_index;
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
Type t1 = LocalType.typeOf(o1);
|
||||
if (t1 == null) {
|
||||
return -1;
|
||||
}
|
||||
Type t2 = LocalType.typeOf(o2);
|
||||
if (t2 == null) {
|
||||
return 1;
|
||||
}
|
||||
return t1.getSize() - t2.getSize();
|
||||
}
|
||||
});
|
||||
if (maxLoale == null || maxLoale._ls_index < 0) {
|
||||
maxLocalIndex = 0;
|
||||
} else {
|
||||
maxLocalIndex = maxLoale._ls_index + LocalType.typeOf(maxLoale).getSize() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Stmt st : ir.stmts) {
|
||||
switch (st.st) {
|
||||
case LABEL:
|
||||
@ -456,13 +502,63 @@ public class IrMethod2AsmMethod implements Opcodes {
|
||||
case IF:
|
||||
reBuildJumpInstructions((JumpStmt) st, asm);
|
||||
break;
|
||||
case LOCK:
|
||||
accept(((UnopStmt) st).op.value, asm);
|
||||
case LOCK: {
|
||||
Value v = ((UnopStmt) st).op.value;
|
||||
accept(v, asm);
|
||||
if (optimizeSynchronized) {
|
||||
switch (v.vt) {
|
||||
case LOCAL:
|
||||
case CONSTANT: {
|
||||
String key;
|
||||
if (v.vt == VT.LOCAL) {
|
||||
key = "L" + ((Local) v)._ls_index;
|
||||
} else {
|
||||
key = "C" + ((Constant) v).value;
|
||||
}
|
||||
Integer integer = lockMap.get(key);
|
||||
int nIndex = integer != null ? integer : ++maxLocalIndex;
|
||||
asm.visitInsn(DUP);
|
||||
asm.visitVarInsn(LocalType.typeOf(v).getOpcode(ISTORE), nIndex);
|
||||
lockMap.put(key, nIndex);
|
||||
}
|
||||
break;
|
||||
// TODO other
|
||||
}
|
||||
}
|
||||
asm.visitInsn(MONITORENTER);
|
||||
}
|
||||
break;
|
||||
case UNLOCK:
|
||||
accept(((UnopStmt) st).op.value, asm);
|
||||
case UNLOCK: {
|
||||
Value v = ((UnopStmt) st).op.value;
|
||||
if (optimizeSynchronized) {
|
||||
switch (v.vt) {
|
||||
case LOCAL:
|
||||
case CONSTANT: {
|
||||
String key;
|
||||
if (v.vt == VT.LOCAL) {
|
||||
key = "L" + ((Local) v)._ls_index;
|
||||
} else {
|
||||
key = "C" + ((Constant) v).value;
|
||||
}
|
||||
Integer integer = lockMap.get(key);
|
||||
if (integer != null) {
|
||||
asm.visitVarInsn(LocalType.typeOf(v).getOpcode(ILOAD), integer);
|
||||
} else {
|
||||
accept(v, asm);
|
||||
}
|
||||
}
|
||||
break;
|
||||
// TODO other
|
||||
default: {
|
||||
accept(v, asm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
accept(v, asm);
|
||||
}
|
||||
asm.visitInsn(MONITOREXIT);
|
||||
}
|
||||
break;
|
||||
case NOP:
|
||||
break;
|
||||
|
@ -64,6 +64,7 @@ public class Main {
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
System.err.println("this cmd is deprecated, use the d2j-dex2jar if possible");
|
||||
System.out.println("dex2jar version: translator-" + Main.class.getPackage().getImplementationVersion());
|
||||
if (args.length == 0) {
|
||||
System.err.println("dex2jar file1.dexORapk file2.dexORapk ...");
|
||||
|
@ -32,6 +32,8 @@ public class V3 implements DexFileVisitor {
|
||||
|
||||
public static final int REUSE_REGISTER = 1 << 0;
|
||||
public static final int TOPOLOGICAL_SORT = 1 << 1;
|
||||
public static final int PRINT_IR = 1 << 2;
|
||||
public static final int OPTIMIZE_SYNCHRONIZED = 1 << 3;
|
||||
protected ClassVisitorFactory cvf;
|
||||
protected Map<String, Integer> accessFlagsMap;
|
||||
protected Map<String, String> innerNameMap;
|
||||
|
@ -95,21 +95,25 @@ public class V3AccessFlagsAdapter implements DexFileVisitor {
|
||||
}
|
||||
for (Annotation ann : anns) {
|
||||
if ("Ldalvik/annotation/InnerClass;".equals(ann.type)) {
|
||||
Integer acc = null;
|
||||
String name = null;
|
||||
for (Item it : ann.items) {
|
||||
if ("accessFlags".equals(it.name)) {
|
||||
map.put(className, (Integer) it.value);
|
||||
acc = (Integer) it.value;
|
||||
} else if ("name".equals(it.name)) {
|
||||
innerNameMap.put(className, (String) it.value);
|
||||
if (it.value == null) {
|
||||
Set<String> set = extraMember.get(enclosingClass);
|
||||
if (set == null) {
|
||||
set = new TreeSet<String>();
|
||||
extraMember.put(enclosingClass, set);
|
||||
}
|
||||
set.add(className);
|
||||
}
|
||||
name = (String) it.value;
|
||||
}
|
||||
}
|
||||
map.put(className, acc);
|
||||
innerNameMap.put(className, name);
|
||||
if (name == null) {
|
||||
Set<String> set = extraMember.get(enclosingClass);
|
||||
if (set == null) {
|
||||
set = new TreeSet<String>();
|
||||
extraMember.put(enclosingClass, set);
|
||||
}
|
||||
set.add(className);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,12 @@ package com.googlecode.dex2jar.v3;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
@ -87,6 +89,7 @@ public class V3ClassAdapter implements DexClassVisitor {
|
||||
if (!build) {
|
||||
String signature = null;
|
||||
String enclosingClass = null;
|
||||
Method enclosingMethod = null;
|
||||
for (Iterator<Annotation> it = anns.iterator(); it.hasNext();) {
|
||||
Annotation ann = it.next();
|
||||
if ("Ldalvik/annotation/Signature;".equals(ann.type)) {
|
||||
@ -109,10 +112,10 @@ public class V3ClassAdapter implements DexClassVisitor {
|
||||
}
|
||||
}
|
||||
} else if (ann.type.equals("Ldalvik/annotation/EnclosingMethod;")) {
|
||||
it.remove();
|
||||
for (Item i : ann.items) {
|
||||
if ("value".equals(i.name)) {
|
||||
Method m = (Method) i.value;
|
||||
enclosingClass = m.getOwner();
|
||||
enclosingMethod = (Method) i.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,27 +150,24 @@ public class V3ClassAdapter implements DexClassVisitor {
|
||||
cv.visit(Opcodes.V1_6, accessInClass, Type.getType(className).getInternalName(), signature,
|
||||
superClass == null ? null : Type.getType(superClass).getInternalName(), nInterfaceNames);
|
||||
|
||||
Set<String> extraMember = extraMemberClass.get(className);
|
||||
|
||||
if (extraMember != null) {
|
||||
for (String innerName : extraMember) {
|
||||
cv.visitInnerClass(Type.getType(innerName).getInternalName(), null, null, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for (Annotation ann : anns) {
|
||||
if (ann.type.equals("Ldalvik/annotation/MemberClasses;")) {
|
||||
Set<String> extraMember = extraMemberClass.get(className);
|
||||
extraMember = extraMember == null ? new TreeSet<String>() : new TreeSet<String>(extraMember);
|
||||
for (Item i : ann.items) {
|
||||
if (i.name.equals("value")) {
|
||||
for (Item j : ((Annotation) i.value).items) {
|
||||
String name = j.value.toString();
|
||||
Integer access = innerAccessFlagsMap.get(name);
|
||||
String innerName = innerNameMap.get(name);
|
||||
cv.visitInnerClass(Type.getType(name).getInternalName(), Type.getType(className)
|
||||
.getInternalName(), innerName, access == null ? 0 : access);
|
||||
extraMember.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (String name : extraMember) {
|
||||
Integer access = innerAccessFlagsMap.get(name);
|
||||
String innerName = innerNameMap.get(name);
|
||||
cv.visitInnerClass(Type.getType(name).getInternalName(), Type.getType(className)
|
||||
.getInternalName(), innerName, access == null ? 0 : access);
|
||||
}
|
||||
continue;
|
||||
} else if (ann.type.equals("Ldalvik/annotation/InnerClass;")) {
|
||||
String name = null;
|
||||
@ -178,24 +178,21 @@ public class V3ClassAdapter implements DexClassVisitor {
|
||||
}
|
||||
int accessInInnerClassAttr = access_flags & (~Opcodes.ACC_SUPER);// inner class attr has no
|
||||
// acc_super
|
||||
if (enclosingMethod != null) {
|
||||
cv.visitOuterClass(Type.getType(enclosingMethod.getOwner()).getInternalName(),
|
||||
enclosingMethod.getName(), enclosingMethod.getDesc());
|
||||
}
|
||||
|
||||
if (name == null) {
|
||||
cv.visitOuterClass(Type.getType(enclosingClass).getInternalName(), null, null);
|
||||
if (enclosingMethod == null) {
|
||||
cv.visitOuterClass(Type.getType(enclosingClass).getInternalName(), null, null);
|
||||
}
|
||||
cv.visitInnerClass(Type.getType(className).getInternalName(), null, null,
|
||||
accessInInnerClassAttr);
|
||||
} else {
|
||||
cv.visitInnerClass(Type.getType(className).getInternalName(), Type.getType(enclosingClass)
|
||||
.getInternalName(), name, accessInInnerClassAttr);
|
||||
}
|
||||
|
||||
continue;
|
||||
} else if (ann.type.equals("Ldalvik/annotation/EnclosingMethod;")) {
|
||||
for (Item it : ann.items) {
|
||||
if ("value".equals(it.name)) {
|
||||
Method m = (Method) it.value;
|
||||
cv.visitOuterClass(Type.getType(m.getOwner()).getInternalName(), m.getName(), m.getDesc());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
AnnotationVisitor av = cv.visitAnnotation(ann.type, ann.visible);
|
||||
|
@ -29,6 +29,7 @@ import org.objectweb.asm.util.TraceMethodVisitor;
|
||||
|
||||
import com.googlecode.dex2jar.Annotation;
|
||||
import com.googlecode.dex2jar.Annotation.Item;
|
||||
import com.googlecode.dex2jar.DexOpcodes;
|
||||
import com.googlecode.dex2jar.Method;
|
||||
import com.googlecode.dex2jar.asm.LdcOptimizeAdapter;
|
||||
import com.googlecode.dex2jar.ir.IrMethod;
|
||||
@ -97,7 +98,9 @@ public class V3MethodAdapter implements DexMethodVisitor, Opcodes {
|
||||
public V3MethodAdapter(int accessFlags, Method method, DexExceptionHandler exceptionHandler, int config) {
|
||||
super();
|
||||
this.method = method;
|
||||
this.accessFlags = accessFlags;
|
||||
// clear ACC_DECLARED_SYNCHRONIZED and ACC_CONSTRUCTOR from method flags
|
||||
final int cleanFlag = ~((DexOpcodes.ACC_DECLARED_SYNCHRONIZED | DexOpcodes.ACC_CONSTRUCTOR));
|
||||
this.accessFlags = accessFlags & cleanFlag;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
this.config = config;
|
||||
// issue 88, the desc must set before visitParameterAnnotation
|
||||
@ -218,8 +221,11 @@ public class V3MethodAdapter implements DexMethodVisitor, Opcodes {
|
||||
indexLabelStmt4Debug(irMethod.stmts);
|
||||
}
|
||||
}
|
||||
new IrMethod2AsmMethod(0 != (config & V3.REUSE_REGISTER)).convert(irMethod, new LdcOptimizeAdapter(
|
||||
methodNode));
|
||||
if (0 != (config & V3.PRINT_IR)) {
|
||||
indexLabelStmt4Debug(irMethod.stmts);
|
||||
System.out.println(irMethod);
|
||||
}
|
||||
new IrMethod2AsmMethod(config).convert(irMethod, new LdcOptimizeAdapter(methodNode));
|
||||
} catch (Exception e) {
|
||||
if (this.exceptionHandler == null) {
|
||||
throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
|
||||
|
@ -0,0 +1,90 @@
|
||||
package com.googlecode.dex2jar.test;
|
||||
|
||||
import static com.googlecode.dex2jar.DexOpcodes.ACC_PUBLIC;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.ACC_STATIC;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_AGET;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_APUT;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_ARRAY_LENGTH;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_CONST;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_INVOKE_VIRTUAL;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_RETURN_VOID;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.TYPE_INT;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.TYPE_SINGLE;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.analysis.AnalyzerException;
|
||||
|
||||
import com.googlecode.dex2jar.Method;
|
||||
import com.googlecode.dex2jar.v3.V3;
|
||||
import com.googlecode.dex2jar.visitors.DexClassVisitor;
|
||||
import com.googlecode.dex2jar.visitors.DexCodeVisitor;
|
||||
import com.googlecode.dex2jar.visitors.DexMethodVisitor;
|
||||
|
||||
public class ArrayTypeTest {
|
||||
|
||||
public static void a120(DexClassVisitor cv) {
|
||||
DexMethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, new Method("La;", "b", new String[] {}, "V"));
|
||||
DexCodeVisitor code = mv.visitCode();
|
||||
code.visitArguments(3, new int[] {});
|
||||
code.visitConstStmt(OP_CONST, 0, Integer.valueOf(0), TYPE_SINGLE);
|
||||
code.visitMethodStmt(OP_INVOKE_VIRTUAL, new int[] { 0 }, new Method("Ljava/lang/String;", "toString",
|
||||
new String[] {}, "Ljava/lang/String;"));
|
||||
code.visitConstStmt(OP_CONST, 1, Integer.valueOf(0), TYPE_SINGLE);
|
||||
code.visitUnopStmt(OP_ARRAY_LENGTH, 2, 1, TYPE_INT);
|
||||
code.visitReturnStmt(OP_RETURN_VOID);
|
||||
code.visitEnd();
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
public static void a122(DexClassVisitor cv) {
|
||||
DexMethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, new Method("La;", "b", new String[] {}, "V"));
|
||||
DexCodeVisitor code = mv.visitCode();
|
||||
code.visitArguments(3, new int[] {});
|
||||
code.visitConstStmt(OP_CONST, 0, Integer.valueOf(0), TYPE_SINGLE);
|
||||
code.visitConstStmt(OP_CONST, 2, Integer.valueOf(1), TYPE_SINGLE);
|
||||
code.visitArrayStmt(OP_AGET, 1, 0, 2, TYPE_SINGLE);
|
||||
code.visitReturnStmt(OP_RETURN_VOID);
|
||||
code.visitEnd();
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
public static void a123(DexClassVisitor cv) {
|
||||
DexMethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, new Method("La;", "b", new String[] {}, "V"));
|
||||
DexCodeVisitor code = mv.visitCode();
|
||||
code.visitArguments(3, new int[] {});
|
||||
code.visitConstStmt(OP_CONST, 0, 0, TYPE_SINGLE);
|
||||
code.visitConstStmt(OP_CONST, 1, 1, TYPE_SINGLE);
|
||||
code.visitConstStmt(OP_CONST, 2, 0x63, TYPE_SINGLE);
|
||||
code.visitArrayStmt(OP_APUT, 2, 0, 1, TYPE_SINGLE);
|
||||
code.visitReturnStmt(OP_RETURN_VOID);
|
||||
code.visitEnd();
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test120() throws IllegalArgumentException, IllegalAccessException, AnalyzerException {
|
||||
TestDexClassV cv = new TestDexClassV("Lt", V3.OPTIMIZE_SYNCHRONIZED | V3.TOPOLOGICAL_SORT);
|
||||
a120(cv);
|
||||
ClassReader cr = new ClassReader(cv.toByteArray());
|
||||
TestUtils.verify(cr);
|
||||
}
|
||||
|
||||
// FIXME issue 122
|
||||
// @Test
|
||||
public void test122() throws IllegalArgumentException, IllegalAccessException, AnalyzerException {
|
||||
TestDexClassV cv = new TestDexClassV("Lt", V3.OPTIMIZE_SYNCHRONIZED | V3.TOPOLOGICAL_SORT);
|
||||
a123(cv);
|
||||
ClassReader cr = new ClassReader(cv.toByteArray());
|
||||
TestUtils.verify(cr);
|
||||
}
|
||||
|
||||
// FIXME issue 123
|
||||
// @Test
|
||||
public void test123() throws IllegalArgumentException, IllegalAccessException, AnalyzerException {
|
||||
TestDexClassV cv = new TestDexClassV("Lt", V3.OPTIMIZE_SYNCHRONIZED | V3.TOPOLOGICAL_SORT);
|
||||
a122(cv);
|
||||
ClassReader cr = new ClassReader(cv.toByteArray());
|
||||
TestUtils.verify(cr);
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.googlecode.dex2jar.test;
|
||||
|
||||
import static com.googlecode.dex2jar.DexOpcodes.ACC_PUBLIC;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.ACC_STATIC;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_CONST_STRING;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_INVOKE_VIRTUAL;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_MOVE_EXCEPTION;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_RETURN_VOID;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
|
||||
import com.googlecode.dex2jar.DexLabel;
|
||||
import com.googlecode.dex2jar.Method;
|
||||
import com.googlecode.dex2jar.v3.V3;
|
||||
import com.googlecode.dex2jar.visitors.DexClassVisitor;
|
||||
import com.googlecode.dex2jar.visitors.DexCodeVisitor;
|
||||
import com.googlecode.dex2jar.visitors.DexMethodVisitor;
|
||||
|
||||
public class I101Test {
|
||||
|
||||
public static void a(DexClassVisitor cv) {
|
||||
DexMethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, new Method("La;", "b", new String[] {}, "V"));
|
||||
DexCodeVisitor code = mv.visitCode();
|
||||
code.visitArguments(2, new int[] {});
|
||||
DexLabel L0 = new DexLabel();
|
||||
DexLabel L1 = new DexLabel();
|
||||
DexLabel L2 = new DexLabel();
|
||||
code.visitTryCatch(L0, L1, L2, "Lsome/Exception;");
|
||||
|
||||
code.visitLabel(L0);
|
||||
code.visitConstStmt(OP_CONST_STRING, 0, "abc", 2);
|
||||
code.visitLabel(L1);
|
||||
|
||||
code.visitMethodStmt(OP_INVOKE_VIRTUAL, new int[] { 0 }, new Method("Ljava/lang/String;", "toString",
|
||||
new String[] {}, "Ljava/lang/String;"));
|
||||
code.visitReturnStmt(OP_RETURN_VOID);
|
||||
code.visitLabel(L2);
|
||||
code.visitMoveStmt(OP_MOVE_EXCEPTION, 1, 2);
|
||||
code.visitMethodStmt(OP_INVOKE_VIRTUAL, new int[] { 1 }, new Method("Ljava/lang/String;", "toString",
|
||||
new String[] {}, "Ljava/lang/String;"));
|
||||
code.visitReturnStmt(OP_RETURN_VOID);
|
||||
code.visitEnd();
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
TestDexClassV cv = new TestDexClassV("Lt", V3.OPTIMIZE_SYNCHRONIZED | V3.TOPOLOGICAL_SORT);
|
||||
a(cv);
|
||||
byte[] data = cv.toByteArray();
|
||||
ClassReader cr = new ClassReader(data);
|
||||
TestUtils.verify(cr);
|
||||
// FIXME java.lang.ClassFormatError: Illegal exception table range in class file Lt
|
||||
// CL cl = new CL();
|
||||
// cl.xxxDefine("Lt", data);
|
||||
}
|
||||
|
||||
static class CL extends ClassLoader {
|
||||
public Class<?> xxxDefine(String type, byte[] data) {
|
||||
return super.defineClass(type, data, 0, data.length);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.googlecode.dex2jar.test;
|
||||
|
||||
import static com.googlecode.dex2jar.DexOpcodes.ACC_PUBLIC;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.ACC_STATIC;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_CONST_STRING;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_GOTO;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_IF_EQZ;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_INVOKE_DIRECT;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_INVOKE_STATIC;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_MOVE_EXCEPTION;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_MOVE_RESULT;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_NEW_INSTANCE;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_RETURN;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.OP_THROW;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.TYPE_INT;
|
||||
import static com.googlecode.dex2jar.DexOpcodes.TYPE_OBJECT;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.analysis.AnalyzerException;
|
||||
|
||||
import com.googlecode.dex2jar.DexLabel;
|
||||
import com.googlecode.dex2jar.Method;
|
||||
import com.googlecode.dex2jar.v3.V3;
|
||||
import com.googlecode.dex2jar.visitors.DexClassVisitor;
|
||||
import com.googlecode.dex2jar.visitors.DexCodeVisitor;
|
||||
import com.googlecode.dex2jar.visitors.DexMethodVisitor;
|
||||
|
||||
public class I121Test {
|
||||
|
||||
public static void a(DexClassVisitor cv) {
|
||||
DexMethodVisitor mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, new Method("La;", "a", new String[] {
|
||||
"Ljava/lang/String;", "Ljava/lang/String;" }, "Ljava/lang/String;"));
|
||||
DexCodeVisitor code = mv.visitCode();
|
||||
int p0 = 2;
|
||||
int p1 = 3;
|
||||
int v0 = 0;
|
||||
int v1 = 1;
|
||||
|
||||
DexLabel cond_7 = new DexLabel();
|
||||
DexLabel try_start_2 = new DexLabel();
|
||||
DexLabel try_end_9 = new DexLabel();
|
||||
DexLabel catch_a = new DexLabel();
|
||||
DexLabel goto_2 = new DexLabel();
|
||||
|
||||
code.visitTryCatch(try_start_2, try_end_9, catch_a, "Ljava/io/UnsupportedEncodingException;");
|
||||
|
||||
code.visitArguments(3, new int[] { p0, p1 });
|
||||
|
||||
code.visitJumpStmt(OP_IF_EQZ, p1, cond_7);
|
||||
|
||||
code.visitLabel(goto_2);
|
||||
code.visitLabel(try_start_2);
|
||||
|
||||
code.visitMethodStmt(OP_INVOKE_STATIC, new int[] { p0, p1 }, new Method("Ljava/net/URLEncoder;", "encode",
|
||||
new String[] { "Ljava/lang/String;", "Ljava/lang/String;" }, "Ljava/lang/String;"));
|
||||
code.visitMoveStmt(OP_MOVE_RESULT, v0, TYPE_OBJECT);
|
||||
code.visitReturnStmt(OP_RETURN, v0, TYPE_OBJECT);
|
||||
code.visitLabel(cond_7);
|
||||
code.visitConstStmt(OP_CONST_STRING, p1, "ISO-8859-1", TYPE_OBJECT);
|
||||
|
||||
code.visitLabel(try_end_9);
|
||||
code.visitJumpStmt(OP_GOTO, goto_2);
|
||||
code.visitLabel(catch_a);
|
||||
code.visitMoveStmt(OP_MOVE_EXCEPTION, v0, TYPE_OBJECT);
|
||||
code.visitClassStmt(OP_NEW_INSTANCE, v1, "Ljava/lang/IllegalArgumentException;");
|
||||
code.visitMethodStmt(OP_INVOKE_DIRECT, new int[] { v1, v0 }, new Method("Ljava/lang/IllegalArgumentException;",
|
||||
"<init>", new String[] { "Ljava/lang/Throwable;" }, "V"));
|
||||
code.visitReturnStmt(OP_THROW, v1, TYPE_INT);
|
||||
code.visitEnd();
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() throws IllegalArgumentException, IllegalAccessException, AnalyzerException {
|
||||
TestDexClassV cv = new TestDexClassV("Lt", V3.OPTIMIZE_SYNCHRONIZED | V3.TOPOLOGICAL_SORT);
|
||||
a(cv);
|
||||
ClassReader cr = new ClassReader(cv.toByteArray());
|
||||
TestUtils.verify(cr);
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ import org.apache.commons.io.FilenameUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.googlecode.dex2jar.reader.DexFileReader;
|
||||
import com.googlecode.dex2jar.v3.Dex2jar;
|
||||
import com.googlecode.dex2jar.v3.Main;
|
||||
|
||||
/**
|
||||
@ -61,8 +62,7 @@ public class ResTest {
|
||||
try {
|
||||
File dex = TestUtils.dex(e.getValue(), new File(dir, name + ".dex"));
|
||||
File distFile = new File(dex.getParentFile(), FilenameUtils.getBaseName(dex.getName()) + "_dex2jar.jar");
|
||||
Main.doData(DexFileReader.readDex(dex), distFile, false);
|
||||
Main.doFile(dex, distFile);
|
||||
Dex2jar.from(dex).reUseReg().skipDebug().optimizeSynchronized().topoLogicalSort().to(distFile);
|
||||
TestUtils.checkZipFile(distFile);
|
||||
System.out.write('.');
|
||||
} catch (Exception ex) {
|
||||
@ -77,6 +77,9 @@ public class ResTest {
|
||||
System.out.flush();
|
||||
System.out.println();
|
||||
if (exes.size() > 0) {
|
||||
for (Exception ex : exes) {
|
||||
ex.printStackTrace(System.err);
|
||||
}
|
||||
throw new RuntimeException("there are " + exes.size() + " errors while translate");
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,40 @@
|
||||
package com.googlecode.dex2jar.test;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import com.googlecode.dex2jar.Method;
|
||||
import com.googlecode.dex2jar.v3.V3MethodAdapter;
|
||||
import com.googlecode.dex2jar.visitors.DexMethodVisitor;
|
||||
import com.googlecode.dex2jar.visitors.EmptyVisitor;
|
||||
|
||||
import org.junit.Ignore;
|
||||
|
||||
@Ignore
|
||||
public class TestDexClassV extends EmptyVisitor {
|
||||
private int config;
|
||||
private ClassWriter cw;
|
||||
|
||||
public TestDexClassV(String clz, int config) {
|
||||
super();
|
||||
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
|
||||
cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC, clz, null, "java/lang/Object", null);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public byte[] toByteArray() {
|
||||
cw.visitEnd();
|
||||
return cw.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexMethodVisitor visitMethod(int accessFlags, Method method) {
|
||||
return new V3MethodAdapter(accessFlags, method, null);
|
||||
return new V3MethodAdapter(accessFlags, method, null, config) {
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
methodNode.accept(cw);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,10 @@ package com.googlecode.dex2jar.test;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
@ -204,6 +206,15 @@ public abstract class TestUtils {
|
||||
|
||||
public static void verify(final ClassReader cr) throws AnalyzerException, IllegalArgumentException,
|
||||
IllegalAccessException {
|
||||
try {
|
||||
verify(cr, new PrintWriter(new OutputStreamWriter(System.out, "UTF-8")));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void verify(final ClassReader cr, PrintWriter out) throws AnalyzerException,
|
||||
IllegalArgumentException, IllegalAccessException {
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG);
|
||||
|
||||
@ -216,13 +227,10 @@ public abstract class TestUtils {
|
||||
try {
|
||||
a.analyze(cn.name, method);
|
||||
} catch (Exception e) {
|
||||
printAnalyzerResult(method, a, new PrintWriter(System.out));
|
||||
try {
|
||||
PrintWriter out = new PrintWriter("target/error.log", "utf8");
|
||||
printAnalyzerResult(method, a, out);
|
||||
out.close();
|
||||
} catch (Exception e2) {
|
||||
}
|
||||
out.println(cr.getClassName() + "." + method.name + method.desc);
|
||||
printAnalyzerResult(method, a, out);
|
||||
e.printStackTrace(out);
|
||||
out.flush();
|
||||
throw new DexException("method " + method.name + " " + method.desc, e);
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package com.googlecode.dex2jar.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -62,9 +63,11 @@ public class V3Test {
|
||||
|
||||
DexFileReader reader = new DexFileReader(data);
|
||||
V3AccessFlagsAdapter afa = new V3AccessFlagsAdapter();
|
||||
final List<String> exes = new ArrayList();
|
||||
final List<String> exes = new ArrayList<String>();
|
||||
reader.accept(afa, DexFileReader.SKIP_CODE | DexFileReader.SKIP_DEBUG);
|
||||
System.out.flush();
|
||||
String logFileName = "target/v3.log." + System.currentTimeMillis();
|
||||
final PrintWriter log = new PrintWriter(logFileName, "UTF-8");
|
||||
System.out.write(String.format("%05d ", 0).getBytes(UTF8));
|
||||
reader.accept(new V3(afa.getAccessFlagsMap(), afa.getInnerNameMap(), afa.getExtraMember(), null,
|
||||
new ClassVisitorFactory() {
|
||||
@ -80,7 +83,7 @@ public class V3Test {
|
||||
super.visitEnd();
|
||||
byte[] data = this.toByteArray();
|
||||
FileUtils.writeByteArrayToFile(new File(destDir, name + ".class"), data);
|
||||
TestUtils.verify(new ClassReader(data));
|
||||
TestUtils.verify(new ClassReader(data), log);
|
||||
System.out.write('.');
|
||||
} catch (Throwable e) {
|
||||
System.out.write('X');
|
||||
@ -97,15 +100,17 @@ public class V3Test {
|
||||
}
|
||||
};
|
||||
}
|
||||
}), 0);
|
||||
}, V3.REUSE_REGISTER | V3.TOPOLOGICAL_SORT | V3.OPTIMIZE_SYNCHRONIZED), DexFileReader.SKIP_DEBUG);
|
||||
System.out.flush();
|
||||
System.out.println();
|
||||
log.close();
|
||||
if (exes.size() > 0) {
|
||||
StringBuilder sb = new StringBuilder("there are ").append(exes.size())
|
||||
.append(" error(s) while translate\n");
|
||||
for (String ln : exes) {
|
||||
sb.append(ln).append("\n");
|
||||
}
|
||||
sb.append("details: ").append(logFileName).append("\n");
|
||||
throw new RuntimeException(sb.toString());
|
||||
}
|
||||
}
|
||||
|
23
dex-translator/src/test/java/res/OptimizeSynchronized.java
Normal file
23
dex-translator/src/test/java/res/OptimizeSynchronized.java
Normal file
@ -0,0 +1,23 @@
|
||||
package res;
|
||||
|
||||
public class OptimizeSynchronized {
|
||||
public void a() {
|
||||
synchronized (this) {
|
||||
System.out.println(this);
|
||||
}
|
||||
}
|
||||
|
||||
Object b;
|
||||
|
||||
public void b() {
|
||||
synchronized (OptimizeSynchronized.class) {
|
||||
System.out.println(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void c() {
|
||||
synchronized (this.b) {
|
||||
System.out.println(this);
|
||||
}
|
||||
}
|
||||
}
|
8
pom.xml
8
pom.xml
@ -130,10 +130,10 @@ Rev = {node|short}
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<dex2jar.tools.version>0.0.0.4</dex2jar.tools.version>
|
||||
<dex2jar.ir.version>1.6</dex2jar.ir.version>
|
||||
<dex2jar.reader.version>1.9</dex2jar.reader.version>
|
||||
<dex2jar.translator.version>0.0.9.8</dex2jar.translator.version>
|
||||
<dex2jar.tools.version>0.0.0.5</dex2jar.tools.version>
|
||||
<dex2jar.ir.version>1.7</dex2jar.ir.version>
|
||||
<dex2jar.reader.version>1.10</dex2jar.reader.version>
|
||||
<dex2jar.translator.version>0.0.9.9</dex2jar.translator.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</project>
|
||||
|
Loading…
Reference in New Issue
Block a user