From d006997d2d231cee47fd205fac498828939f8aea Mon Sep 17 00:00:00 2001 From: Graham Date: Sun, 12 Apr 2020 09:18:13 +0100 Subject: [PATCH] Add annotation processor for creating deobufscator name mapping files I'm ignoring the deobfuscator mapping files for now, but when the deobfuscator is finished then I'll add them to the repository and keep them up to date. Signed-off-by: Graham --- .../main/java/dev/openrs2/asm/MemberRef.kt | 16 ++- buildSrc/src/main/java/Versions.kt | 1 + data/.gitignore | 1 + deob-map/build.gradle.kts | 25 +++++ .../main/java/dev/openrs2/deob/map/Field.kt | 3 + .../main/java/dev/openrs2/deob/map/Method.kt | 14 +++ .../main/java/dev/openrs2/deob/map/NameMap.kt | 10 ++ deob-processor/build.gradle.kts | 28 +++++ .../deob/processor/LocalVariableScanner.kt | 19 ++++ .../deob/processor/NameMapProcessor.kt | 102 ++++++++++++++++++ .../javax.annotation.processing.Processor | 1 + settings.gradle.kts | 2 + 12 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 data/.gitignore create mode 100644 deob-map/build.gradle.kts create mode 100644 deob-map/src/main/java/dev/openrs2/deob/map/Field.kt create mode 100644 deob-map/src/main/java/dev/openrs2/deob/map/Method.kt create mode 100644 deob-map/src/main/java/dev/openrs2/deob/map/NameMap.kt create mode 100644 deob-processor/build.gradle.kts create mode 100644 deob-processor/src/main/java/dev/openrs2/deob/processor/LocalVariableScanner.kt create mode 100644 deob-processor/src/main/java/dev/openrs2/deob/processor/NameMapProcessor.kt create mode 100644 deob-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor diff --git a/asm/src/main/java/dev/openrs2/asm/MemberRef.kt b/asm/src/main/java/dev/openrs2/asm/MemberRef.kt index f6f34ecd..53dca95c 100644 --- a/asm/src/main/java/dev/openrs2/asm/MemberRef.kt +++ b/asm/src/main/java/dev/openrs2/asm/MemberRef.kt @@ -6,13 +6,27 @@ import org.objectweb.asm.tree.FieldNode import org.objectweb.asm.tree.MethodInsnNode import org.objectweb.asm.tree.MethodNode -data class MemberRef(val owner: String, val name: String, val desc: String) { +data class MemberRef(val owner: String, val name: String, val desc: String) : Comparable { constructor(clazz: ClassNode, field: FieldNode) : this(clazz.name, field.name, field.desc) constructor(clazz: ClassNode, method: MethodNode) : this(clazz.name, method.name, method.desc) constructor(fieldInsn: FieldInsnNode) : this(fieldInsn.owner, fieldInsn.name, fieldInsn.desc) constructor(methodInsn: MethodInsnNode) : this(methodInsn.owner, methodInsn.name, methodInsn.desc) constructor(owner: String, desc: MemberDesc) : this(owner, desc.name, desc.desc) + override fun compareTo(other: MemberRef): Int { + var result = owner.compareTo(other.owner) + if (result != 0) { + return result + } + + result = name.compareTo(other.name) + if (result != 0) { + return result + } + + return desc.compareTo(other.desc) + } + override fun toString(): String { return "$owner.$name $desc" } diff --git a/buildSrc/src/main/java/Versions.kt b/buildSrc/src/main/java/Versions.kt index 7fdc0a14..9b084769 100644 --- a/buildSrc/src/main/java/Versions.kt +++ b/buildSrc/src/main/java/Versions.kt @@ -9,6 +9,7 @@ object Versions { const val guava = "28.2-jre" const val guice = "4.2.3" const val inlineLogger = "1.0.2" + const val jackson = "2.10.3" const val javaParser = "3.15.18" const val jdom = "2.0.6" const val jgrapht = "1.4.0" diff --git a/data/.gitignore b/data/.gitignore new file mode 100644 index 00000000..74d6c1f8 --- /dev/null +++ b/data/.gitignore @@ -0,0 +1 @@ +/deob-map diff --git a/deob-map/build.gradle.kts b/deob-map/build.gradle.kts new file mode 100644 index 00000000..d531cb4a --- /dev/null +++ b/deob-map/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + `maven-publish` + kotlin("jvm") +} + +dependencies { + api(project(":asm")) +} + +publishing { + publications.create("maven") { + from(components["java"]) + + pom { + packaging = "jar" + name.set("OpenRS2 Deobfuscator Map") + description.set( + """ + Data structures for representing a map of obfuscated to + refactored names. + """.trimIndent() + ) + } + } +} diff --git a/deob-map/src/main/java/dev/openrs2/deob/map/Field.kt b/deob-map/src/main/java/dev/openrs2/deob/map/Field.kt new file mode 100644 index 00000000..b0d88939 --- /dev/null +++ b/deob-map/src/main/java/dev/openrs2/deob/map/Field.kt @@ -0,0 +1,3 @@ +package dev.openrs2.deob.map + +data class Field(val owner: String, val name: String) diff --git a/deob-map/src/main/java/dev/openrs2/deob/map/Method.kt b/deob-map/src/main/java/dev/openrs2/deob/map/Method.kt new file mode 100644 index 00000000..9a1a86c4 --- /dev/null +++ b/deob-map/src/main/java/dev/openrs2/deob/map/Method.kt @@ -0,0 +1,14 @@ +package dev.openrs2.deob.map + +import java.util.SortedMap + +data class Method( + val owner: String, + val name: String, + /* + * Uses concrete type as there is no interface for a map sorted by + * insertion order. + */ + val arguments: LinkedHashMap, + val locals: SortedMap +) diff --git a/deob-map/src/main/java/dev/openrs2/deob/map/NameMap.kt b/deob-map/src/main/java/dev/openrs2/deob/map/NameMap.kt new file mode 100644 index 00000000..815942ad --- /dev/null +++ b/deob-map/src/main/java/dev/openrs2/deob/map/NameMap.kt @@ -0,0 +1,10 @@ +package dev.openrs2.deob.map + +import dev.openrs2.asm.MemberRef +import java.util.SortedMap + +data class NameMap( + val classes: SortedMap, + val fields: SortedMap, + val methods: SortedMap +) diff --git a/deob-processor/build.gradle.kts b/deob-processor/build.gradle.kts new file mode 100644 index 00000000..6e5650de --- /dev/null +++ b/deob-processor/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + `maven-publish` + kotlin("jvm") +} + +dependencies { + implementation(project(":deob-annotations")) + implementation(project(":deob-map")) + implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${Versions.jackson}") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:${Versions.jackson}") +} + +publishing { + publications.create("maven") { + from(components["java"]) + + pom { + packaging = "jar" + name.set("OpenRS2 Deobfuscator Annotation Processor") + description.set( + """ + Processes deobfuscator annotations to create a mapping file of + obfuscated to refactored names. + """.trimIndent() + ) + } + } +} diff --git a/deob-processor/src/main/java/dev/openrs2/deob/processor/LocalVariableScanner.kt b/deob-processor/src/main/java/dev/openrs2/deob/processor/LocalVariableScanner.kt new file mode 100644 index 00000000..16f018f0 --- /dev/null +++ b/deob-processor/src/main/java/dev/openrs2/deob/processor/LocalVariableScanner.kt @@ -0,0 +1,19 @@ +package dev.openrs2.deob.processor + +import com.sun.source.tree.VariableTree +import com.sun.source.util.TreePathScanner +import com.sun.source.util.Trees +import dev.openrs2.deob.annotation.Pc + +class LocalVariableScanner(private val trees: Trees) : TreePathScanner>() { + override fun visitVariable(node: VariableTree, p: MutableMap): Void? { + val element = trees.getElement(currentPath) + + val pc = element.getAnnotation(Pc::class.java) + if (pc != null) { + p[pc.value] = element.simpleName.toString() + } + + return super.visitVariable(node, p) + } +} diff --git a/deob-processor/src/main/java/dev/openrs2/deob/processor/NameMapProcessor.kt b/deob-processor/src/main/java/dev/openrs2/deob/processor/NameMapProcessor.kt new file mode 100644 index 00000000..b2be0dc8 --- /dev/null +++ b/deob-processor/src/main/java/dev/openrs2/deob/processor/NameMapProcessor.kt @@ -0,0 +1,102 @@ +package dev.openrs2.deob.processor + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory +import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import com.sun.source.util.Trees +import dev.openrs2.asm.MemberRef +import dev.openrs2.asm.toInternalClassName +import dev.openrs2.deob.annotation.OriginalArg +import dev.openrs2.deob.annotation.OriginalClass +import dev.openrs2.deob.annotation.OriginalMember +import dev.openrs2.deob.map.Field +import dev.openrs2.deob.map.Method +import dev.openrs2.deob.map.NameMap +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.util.TreeMap +import javax.annotation.processing.AbstractProcessor +import javax.annotation.processing.ProcessingEnvironment +import javax.annotation.processing.RoundEnvironment +import javax.annotation.processing.SupportedAnnotationTypes +import javax.annotation.processing.SupportedOptions +import javax.annotation.processing.SupportedSourceVersion +import javax.lang.model.SourceVersion +import javax.lang.model.element.ExecutableElement +import javax.lang.model.element.TypeElement +import javax.lang.model.element.VariableElement + +@SupportedAnnotationTypes( + "dev.openrs2.deob.annotation.OriginalArg", + "dev.openrs2.deob.annotation.OriginalClass", + "dev.openrs2.deob.annotation.OriginalMember", + "dev.openrs2.deob.annotation.Pc" +) +@SupportedSourceVersion(SourceVersion.RELEASE_11) +@SupportedOptions( + "map" +) +class NameMapProcessor : AbstractProcessor() { + private val classes = TreeMap() + private val fields = TreeMap() + private val methods = TreeMap() + private lateinit var trees: Trees + private lateinit var localScanner: LocalVariableScanner + + override fun init(env: ProcessingEnvironment) { + super.init(env) + trees = Trees.instance(env) + localScanner = LocalVariableScanner(trees) + } + + private fun getPath(): Path? { + val map = processingEnv.options["map"] ?: return null + return Paths.get(map) + } + + override fun process(annotations: Set, env: RoundEnvironment): Boolean { + val mapPath = getPath() ?: return true + + for (element in env.getElementsAnnotatedWith(OriginalClass::class.java)) { + check(element is TypeElement) + + val originalClass = element.getAnnotation(OriginalClass::class.java)!! + classes[originalClass.value] = element.qualifiedName.toString().toInternalClassName() + } + + for (element in env.getElementsAnnotatedWith(OriginalMember::class.java)) { + val path = trees.getPath(element) + val owner = trees.getScope(path).enclosingClass.qualifiedName.toString().toInternalClassName() + val name = element.simpleName.toString() + + val originalMember = element.getAnnotation(OriginalMember::class.java)!! + val ref = MemberRef(originalMember.owner, originalMember.name, originalMember.descriptor) + + when (element) { + is VariableElement -> fields[ref] = Field(owner, name) + is ExecutableElement -> { + val arguments = element.parameters.map { parameter -> + val originalArg = parameter.getAnnotation(OriginalArg::class.java)!! + Pair(originalArg.value, parameter.simpleName.toString()) + }.toMap(LinkedHashMap()) + + val locals = TreeMap() + localScanner.scan(path, locals) + + methods[ref] = Method(owner, name, arguments, locals) + } + else -> error("Unexpected element type") + } + } + + if (env.processingOver()) { + Files.newBufferedWriter(mapPath).use { writer -> + val mapper = ObjectMapper(YAMLFactory()).registerKotlinModule() + mapper.writeValue(writer, NameMap(classes, fields, methods)) + } + } + + return true + } +} diff --git a/deob-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/deob-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000..f89b051b --- /dev/null +++ b/deob-processor/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +dev.openrs2.deob.processor.NameMapProcessor diff --git a/settings.gradle.kts b/settings.gradle.kts index 368773da..9fbb4411 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,6 +15,8 @@ include( "deob", "deob-annotations", "deob-ast", + "deob-map", + "deob-processor", "game", "util" )