diff options
Diffstat (limited to 'src/cuchaz/enigma/analysis/JarIndex.java')
| -rw-r--r-- | src/cuchaz/enigma/analysis/JarIndex.java | 141 |
1 files changed, 93 insertions, 48 deletions
diff --git a/src/cuchaz/enigma/analysis/JarIndex.java b/src/cuchaz/enigma/analysis/JarIndex.java index 7d68c35..f1c29c5 100644 --- a/src/cuchaz/enigma/analysis/JarIndex.java +++ b/src/cuchaz/enigma/analysis/JarIndex.java | |||
| @@ -35,12 +35,15 @@ import javassist.expr.MethodCall; | |||
| 35 | import javassist.expr.NewExpr; | 35 | import javassist.expr.NewExpr; |
| 36 | 36 | ||
| 37 | import com.google.common.collect.HashMultimap; | 37 | import com.google.common.collect.HashMultimap; |
| 38 | import com.google.common.collect.HashMultiset; | ||
| 38 | import com.google.common.collect.Lists; | 39 | import com.google.common.collect.Lists; |
| 39 | import com.google.common.collect.Maps; | 40 | import com.google.common.collect.Maps; |
| 40 | import com.google.common.collect.Multimap; | 41 | import com.google.common.collect.Multimap; |
| 42 | import com.google.common.collect.Multiset; | ||
| 41 | import com.google.common.collect.Sets; | 43 | import com.google.common.collect.Sets; |
| 42 | 44 | ||
| 43 | import cuchaz.enigma.mapping.ArgumentEntry; | 45 | import cuchaz.enigma.mapping.ArgumentEntry; |
| 46 | import cuchaz.enigma.mapping.BehaviorEntry; | ||
| 44 | import cuchaz.enigma.mapping.ClassEntry; | 47 | import cuchaz.enigma.mapping.ClassEntry; |
| 45 | import cuchaz.enigma.mapping.ConstructorEntry; | 48 | import cuchaz.enigma.mapping.ConstructorEntry; |
| 46 | import cuchaz.enigma.mapping.Entry; | 49 | import cuchaz.enigma.mapping.Entry; |
| @@ -53,8 +56,8 @@ public class JarIndex | |||
| 53 | private Set<String> m_obfClassNames; | 56 | private Set<String> m_obfClassNames; |
| 54 | private Ancestries m_ancestries; | 57 | private Ancestries m_ancestries; |
| 55 | private Multimap<String,MethodEntry> m_methodImplementations; | 58 | private Multimap<String,MethodEntry> m_methodImplementations; |
| 56 | private Multimap<Entry,Entry> m_methodCalls; | 59 | private Multimap<BehaviorEntry,EntryReference<? extends Entry>> m_behaviorReferences; |
| 57 | private Multimap<FieldEntry,Entry> m_fieldCalls; | 60 | private Multimap<FieldEntry,EntryReference<? extends Entry>> m_fieldReferences; |
| 58 | private Multimap<String,String> m_innerClasses; | 61 | private Multimap<String,String> m_innerClasses; |
| 59 | private Map<String,String> m_outerClasses; | 62 | private Map<String,String> m_outerClasses; |
| 60 | private Set<String> m_anonymousClasses; | 63 | private Set<String> m_anonymousClasses; |
| @@ -64,8 +67,8 @@ public class JarIndex | |||
| 64 | m_obfClassNames = Sets.newHashSet(); | 67 | m_obfClassNames = Sets.newHashSet(); |
| 65 | m_ancestries = new Ancestries(); | 68 | m_ancestries = new Ancestries(); |
| 66 | m_methodImplementations = HashMultimap.create(); | 69 | m_methodImplementations = HashMultimap.create(); |
| 67 | m_methodCalls = HashMultimap.create(); | 70 | m_behaviorReferences = HashMultimap.create(); |
| 68 | m_fieldCalls = HashMultimap.create(); | 71 | m_fieldReferences = HashMultimap.create(); |
| 69 | m_innerClasses = HashMultimap.create(); | 72 | m_innerClasses = HashMultimap.create(); |
| 70 | m_outerClasses = Maps.newHashMap(); | 73 | m_outerClasses = Maps.newHashMap(); |
| 71 | m_anonymousClasses = Sets.newHashSet(); | 74 | m_anonymousClasses = Sets.newHashSet(); |
| @@ -128,7 +131,7 @@ public class JarIndex | |||
| 128 | { | 131 | { |
| 129 | // get the method entry | 132 | // get the method entry |
| 130 | String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); | 133 | String className = Descriptor.toJvmName( behavior.getDeclaringClass().getName() ); |
| 131 | final Entry thisEntry; | 134 | final BehaviorEntry thisEntry; |
| 132 | if( behavior instanceof CtMethod ) | 135 | if( behavior instanceof CtMethod ) |
| 133 | { | 136 | { |
| 134 | MethodEntry methodEntry = new MethodEntry( | 137 | MethodEntry methodEntry = new MethodEntry( |
| @@ -156,6 +159,7 @@ public class JarIndex | |||
| 156 | // index method calls | 159 | // index method calls |
| 157 | try | 160 | try |
| 158 | { | 161 | { |
| 162 | final Multiset<Entry> callNumbers = HashMultiset.create(); | ||
| 159 | behavior.instrument( new ExprEditor( ) | 163 | behavior.instrument( new ExprEditor( ) |
| 160 | { | 164 | { |
| 161 | @Override | 165 | @Override |
| @@ -167,7 +171,13 @@ public class JarIndex | |||
| 167 | call.getMethodName(), | 171 | call.getMethodName(), |
| 168 | call.getSignature() | 172 | call.getSignature() |
| 169 | ); | 173 | ); |
| 170 | m_methodCalls.put( calledMethodEntry, thisEntry ); | 174 | callNumbers.add( calledMethodEntry ); |
| 175 | EntryReference<MethodEntry> reference = new EntryReference<MethodEntry>( | ||
| 176 | calledMethodEntry, | ||
| 177 | thisEntry, | ||
| 178 | callNumbers.count( calledMethodEntry ) - 1 | ||
| 179 | ); | ||
| 180 | m_behaviorReferences.put( calledMethodEntry, reference ); | ||
| 171 | } | 181 | } |
| 172 | 182 | ||
| 173 | @Override | 183 | @Override |
| @@ -178,22 +188,33 @@ public class JarIndex | |||
| 178 | new ClassEntry( className ), | 188 | new ClassEntry( className ), |
| 179 | call.getFieldName() | 189 | call.getFieldName() |
| 180 | ); | 190 | ); |
| 181 | m_fieldCalls.put( calledFieldEntry, thisEntry ); | 191 | callNumbers.add( calledFieldEntry ); |
| 192 | EntryReference<FieldEntry> reference = new EntryReference<FieldEntry>( | ||
| 193 | calledFieldEntry, | ||
| 194 | thisEntry, | ||
| 195 | callNumbers.count( calledFieldEntry ) - 1 | ||
| 196 | ); | ||
| 197 | m_fieldReferences.put( calledFieldEntry, reference ); | ||
| 182 | } | 198 | } |
| 183 | 199 | ||
| 184 | @Override | 200 | @Override |
| 185 | public void edit( ConstructorCall call ) | 201 | public void edit( ConstructorCall call ) |
| 186 | { | 202 | { |
| 203 | // TODO: save isSuper in the reference somehow | ||
| 187 | boolean isSuper = call.getMethodName().equals( "super" ); | 204 | boolean isSuper = call.getMethodName().equals( "super" ); |
| 188 | // TODO: make method reference class, update method calls tree to use Invocation instances | ||
| 189 | // this might end up being a big refactor... =( | ||
| 190 | 205 | ||
| 191 | String className = Descriptor.toJvmName( call.getClassName() ); | 206 | String className = Descriptor.toJvmName( call.getClassName() ); |
| 192 | ConstructorEntry calledConstructorEntry = new ConstructorEntry( | 207 | ConstructorEntry calledConstructorEntry = new ConstructorEntry( |
| 193 | new ClassEntry( className ), | 208 | new ClassEntry( className ), |
| 194 | call.getSignature() | 209 | call.getSignature() |
| 195 | ); | 210 | ); |
| 196 | m_methodCalls.put( calledConstructorEntry, thisEntry ); | 211 | callNumbers.add( calledConstructorEntry ); |
| 212 | EntryReference<ConstructorEntry> reference = new EntryReference<ConstructorEntry>( | ||
| 213 | calledConstructorEntry, | ||
| 214 | thisEntry, | ||
| 215 | callNumbers.count( calledConstructorEntry ) - 1 | ||
| 216 | ); | ||
| 217 | m_behaviorReferences.put( calledConstructorEntry, reference ); | ||
| 197 | } | 218 | } |
| 198 | 219 | ||
| 199 | @Override | 220 | @Override |
| @@ -204,7 +225,13 @@ public class JarIndex | |||
| 204 | new ClassEntry( className ), | 225 | new ClassEntry( className ), |
| 205 | call.getSignature() | 226 | call.getSignature() |
| 206 | ); | 227 | ); |
| 207 | m_methodCalls.put( calledConstructorEntry, thisEntry ); | 228 | callNumbers.add( calledConstructorEntry ); |
| 229 | EntryReference<ConstructorEntry> reference = new EntryReference<ConstructorEntry>( | ||
| 230 | calledConstructorEntry, | ||
| 231 | thisEntry, | ||
| 232 | callNumbers.count( calledConstructorEntry ) - 1 | ||
| 233 | ); | ||
| 234 | m_behaviorReferences.put( calledConstructorEntry, reference ); | ||
| 208 | } | 235 | } |
| 209 | } ); | 236 | } ); |
| 210 | } | 237 | } |
| @@ -234,9 +261,9 @@ public class JarIndex | |||
| 234 | new ClassEntry( Descriptor.toJvmName( c.getName() ) ), | 261 | new ClassEntry( Descriptor.toJvmName( c.getName() ) ), |
| 235 | constructor.getMethodInfo().getDescriptor() | 262 | constructor.getMethodInfo().getDescriptor() |
| 236 | ); | 263 | ); |
| 237 | for( Entry callerEntry : getMethodCallers( constructorEntry ) ) | 264 | for( EntryReference<BehaviorEntry> reference : getBehaviorReferences( constructorEntry ) ) |
| 238 | { | 265 | { |
| 239 | callerClasses.add( callerEntry.getClassEntry() ); | 266 | callerClasses.add( reference.caller.getClassEntry() ); |
| 240 | } | 267 | } |
| 241 | 268 | ||
| 242 | // is this called by exactly one class? | 269 | // is this called by exactly one class? |
| @@ -388,7 +415,7 @@ public class JarIndex | |||
| 388 | new ClassEntry( innerClassName ), | 415 | new ClassEntry( innerClassName ), |
| 389 | constructor.getMethodInfo().getDescriptor() | 416 | constructor.getMethodInfo().getDescriptor() |
| 390 | ); | 417 | ); |
| 391 | if( getMethodCallers( constructorEntry ).size() != 1 ) | 418 | if( getBehaviorReferences( constructorEntry ).size() != 1 ) |
| 392 | { | 419 | { |
| 393 | return false; | 420 | return false; |
| 394 | } | 421 | } |
| @@ -469,14 +496,26 @@ public class JarIndex | |||
| 469 | return rootNode; | 496 | return rootNode; |
| 470 | } | 497 | } |
| 471 | 498 | ||
| 472 | public Collection<Entry> getFieldCallers( FieldEntry fieldEntry ) | 499 | @SuppressWarnings( "unchecked" ) |
| 500 | public Collection<EntryReference<FieldEntry>> getFieldReferences( FieldEntry fieldEntry ) | ||
| 473 | { | 501 | { |
| 474 | return m_fieldCalls.get( fieldEntry ); | 502 | List<EntryReference<FieldEntry>> references = Lists.newArrayList(); |
| 503 | for( EntryReference<? extends Entry> reference : m_fieldReferences.get( fieldEntry ) ) | ||
| 504 | { | ||
| 505 | references.add( (EntryReference<FieldEntry>)reference ); | ||
| 506 | } | ||
| 507 | return references; | ||
| 475 | } | 508 | } |
| 476 | 509 | ||
| 477 | public Collection<Entry> getMethodCallers( Entry entry ) | 510 | @SuppressWarnings( "unchecked" ) |
| 511 | public Collection<EntryReference<BehaviorEntry>> getBehaviorReferences( BehaviorEntry behaviorEntry ) | ||
| 478 | { | 512 | { |
| 479 | return m_methodCalls.get( entry ); | 513 | List<EntryReference<BehaviorEntry>> references = Lists.newArrayList(); |
| 514 | for( EntryReference<? extends Entry> reference : m_behaviorReferences.get( behaviorEntry ) ) | ||
| 515 | { | ||
| 516 | references.add( (EntryReference<BehaviorEntry>)reference ); | ||
| 517 | } | ||
| 518 | return references; | ||
| 480 | } | 519 | } |
| 481 | 520 | ||
| 482 | public Collection<String> getInnerClasses( String obfOuterClassName ) | 521 | public Collection<String> getInnerClasses( String obfOuterClassName ) |
| @@ -498,85 +537,91 @@ public class JarIndex | |||
| 498 | { | 537 | { |
| 499 | m_ancestries.renameClasses( renames ); | 538 | m_ancestries.renameClasses( renames ); |
| 500 | renameMultimap( renames, m_methodImplementations ); | 539 | renameMultimap( renames, m_methodImplementations ); |
| 501 | renameMultimap( renames, m_methodCalls ); | 540 | renameMultimap( renames, m_behaviorReferences ); |
| 502 | renameMultimap( renames, m_fieldCalls ); | 541 | renameMultimap( renames, m_fieldReferences ); |
| 503 | } | 542 | } |
| 504 | 543 | ||
| 505 | private <T,U> void renameMultimap( Map<String,String> renames, Multimap<T,U> map ) | 544 | private <Key,Val> void renameMultimap( Map<String,String> renames, Multimap<Key,Val> map ) |
| 506 | { | 545 | { |
| 507 | // for each key/value pair... | 546 | // for each key/value pair... |
| 508 | Set<Map.Entry<T,U>> entriesToAdd = Sets.newHashSet(); | 547 | Set<Map.Entry<Key,Val>> entriesToAdd = Sets.newHashSet(); |
| 509 | Iterator<Map.Entry<T,U>> iter = map.entries().iterator(); | 548 | Iterator<Map.Entry<Key,Val>> iter = map.entries().iterator(); |
| 510 | while( iter.hasNext() ) | 549 | while( iter.hasNext() ) |
| 511 | { | 550 | { |
| 512 | Map.Entry<T,U> entry = iter.next(); | 551 | Map.Entry<Key,Val> entry = iter.next(); |
| 513 | iter.remove(); | 552 | iter.remove(); |
| 514 | entriesToAdd.add( new AbstractMap.SimpleEntry<T,U>( | 553 | entriesToAdd.add( new AbstractMap.SimpleEntry<Key,Val>( |
| 515 | renameEntry( renames, entry.getKey() ), | 554 | renameThing( renames, entry.getKey() ), |
| 516 | renameEntry( renames, entry.getValue() ) | 555 | renameThing( renames, entry.getValue() ) |
| 517 | ) ); | 556 | ) ); |
| 518 | } | 557 | } |
| 519 | for( Map.Entry<T,U> entry : entriesToAdd ) | 558 | for( Map.Entry<Key,Val> entry : entriesToAdd ) |
| 520 | { | 559 | { |
| 521 | map.put( entry.getKey(), entry.getValue() ); | 560 | map.put( entry.getKey(), entry.getValue() ); |
| 522 | } | 561 | } |
| 523 | } | 562 | } |
| 524 | 563 | ||
| 525 | @SuppressWarnings( "unchecked" ) | 564 | @SuppressWarnings( "unchecked" ) |
| 526 | private <T> T renameEntry( Map<String,String> renames, T entry ) | 565 | private <T> T renameThing( Map<String,String> renames, T thing ) |
| 527 | { | 566 | { |
| 528 | if( entry instanceof String ) | 567 | if( thing instanceof String ) |
| 529 | { | 568 | { |
| 530 | String stringEntry = (String)entry; | 569 | String stringEntry = (String)thing; |
| 531 | if( renames.containsKey( stringEntry ) ) | 570 | if( renames.containsKey( stringEntry ) ) |
| 532 | { | 571 | { |
| 533 | return (T)renames.get( stringEntry ); | 572 | return (T)renames.get( stringEntry ); |
| 534 | } | 573 | } |
| 535 | } | 574 | } |
| 536 | else if( entry instanceof ClassEntry ) | 575 | else if( thing instanceof ClassEntry ) |
| 537 | { | 576 | { |
| 538 | ClassEntry classEntry = (ClassEntry)entry; | 577 | ClassEntry classEntry = (ClassEntry)thing; |
| 539 | return (T)new ClassEntry( renameEntry( renames, classEntry.getClassName() ) ); | 578 | return (T)new ClassEntry( renameThing( renames, classEntry.getClassName() ) ); |
| 540 | } | 579 | } |
| 541 | else if( entry instanceof FieldEntry ) | 580 | else if( thing instanceof FieldEntry ) |
| 542 | { | 581 | { |
| 543 | FieldEntry fieldEntry = (FieldEntry)entry; | 582 | FieldEntry fieldEntry = (FieldEntry)thing; |
| 544 | return (T)new FieldEntry( | 583 | return (T)new FieldEntry( |
| 545 | renameEntry( renames, fieldEntry.getClassEntry() ), | 584 | renameThing( renames, fieldEntry.getClassEntry() ), |
| 546 | fieldEntry.getName() | 585 | fieldEntry.getName() |
| 547 | ); | 586 | ); |
| 548 | } | 587 | } |
| 549 | else if( entry instanceof ConstructorEntry ) | 588 | else if( thing instanceof ConstructorEntry ) |
| 550 | { | 589 | { |
| 551 | ConstructorEntry constructorEntry = (ConstructorEntry)entry; | 590 | ConstructorEntry constructorEntry = (ConstructorEntry)thing; |
| 552 | return (T)new ConstructorEntry( | 591 | return (T)new ConstructorEntry( |
| 553 | renameEntry( renames, constructorEntry.getClassEntry() ), | 592 | renameThing( renames, constructorEntry.getClassEntry() ), |
| 554 | constructorEntry.getSignature() | 593 | constructorEntry.getSignature() |
| 555 | ); | 594 | ); |
| 556 | } | 595 | } |
| 557 | else if( entry instanceof MethodEntry ) | 596 | else if( thing instanceof MethodEntry ) |
| 558 | { | 597 | { |
| 559 | MethodEntry methodEntry = (MethodEntry)entry; | 598 | MethodEntry methodEntry = (MethodEntry)thing; |
| 560 | return (T)new MethodEntry( | 599 | return (T)new MethodEntry( |
| 561 | renameEntry( renames, methodEntry.getClassEntry() ), | 600 | renameThing( renames, methodEntry.getClassEntry() ), |
| 562 | methodEntry.getName(), | 601 | methodEntry.getName(), |
| 563 | methodEntry.getSignature() | 602 | methodEntry.getSignature() |
| 564 | ); | 603 | ); |
| 565 | } | 604 | } |
| 566 | else if( entry instanceof ArgumentEntry ) | 605 | else if( thing instanceof ArgumentEntry ) |
| 567 | { | 606 | { |
| 568 | ArgumentEntry argumentEntry = (ArgumentEntry)entry; | 607 | ArgumentEntry argumentEntry = (ArgumentEntry)thing; |
| 569 | return (T)new ArgumentEntry( | 608 | return (T)new ArgumentEntry( |
| 570 | renameEntry( renames, argumentEntry.getMethodEntry() ), | 609 | renameThing( renames, argumentEntry.getMethodEntry() ), |
| 571 | argumentEntry.getIndex(), | 610 | argumentEntry.getIndex(), |
| 572 | argumentEntry.getName() | 611 | argumentEntry.getName() |
| 573 | ); | 612 | ); |
| 574 | } | 613 | } |
| 614 | else if( thing instanceof EntryReference ) | ||
| 615 | { | ||
| 616 | EntryReference<Entry> reference = (EntryReference<Entry>)thing; | ||
| 617 | reference.entry = renameThing( renames, reference.entry ); | ||
| 618 | return thing; | ||
| 619 | } | ||
| 575 | else | 620 | else |
| 576 | { | 621 | { |
| 577 | throw new Error( "Not an entry: " + entry ); | 622 | throw new Error( "Not an entry: " + thing ); |
| 578 | } | 623 | } |
| 579 | 624 | ||
| 580 | return entry; | 625 | return thing; |
| 581 | } | 626 | } |
| 582 | } | 627 | } |