merge 0.0.9.9 to default

This commit is contained in:
Panxiaobo 2012-07-18 21:55:23 +08:00
commit ba5fbc23bb
27 changed files with 812 additions and 71 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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;

View File

@ -34,7 +34,7 @@
<dependency>
<groupId>pxb.bc</groupId>
<artifactId>p-rename</artifactId>
<version>1.0</version>
<version>1.1</version>
</dependency>
</dependencies>
<build>

View 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" %*

View 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" $@

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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 ");

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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 ...");

View File

@ -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;

View File

@ -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);
}
}
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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");
}
}

View File

@ -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);
}
};
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View 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);
}
}
}

View File

@ -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>