From c4e35f2d516ade27e8e1a863b4bc356f182f43c2 Mon Sep 17 00:00:00 2001 From: jeff Date: Tue, 19 Aug 2014 00:25:32 -0400 Subject: started new reference navigation system --- .../enigma/analysis/BehaviorReferenceTreeNode.java | 105 +++++++++++++++ src/cuchaz/enigma/analysis/EntryReference.java | 28 ++++ src/cuchaz/enigma/analysis/FieldCallsTreeNode.java | 82 ------------ .../enigma/analysis/FieldReferenceTreeNode.java | 92 +++++++++++++ src/cuchaz/enigma/analysis/JarIndex.java | 141 +++++++++++++------- .../enigma/analysis/MethodCallsTreeNode.java | 144 --------------------- src/cuchaz/enigma/analysis/ReferenceTreeNode.java | 19 +++ src/cuchaz/enigma/analysis/SourceIndexVisitor.java | 20 ++- src/cuchaz/enigma/analysis/TreeDumpVisitor.java | 11 +- src/cuchaz/enigma/gui/Gui.java | 46 ++++--- src/cuchaz/enigma/gui/GuiController.java | 65 +++++----- src/cuchaz/enigma/mapping/BehaviorEntry.java | 6 + src/cuchaz/enigma/mapping/ConstructorEntry.java | 3 +- src/cuchaz/enigma/mapping/MethodEntry.java | 3 +- src/cuchaz/enigma/mapping/Translator.java | 13 ++ 15 files changed, 441 insertions(+), 337 deletions(-) create mode 100644 src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java create mode 100644 src/cuchaz/enigma/analysis/EntryReference.java delete mode 100644 src/cuchaz/enigma/analysis/FieldCallsTreeNode.java create mode 100644 src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java delete mode 100644 src/cuchaz/enigma/analysis/MethodCallsTreeNode.java create mode 100644 src/cuchaz/enigma/analysis/ReferenceTreeNode.java create mode 100644 src/cuchaz/enigma/mapping/BehaviorEntry.java diff --git a/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java new file mode 100644 index 00000000..158aad71 --- /dev/null +++ b/src/cuchaz/enigma/analysis/BehaviorReferenceTreeNode.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.analysis; + +import java.util.Set; + +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; + +import com.google.common.collect.Sets; + +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.Entry; +import cuchaz.enigma.mapping.Translator; + +public class BehaviorReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode +{ + private static final long serialVersionUID = -3658163700783307520L; + + private Translator m_deobfuscatingTranslator; + private BehaviorEntry m_entry; + private EntryReference m_reference; + + public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, BehaviorEntry entry ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = entry; + m_reference = null; + } + + public BehaviorReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = reference.entry; + m_reference = reference; + } + + @Override + public BehaviorEntry getEntry( ) + { + return m_entry; + } + + @Override + public EntryReference getReference( ) + { + return m_reference; + } + + @Override + public String toString( ) + { + if( m_reference != null ) + { + return m_deobfuscatingTranslator.translateEntry( m_reference.caller ).toString(); + } + return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); + } + + public void load( JarIndex index, boolean recurse ) + { + // get all the child nodes + for( EntryReference reference : index.getBehaviorReferences( m_entry ) ) + { + add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); + } + + if( recurse && children != null ) + { + for( Object child : children ) + { + if( child instanceof BehaviorReferenceTreeNode ) + { + BehaviorReferenceTreeNode node = (BehaviorReferenceTreeNode)child; + + // don't recurse into ancestor + Set ancestors = Sets.newHashSet(); + TreeNode n = (TreeNode)node; + while( n.getParent() != null ) + { + n = n.getParent(); + if( n instanceof BehaviorReferenceTreeNode ) + { + ancestors.add( ((BehaviorReferenceTreeNode)n).getEntry() ); + } + } + if( ancestors.contains( node.getEntry() ) ) + { + continue; + } + + node.load( index, true ); + } + } + } + } +} diff --git a/src/cuchaz/enigma/analysis/EntryReference.java b/src/cuchaz/enigma/analysis/EntryReference.java new file mode 100644 index 00000000..f462210a --- /dev/null +++ b/src/cuchaz/enigma/analysis/EntryReference.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.analysis; + +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.Entry; + +public class EntryReference +{ + public T entry; + public BehaviorEntry caller; + public int pos; + + public EntryReference( T entry, BehaviorEntry caller, int pos ) + { + this.entry = entry; + this.caller = caller; + this.pos = pos; + } +} diff --git a/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java b/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java deleted file mode 100644 index 0427b3be..00000000 --- a/src/cuchaz/enigma/analysis/FieldCallsTreeNode.java +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import javax.swing.tree.DefaultMutableTreeNode; - -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.FieldEntry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Translator; - -public class FieldCallsTreeNode extends DefaultMutableTreeNode -{ - private static final long serialVersionUID = -7934108091928699835L; - - private Translator m_deobfuscatingTranslator; - private FieldEntry m_entry; - - public FieldCallsTreeNode( Translator deobfuscatingTranslator, FieldEntry fieldEntry ) - { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_entry = fieldEntry; - } - - public FieldEntry getFieldEntry( ) - { - return m_entry; - } - - @Override - public String toString( ) - { - String className = m_deobfuscatingTranslator.translateClass( m_entry.getClassName() ); - if( className == null ) - { - className = m_entry.getClassName(); - } - - String targetName = m_deobfuscatingTranslator.translate( m_entry ); - if( targetName == null ) - { - targetName = m_entry.getName(); - } - return className + "." + targetName; - } - - public void load( JarIndex index, boolean recurse ) - { - // get all the child nodes - for( Entry entry : index.getFieldCallers( m_entry ) ) - { - if( entry instanceof MethodEntry ) - { - add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (MethodEntry)entry ) ); - } - else if( entry instanceof ConstructorEntry ) - { - add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (ConstructorEntry)entry ) ); - } - } - - if( recurse && children != null ) - { - for( Object node : children ) - { - if( node instanceof MethodCallsTreeNode ) - { - ((MethodCallsTreeNode)node).load( index, true ); - } - } - } - } -} diff --git a/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java new file mode 100644 index 00000000..dd552d68 --- /dev/null +++ b/src/cuchaz/enigma/analysis/FieldReferenceTreeNode.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.analysis; + +import javax.swing.tree.DefaultMutableTreeNode; + +import cuchaz.enigma.mapping.BehaviorEntry; +import cuchaz.enigma.mapping.FieldEntry; +import cuchaz.enigma.mapping.Translator; + +public class FieldReferenceTreeNode extends DefaultMutableTreeNode implements ReferenceTreeNode +{ + private static final long serialVersionUID = -7934108091928699835L; + + private Translator m_deobfuscatingTranslator; + private FieldEntry m_entry; + private EntryReference m_reference; + + public FieldReferenceTreeNode( Translator deobfuscatingTranslator, FieldEntry entry ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = entry; + m_reference = null; + } + + private FieldReferenceTreeNode( Translator deobfuscatingTranslator, EntryReference reference ) + { + m_deobfuscatingTranslator = deobfuscatingTranslator; + m_entry = reference.entry; + m_reference = reference; + } + + @Override + public FieldEntry getEntry( ) + { + return m_entry; + } + + @Override + public EntryReference getReference( ) + { + return m_reference; + } + + @Override + public String toString( ) + { + if( m_reference != null ) + { + return m_deobfuscatingTranslator.translateEntry( m_reference.caller ).toString(); + } + return m_deobfuscatingTranslator.translateEntry( m_entry ).toString(); + } + + public void load( JarIndex index, boolean recurse ) + { + // get all the child nodes + if( m_reference == null ) + { + for( EntryReference reference : index.getFieldReferences( m_entry ) ) + { + add( new FieldReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); + } + } + else + { + for( EntryReference reference : index.getBehaviorReferences( m_reference.caller ) ) + { + add( new BehaviorReferenceTreeNode( m_deobfuscatingTranslator, reference ) ); + } + } + + if( recurse && children != null ) + { + for( Object node : children ) + { + if( node instanceof BehaviorReferenceTreeNode ) + { + ((BehaviorReferenceTreeNode)node).load( index, true ); + } + } + } + } +} diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 7d68c357..f1c29c5b 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java @@ -35,12 +35,15 @@ import javassist.expr.MethodCall; import javassist.expr.NewExpr; import com.google.common.collect.HashMultimap; +import com.google.common.collect.HashMultiset; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import com.google.common.collect.Multiset; import com.google.common.collect.Sets; import cuchaz.enigma.mapping.ArgumentEntry; +import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; @@ -53,8 +56,8 @@ public class JarIndex private Set m_obfClassNames; private Ancestries m_ancestries; private Multimap m_methodImplementations; - private Multimap m_methodCalls; - private Multimap m_fieldCalls; + private Multimap> m_behaviorReferences; + private Multimap> m_fieldReferences; private Multimap m_innerClasses; private Map m_outerClasses; private Set m_anonymousClasses; @@ -64,8 +67,8 @@ public class JarIndex m_obfClassNames = Sets.newHashSet(); m_ancestries = new Ancestries(); m_methodImplementations = HashMultimap.create(); - m_methodCalls = HashMultimap.create(); - m_fieldCalls = HashMultimap.create(); + m_behaviorReferences = HashMultimap.create(); + m_fieldReferences = HashMultimap.create(); m_innerClasses = HashMultimap.create(); m_outerClasses = Maps.newHashMap(); m_anonymousClasses = Sets.newHashSet(); @@ -128,7 +131,7 @@ public class JarIndex { // get the method entry String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); - final Entry thisEntry; + final BehaviorEntry thisEntry; if( behavior instanceof CtMethod ) { MethodEntry methodEntry = new MethodEntry( @@ -156,6 +159,7 @@ public class JarIndex // index method calls try { + final Multiset callNumbers = HashMultiset.create(); behavior.instrument( new ExprEditor( ) { @Override @@ -167,7 +171,13 @@ public class JarIndex call.getMethodName(), call.getSignature() ); - m_methodCalls.put( calledMethodEntry, thisEntry ); + callNumbers.add( calledMethodEntry ); + EntryReference reference = new EntryReference( + calledMethodEntry, + thisEntry, + callNumbers.count( calledMethodEntry ) - 1 + ); + m_behaviorReferences.put( calledMethodEntry, reference ); } @Override @@ -178,22 +188,33 @@ public class JarIndex new ClassEntry( className ), call.getFieldName() ); - m_fieldCalls.put( calledFieldEntry, thisEntry ); + callNumbers.add( calledFieldEntry ); + EntryReference reference = new EntryReference( + calledFieldEntry, + thisEntry, + callNumbers.count( calledFieldEntry ) - 1 + ); + m_fieldReferences.put( calledFieldEntry, reference ); } @Override public void edit( ConstructorCall call ) { + // TODO: save isSuper in the reference somehow boolean isSuper = call.getMethodName().equals( "super" ); - // TODO: make method reference class, update method calls tree to use Invocation instances - // this might end up being a big refactor... =( String className = Descriptor.toJvmName( call.getClassName() ); ConstructorEntry calledConstructorEntry = new ConstructorEntry( new ClassEntry( className ), call.getSignature() ); - m_methodCalls.put( calledConstructorEntry, thisEntry ); + callNumbers.add( calledConstructorEntry ); + EntryReference reference = new EntryReference( + calledConstructorEntry, + thisEntry, + callNumbers.count( calledConstructorEntry ) - 1 + ); + m_behaviorReferences.put( calledConstructorEntry, reference ); } @Override @@ -204,7 +225,13 @@ public class JarIndex new ClassEntry( className ), call.getSignature() ); - m_methodCalls.put( calledConstructorEntry, thisEntry ); + callNumbers.add( calledConstructorEntry ); + EntryReference reference = new EntryReference( + calledConstructorEntry, + thisEntry, + callNumbers.count( calledConstructorEntry ) - 1 + ); + m_behaviorReferences.put( calledConstructorEntry, reference ); } } ); } @@ -234,9 +261,9 @@ public class JarIndex new ClassEntry( Descriptor.toJvmName( c.getName() ) ), constructor.getMethodInfo().getDescriptor() ); - for( Entry callerEntry : getMethodCallers( constructorEntry ) ) + for( EntryReference reference : getBehaviorReferences( constructorEntry ) ) { - callerClasses.add( callerEntry.getClassEntry() ); + callerClasses.add( reference.caller.getClassEntry() ); } // is this called by exactly one class? @@ -388,7 +415,7 @@ public class JarIndex new ClassEntry( innerClassName ), constructor.getMethodInfo().getDescriptor() ); - if( getMethodCallers( constructorEntry ).size() != 1 ) + if( getBehaviorReferences( constructorEntry ).size() != 1 ) { return false; } @@ -469,14 +496,26 @@ public class JarIndex return rootNode; } - public Collection getFieldCallers( FieldEntry fieldEntry ) + @SuppressWarnings( "unchecked" ) + public Collection> getFieldReferences( FieldEntry fieldEntry ) { - return m_fieldCalls.get( fieldEntry ); + List> references = Lists.newArrayList(); + for( EntryReference reference : m_fieldReferences.get( fieldEntry ) ) + { + references.add( (EntryReference)reference ); + } + return references; } - public Collection getMethodCallers( Entry entry ) + @SuppressWarnings( "unchecked" ) + public Collection> getBehaviorReferences( BehaviorEntry behaviorEntry ) { - return m_methodCalls.get( entry ); + List> references = Lists.newArrayList(); + for( EntryReference reference : m_behaviorReferences.get( behaviorEntry ) ) + { + references.add( (EntryReference)reference ); + } + return references; } public Collection getInnerClasses( String obfOuterClassName ) @@ -498,85 +537,91 @@ public class JarIndex { m_ancestries.renameClasses( renames ); renameMultimap( renames, m_methodImplementations ); - renameMultimap( renames, m_methodCalls ); - renameMultimap( renames, m_fieldCalls ); + renameMultimap( renames, m_behaviorReferences ); + renameMultimap( renames, m_fieldReferences ); } - private void renameMultimap( Map renames, Multimap map ) + private void renameMultimap( Map renames, Multimap map ) { // for each key/value pair... - Set> entriesToAdd = Sets.newHashSet(); - Iterator> iter = map.entries().iterator(); + Set> entriesToAdd = Sets.newHashSet(); + Iterator> iter = map.entries().iterator(); while( iter.hasNext() ) { - Map.Entry entry = iter.next(); + Map.Entry entry = iter.next(); iter.remove(); - entriesToAdd.add( new AbstractMap.SimpleEntry( - renameEntry( renames, entry.getKey() ), - renameEntry( renames, entry.getValue() ) + entriesToAdd.add( new AbstractMap.SimpleEntry( + renameThing( renames, entry.getKey() ), + renameThing( renames, entry.getValue() ) ) ); } - for( Map.Entry entry : entriesToAdd ) + for( Map.Entry entry : entriesToAdd ) { map.put( entry.getKey(), entry.getValue() ); } } @SuppressWarnings( "unchecked" ) - private T renameEntry( Map renames, T entry ) + private T renameThing( Map renames, T thing ) { - if( entry instanceof String ) + if( thing instanceof String ) { - String stringEntry = (String)entry; + String stringEntry = (String)thing; if( renames.containsKey( stringEntry ) ) { return (T)renames.get( stringEntry ); } } - else if( entry instanceof ClassEntry ) + else if( thing instanceof ClassEntry ) { - ClassEntry classEntry = (ClassEntry)entry; - return (T)new ClassEntry( renameEntry( renames, classEntry.getClassName() ) ); + ClassEntry classEntry = (ClassEntry)thing; + return (T)new ClassEntry( renameThing( renames, classEntry.getClassName() ) ); } - else if( entry instanceof FieldEntry ) + else if( thing instanceof FieldEntry ) { - FieldEntry fieldEntry = (FieldEntry)entry; + FieldEntry fieldEntry = (FieldEntry)thing; return (T)new FieldEntry( - renameEntry( renames, fieldEntry.getClassEntry() ), + renameThing( renames, fieldEntry.getClassEntry() ), fieldEntry.getName() ); } - else if( entry instanceof ConstructorEntry ) + else if( thing instanceof ConstructorEntry ) { - ConstructorEntry constructorEntry = (ConstructorEntry)entry; + ConstructorEntry constructorEntry = (ConstructorEntry)thing; return (T)new ConstructorEntry( - renameEntry( renames, constructorEntry.getClassEntry() ), + renameThing( renames, constructorEntry.getClassEntry() ), constructorEntry.getSignature() ); } - else if( entry instanceof MethodEntry ) + else if( thing instanceof MethodEntry ) { - MethodEntry methodEntry = (MethodEntry)entry; + MethodEntry methodEntry = (MethodEntry)thing; return (T)new MethodEntry( - renameEntry( renames, methodEntry.getClassEntry() ), + renameThing( renames, methodEntry.getClassEntry() ), methodEntry.getName(), methodEntry.getSignature() ); } - else if( entry instanceof ArgumentEntry ) + else if( thing instanceof ArgumentEntry ) { - ArgumentEntry argumentEntry = (ArgumentEntry)entry; + ArgumentEntry argumentEntry = (ArgumentEntry)thing; return (T)new ArgumentEntry( - renameEntry( renames, argumentEntry.getMethodEntry() ), + renameThing( renames, argumentEntry.getMethodEntry() ), argumentEntry.getIndex(), argumentEntry.getName() ); } + else if( thing instanceof EntryReference ) + { + EntryReference reference = (EntryReference)thing; + reference.entry = renameThing( renames, reference.entry ); + return thing; + } else { - throw new Error( "Not an entry: " + entry ); + throw new Error( "Not an entry: " + thing ); } - return entry; + return thing; } } diff --git a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java b/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java deleted file mode 100644 index b5cf4c33..00000000 --- a/src/cuchaz/enigma/analysis/MethodCallsTreeNode.java +++ /dev/null @@ -1,144 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2014 Jeff Martin. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v3.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/gpl.html - * - * Contributors: - * Jeff Martin - initial API and implementation - ******************************************************************************/ -package cuchaz.enigma.analysis; - -import java.util.Set; - -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.TreeNode; - -import com.google.common.collect.Sets; - -import cuchaz.enigma.mapping.ConstructorEntry; -import cuchaz.enigma.mapping.Entry; -import cuchaz.enigma.mapping.MethodEntry; -import cuchaz.enigma.mapping.Translator; - -public class MethodCallsTreeNode extends DefaultMutableTreeNode -{ - private static final long serialVersionUID = -3658163700783307520L; - - private Translator m_deobfuscatingTranslator; - private MethodEntry m_methodEntry; - private ConstructorEntry m_constructorEntry; - - public MethodCallsTreeNode( Translator deobfuscatingTranslator, MethodEntry entry ) - { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_methodEntry = entry; - m_constructorEntry = null; - } - - public MethodCallsTreeNode( Translator deobfuscatingTranslator, ConstructorEntry entry ) - { - m_deobfuscatingTranslator = deobfuscatingTranslator; - m_methodEntry = null; - m_constructorEntry = entry; - } - - public MethodEntry getMethodEntry( ) - { - return m_methodEntry; - } - - public ConstructorEntry getConstructorEntry( ) - { - return m_constructorEntry; - } - - public Entry getEntry( ) - { - if( m_methodEntry != null ) - { - return m_methodEntry; - } - else if( m_constructorEntry != null ) - { - return m_constructorEntry; - } - throw new Error( "Illegal state!" ); - } - - @Override - public String toString( ) - { - if( m_methodEntry != null ) - { - String className = m_deobfuscatingTranslator.translateClass( m_methodEntry.getClassName() ); - if( className == null ) - { - className = m_methodEntry.getClassName(); - } - - String methodName = m_deobfuscatingTranslator.translate( m_methodEntry ); - if( methodName == null ) - { - methodName = m_methodEntry.getName(); - } - return className + "." + methodName + "()"; - } - else if( m_constructorEntry != null ) - { - String className = m_deobfuscatingTranslator.translateClass( m_constructorEntry.getClassName() ); - if( className == null ) - { - className = m_constructorEntry.getClassName(); - } - return className + "()"; - } - throw new Error( "Illegal state!" ); - } - - public void load( JarIndex index, boolean recurse ) - { - // get all the child nodes - for( Entry entry : index.getMethodCallers( getEntry() ) ) - { - if( entry instanceof MethodEntry ) - { - add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (MethodEntry)entry ) ); - } - else if( entry instanceof ConstructorEntry ) - { - add( new MethodCallsTreeNode( m_deobfuscatingTranslator, (ConstructorEntry)entry ) ); - } - } - - if( recurse && children != null ) - { - for( Object child : children ) - { - if( child instanceof MethodCallsTreeNode ) - { - MethodCallsTreeNode node = (MethodCallsTreeNode)child; - - // don't recurse into ancestor - Set ancestors = Sets.newHashSet(); - TreeNode n = (TreeNode)node; - while( n.getParent() != null ) - { - n = n.getParent(); - if( n instanceof MethodCallsTreeNode ) - { - ancestors.add( ((MethodCallsTreeNode)n).getEntry() ); - } - } - if( ancestors.contains( node.getEntry() ) ) - { - continue; - } - - node.load( index, true ); - } - } - } - } -} diff --git a/src/cuchaz/enigma/analysis/ReferenceTreeNode.java b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java new file mode 100644 index 00000000..08ae39d9 --- /dev/null +++ b/src/cuchaz/enigma/analysis/ReferenceTreeNode.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2014 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v3.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/gpl.html + * + * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ +package cuchaz.enigma.analysis; + +import cuchaz.enigma.mapping.Entry; + +public interface ReferenceTreeNode +{ + T getEntry(); + EntryReference getReference(); +} diff --git a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java index f31eb1a8..841d1767 100644 --- a/src/cuchaz/enigma/analysis/SourceIndexVisitor.java +++ b/src/cuchaz/enigma/analysis/SourceIndexVisitor.java @@ -213,6 +213,20 @@ public class SourceIndexVisitor implements IAstVisitor return recurse( node, index ); } + @Override + public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) + { + MemberReference ref = node.getUserData( Keys.MEMBER_REFERENCE ); + if( ref != null ) + { + ClassEntry classEntry = new ClassEntry( ref.getDeclaringType().getInternalName() ); + FieldEntry fieldEntry = new FieldEntry( classEntry, ref.getName() ); + index.add( node.getIdentifierToken(), fieldEntry ); + } + + return recurse( node, index ); + } + private Void recurse( AstNode node, SourceIndex index ) { for( final AstNode child : node.getChildren() ) @@ -476,12 +490,6 @@ public class SourceIndexVisitor implements IAstVisitor return recurse( node, index ); } - @Override - public Void visitIdentifierExpression( IdentifierExpression node, SourceIndex index ) - { - return recurse( node, index ); - } - @Override public Void visitUnaryOperatorExpression( UnaryOperatorExpression node, SourceIndex index ) { diff --git a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java index ac3e92db..12febefd 100644 --- a/src/cuchaz/enigma/analysis/TreeDumpVisitor.java +++ b/src/cuchaz/enigma/analysis/TreeDumpVisitor.java @@ -122,7 +122,7 @@ public class TreeDumpVisitor implements IAstVisitor // show the tree try { - m_out.write( getIndent( node ) + node.getClass().getSimpleName() + dumpUserData( node ) + " " + node.getRegion() + "\n" ); + m_out.write( getIndent( node ) + node.getClass().getSimpleName() + " " + getText( node ) + " " + dumpUserData( node ) + " " + node.getRegion() + "\n" ); } catch( IOException ex ) { @@ -137,6 +137,15 @@ public class TreeDumpVisitor implements IAstVisitor return null; } + private String getText( AstNode node ) + { + if( node instanceof Identifier ) + { + return "\"" + node.getText() + "\""; + } + return ""; + } + private String dumpUserData( AstNode node ) { StringBuilder buf = new StringBuilder(); diff --git a/src/cuchaz/enigma/gui/Gui.java b/src/cuchaz/enigma/gui/Gui.java index 9ed6dd86..43a0cdad 100644 --- a/src/cuchaz/enigma/gui/Gui.java +++ b/src/cuchaz/enigma/gui/Gui.java @@ -66,10 +66,11 @@ import jsyntaxpane.DefaultSyntaxKit; import com.google.common.collect.Lists; import cuchaz.enigma.Constants; +import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; -import cuchaz.enigma.analysis.FieldCallsTreeNode; -import cuchaz.enigma.analysis.MethodCallsTreeNode; +import cuchaz.enigma.analysis.FieldReferenceTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; +import cuchaz.enigma.analysis.ReferenceTreeNode; import cuchaz.enigma.analysis.Token; import cuchaz.enigma.mapping.ArgumentEntry; import cuchaz.enigma.mapping.ClassEntry; @@ -191,7 +192,7 @@ public class Gui String selected = m_obfClasses.getSelectedValue(); if( selected != null ) { - m_controller.openEntry( new ClassEntry( selected ) ); + m_controller.openDeclaration( new ClassEntry( selected ) ); } } } @@ -217,7 +218,7 @@ public class Gui String selected = m_deobfClasses.getSelectedValue(); if( selected != null ) { - m_controller.openEntry( new ClassEntry( selected ) ); + m_controller.openDeclaration( new ClassEntry( selected ) ); } } } @@ -268,11 +269,11 @@ public class Gui break; case KeyEvent.VK_N: - openEntry(); + openDeclaration(); break; case KeyEvent.VK_P: - m_controller.openPreviousEntry(); + m_controller.openPreviousLocation(); break; case KeyEvent.VK_C: @@ -341,7 +342,7 @@ public class Gui @Override public void actionPerformed( ActionEvent event ) { - openEntry(); + openDeclaration(); } } ); menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_N, 0 ) ); @@ -356,7 +357,7 @@ public class Gui @Override public void actionPerformed( ActionEvent event ) { - m_controller.openPreviousEntry(); + m_controller.openPreviousLocation(); } } ); menu.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_P, 0 ) ); @@ -385,14 +386,14 @@ public class Gui Object node = path.getLastPathComponent(); if( node instanceof ClassInheritanceTreeNode ) { - m_controller.openEntry( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); + m_controller.openDeclaration( new ClassEntry( ((ClassInheritanceTreeNode)node).getObfClassName() ) ); } else if( node instanceof MethodInheritanceTreeNode ) { MethodInheritanceTreeNode methodNode = (MethodInheritanceTreeNode)node; if( methodNode.isImplemented() ) { - m_controller.openEntry( methodNode.getMethodEntry() ); + m_controller.openDeclaration( methodNode.getMethodEntry() ); } } } @@ -407,6 +408,7 @@ public class Gui m_callsTree.setModel( null ); m_callsTree.addMouseListener( new MouseAdapter( ) { + @SuppressWarnings( "unchecked" ) @Override public void mouseClicked( MouseEvent event ) { @@ -420,9 +422,17 @@ public class Gui } Object node = path.getLastPathComponent(); - if( node instanceof MethodCallsTreeNode ) + if( node instanceof ReferenceTreeNode ) { - m_controller.openEntry( ((MethodCallsTreeNode)node).getEntry() ); + ReferenceTreeNode referenceNode = ((ReferenceTreeNode)node); + if( referenceNode.getReference() != null ) + { + m_controller.openReference( referenceNode.getReference() ); + } + else + { + m_controller.openDeclaration( referenceNode.getEntry() ); + } } } } @@ -862,7 +872,7 @@ public class Gui m_showInheritanceMenu.setEnabled( isClassEntry || isMethodEntry || isConstructorEntry ); m_showCallsMenu.setEnabled( isFieldEntry || isMethodEntry || isConstructorEntry ); m_openEntryMenu.setEnabled( isClassEntry || isFieldEntry || isMethodEntry || isConstructorEntry ); - m_openPreviousMenu.setEnabled( m_controller.hasPreviousEntry() ); + m_openPreviousMenu.setEnabled( m_controller.hasPreviousLocation() ); } private void startRename( ) @@ -977,17 +987,17 @@ public class Gui if( m_selectedEntryPair.obf instanceof FieldEntry ) { - FieldCallsTreeNode node = m_controller.getFieldCalls( (FieldEntry)m_selectedEntryPair.obf ); + FieldReferenceTreeNode node = m_controller.getFieldReferences( (FieldEntry)m_selectedEntryPair.obf ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } else if( m_selectedEntryPair.obf instanceof MethodEntry ) { - MethodCallsTreeNode node = m_controller.getMethodCalls( (MethodEntry)m_selectedEntryPair.obf ); + BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (MethodEntry)m_selectedEntryPair.obf ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } else if( m_selectedEntryPair.obf instanceof ConstructorEntry ) { - MethodCallsTreeNode node = m_controller.getMethodCalls( (ConstructorEntry)m_selectedEntryPair.obf ); + BehaviorReferenceTreeNode node = m_controller.getMethodReferences( (ConstructorEntry)m_selectedEntryPair.obf ); m_callsTree.setModel( new DefaultTreeModel( node ) ); } @@ -1009,13 +1019,13 @@ public class Gui return new TreePath( nodes.toArray() ); } - private void openEntry( ) + private void openDeclaration( ) { if( m_selectedEntryPair == null ) { return; } - m_controller.openEntry( m_selectedEntryPair.obf ); + m_controller.openDeclaration( m_selectedEntryPair.obf ); } private void close( ) diff --git a/src/cuchaz/enigma/gui/GuiController.java b/src/cuchaz/enigma/gui/GuiController.java index f305e341..f80bec7e 100644 --- a/src/cuchaz/enigma/gui/GuiController.java +++ b/src/cuchaz/enigma/gui/GuiController.java @@ -20,14 +20,15 @@ import java.util.Stack; import com.google.common.collect.Lists; import cuchaz.enigma.Deobfuscator; +import cuchaz.enigma.analysis.BehaviorReferenceTreeNode; import cuchaz.enigma.analysis.ClassInheritanceTreeNode; -import cuchaz.enigma.analysis.FieldCallsTreeNode; -import cuchaz.enigma.analysis.MethodCallsTreeNode; +import cuchaz.enigma.analysis.EntryReference; +import cuchaz.enigma.analysis.FieldReferenceTreeNode; import cuchaz.enigma.analysis.MethodInheritanceTreeNode; import cuchaz.enigma.analysis.SourceIndex; import cuchaz.enigma.analysis.Token; +import cuchaz.enigma.mapping.BehaviorEntry; import cuchaz.enigma.mapping.ClassEntry; -import cuchaz.enigma.mapping.ConstructorEntry; import cuchaz.enigma.mapping.Entry; import cuchaz.enigma.mapping.EntryPair; import cuchaz.enigma.mapping.FieldEntry; @@ -44,7 +45,7 @@ public class GuiController private SourceIndex m_index; private ClassEntry m_currentClass; private boolean m_isDirty; - private Stack m_entryStack; + private Stack m_locationStack; // TODO: make a location class, can be either Entry or EntryReference public GuiController( Gui gui ) { @@ -53,7 +54,7 @@ public class GuiController m_index = null; m_currentClass = null; m_isDirty = false; - m_entryStack = new Stack(); + m_locationStack = new Stack(); } public boolean isDirty( ) @@ -157,9 +158,9 @@ public class GuiController return MethodInheritanceTreeNode.findNode( rootNode, obfMethodEntry ); } - public FieldCallsTreeNode getFieldCalls( FieldEntry obfFieldEntry ) + public FieldReferenceTreeNode getFieldReferences( FieldEntry obfFieldEntry ) { - FieldCallsTreeNode rootNode = new FieldCallsTreeNode( + FieldReferenceTreeNode rootNode = new FieldReferenceTreeNode( m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), obfFieldEntry ); @@ -167,27 +168,12 @@ public class GuiController return rootNode; } - public MethodCallsTreeNode getMethodCalls( Entry obfEntry ) + public BehaviorReferenceTreeNode getMethodReferences( BehaviorEntry obfEntry ) { - MethodCallsTreeNode rootNode; - if( obfEntry instanceof MethodEntry ) - { - rootNode = new MethodCallsTreeNode( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), - (MethodEntry)obfEntry - ); - } - else if( obfEntry instanceof ConstructorEntry ) - { - rootNode = new MethodCallsTreeNode( - m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), - (ConstructorEntry)obfEntry - ); - } - else - { - throw new IllegalArgumentException( "entry must be a MethodEntry or a ConstructorEntry!" ); - } + BehaviorReferenceTreeNode rootNode = new BehaviorReferenceTreeNode( + m_deobfuscator.getTranslator( TranslationDirection.Deobfuscating ), + obfEntry + ); rootNode.load( m_deobfuscator.getJarIndex(), true ); return rootNode; } @@ -200,7 +186,7 @@ public class GuiController refreshCurrentClass( obfEntry ); } - public void openEntry( Entry entry ) + public void openDeclaration( Entry entry ) { // go to the entry Entry obfEntry = m_deobfuscator.obfuscateEntry( entry ); @@ -214,25 +200,32 @@ public class GuiController m_gui.showToken( m_index.getDeclarationToken( m_deobfuscator.deobfuscateEntry( obfEntry ) ) ); } - if( m_entryStack.isEmpty() || !m_entryStack.peek().equals( obfEntry ) ) + if( m_locationStack.isEmpty() || !m_locationStack.peek().equals( obfEntry ) ) { // update the stack - m_entryStack.push( obfEntry ); + m_locationStack.push( obfEntry ); } } - public void openPreviousEntry( ) + public void openReference( EntryReference reference ) + { + // TODO: find out how to load the n-th reference in a caller + // TEMP: just go to the caller for now + openDeclaration( reference.caller ); + } + + public void openPreviousLocation( ) { - if( hasPreviousEntry() ) + if( hasPreviousLocation() ) { - m_entryStack.pop(); - openEntry( m_entryStack.peek() ); + m_locationStack.pop(); + openDeclaration( m_locationStack.peek() ); } } - public boolean hasPreviousEntry( ) + public boolean hasPreviousLocation( ) { - return m_entryStack.size() > 1; + return m_locationStack.size() > 1; } private void refreshClasses( ) diff --git a/src/cuchaz/enigma/mapping/BehaviorEntry.java b/src/cuchaz/enigma/mapping/BehaviorEntry.java new file mode 100644 index 00000000..99fdd28d --- /dev/null +++ b/src/cuchaz/enigma/mapping/BehaviorEntry.java @@ -0,0 +1,6 @@ +package cuchaz.enigma.mapping; + +public interface BehaviorEntry extends Entry +{ + public String getSignature(); +} diff --git a/src/cuchaz/enigma/mapping/ConstructorEntry.java b/src/cuchaz/enigma/mapping/ConstructorEntry.java index e0fa7cf6..0f7dab68 100644 --- a/src/cuchaz/enigma/mapping/ConstructorEntry.java +++ b/src/cuchaz/enigma/mapping/ConstructorEntry.java @@ -14,7 +14,7 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class ConstructorEntry implements Entry, Serializable +public class ConstructorEntry implements BehaviorEntry, Serializable { private static final long serialVersionUID = -868346075317366758L; @@ -54,6 +54,7 @@ public class ConstructorEntry implements Entry, Serializable return m_classEntry.getName(); } + @Override public String getSignature( ) { return m_signature; diff --git a/src/cuchaz/enigma/mapping/MethodEntry.java b/src/cuchaz/enigma/mapping/MethodEntry.java index b4b9c9bf..a311e636 100644 --- a/src/cuchaz/enigma/mapping/MethodEntry.java +++ b/src/cuchaz/enigma/mapping/MethodEntry.java @@ -14,7 +14,7 @@ import java.io.Serializable; import cuchaz.enigma.Util; -public class MethodEntry implements Entry, Serializable +public class MethodEntry implements BehaviorEntry, Serializable { private static final long serialVersionUID = 4770915224467247458L; @@ -68,6 +68,7 @@ public class MethodEntry implements Entry, Serializable return m_name; } + @Override public String getSignature( ) { return m_signature; diff --git a/src/cuchaz/enigma/mapping/Translator.java b/src/cuchaz/enigma/mapping/Translator.java index fc41f945..a1230db3 100644 --- a/src/cuchaz/enigma/mapping/Translator.java +++ b/src/cuchaz/enigma/mapping/Translator.java @@ -172,6 +172,19 @@ public class Translator ); } + public BehaviorEntry translateEntry( BehaviorEntry in ) + { + if( in instanceof MethodEntry ) + { + return translateEntry( (MethodEntry)in ); + } + else if( in instanceof ConstructorEntry ) + { + return translateEntry( (ConstructorEntry)in ); + } + throw new Error( "Wrong entry type!" ); + } + public String translate( ArgumentEntry in ) { for( String className : getSelfAndAncestors( in.getClassName() ) ) -- cgit v1.2.3