From 4ca56ff079d52fa319044124c8dbc1757fe78da0 Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Mon, 19 Jul 2021 19:22:18 -0700 Subject: [PATCH] [ci skip] Put mappings util in a separate class to the stacktrace deobfuscator (#6230) --- ...ktraces-in-log-messages-crash-report.patch | 180 ++++++++++-------- ...nd-timings-for-sensors-and-behaviors.patch | 34 ++-- 2 files changed, 119 insertions(+), 95 deletions(-) diff --git a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch index 9c4fe9c3a3..48dbb5c1eb 100644 --- a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch +++ b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch @@ -157,60 +157,49 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return new StacktraceDeobfuscatingRewritePolicy(); + } +} -diff --git a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java +diff --git a/src/main/java/io/papermc/paper/util/ObfHelper.java b/src/main/java/io/papermc/paper/util/ObfHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 --- /dev/null -+++ b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java ++++ b/src/main/java/io/papermc/paper/util/ObfHelper.java @@ -0,0 +0,0 @@ +package io.papermc.paper.util; + -+import com.destroystokyo.paper.PaperConfig; +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableMap; +import com.mojang.datafixers.util.Pair; -+import it.unimi.dsi.fastutil.ints.IntArrayList; -+import it.unimi.dsi.fastutil.ints.IntList; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; -+import java.util.Collections; -+import java.util.HashMap; -+import java.util.LinkedHashMap; +import java.util.Map; +import net.fabricmc.mapping.tree.ClassDef; +import net.fabricmc.mapping.tree.MethodDef; +import net.fabricmc.mapping.tree.TinyMappingFactory; +import net.fabricmc.mapping.tree.TinyTree; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+import org.objectweb.asm.ClassReader; -+import org.objectweb.asm.ClassVisitor; -+import org.objectweb.asm.Label; -+import org.objectweb.asm.MethodVisitor; -+import org.objectweb.asm.Opcodes; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; + -+public enum StacktraceDeobfuscator { ++@DefaultQualifier(NonNull.class) ++public enum ObfHelper { + INSTANCE; + -+ private static final String MOJANG_PLUS_YARN_NAMESPACE = "mojang+yarn"; -+ private static final String SPIGOT_NAMESPACE = "spigot"; ++ public static final String MOJANG_PLUS_YARN_NAMESPACE = "mojang+yarn"; ++ public static final String SPIGOT_NAMESPACE = "spigot"; + + private final @Nullable Map mappings; -+ private final Map, Map, IntList>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(64, 0.75f, true) { -+ @Override -+ protected boolean removeEldestEntry(final Map.Entry, Map, IntList>> eldest) { -+ return this.size() > 63; -+ } -+ }); + -+ StacktraceDeobfuscator() { ++ ObfHelper() { + this.mappings = loadMappingsIfPresent(); + } + ++ public @Nullable Map mappings() { ++ return this.mappings; ++ } ++ + private static @Nullable Map loadMappingsIfPresent() { -+ try (final InputStream mappingsInputStream = StacktraceDeobfuscator.class.getClassLoader().getResourceAsStream("META-INF/mappings/reobf.tiny")) { ++ try (final @Nullable InputStream mappingsInputStream = StacktraceDeobfuscator.class.getClassLoader().getResourceAsStream("META-INF/mappings/reobf.tiny")) { + if (mappingsInputStream == null) { + return null; + } @@ -249,6 +238,55 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } + ++ public record ClassMapping( ++ String obfName, ++ String mojangName, ++ Map, MethodMapping> methodMappings ++ ) {} ++ ++ public record MethodMapping( ++ String obfName, ++ String mojangName, ++ String descriptor ++ ) {} ++} +diff --git a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.util; ++ ++import com.destroystokyo.paper.PaperConfig; ++import com.mojang.datafixers.util.Pair; ++import it.unimi.dsi.fastutil.ints.IntArrayList; ++import it.unimi.dsi.fastutil.ints.IntList; ++import java.io.IOException; ++import java.util.Collections; ++import java.util.HashMap; ++import java.util.LinkedHashMap; ++import java.util.Map; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++import org.objectweb.asm.ClassReader; ++import org.objectweb.asm.ClassVisitor; ++import org.objectweb.asm.Label; ++import org.objectweb.asm.MethodVisitor; ++import org.objectweb.asm.Opcodes; ++ ++@DefaultQualifier(NonNull.class) ++public enum StacktraceDeobfuscator { ++ INSTANCE; ++ ++ private final Map, Map, IntList>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) { ++ @Override ++ protected boolean removeEldestEntry(final Map.Entry, Map, IntList>> eldest) { ++ return this.size() > 127; ++ } ++ }); ++ + public void deobfuscateThrowable(final Throwable throwable) { + if (!PaperConfig.deobfuscateStacktraces) { + return; @@ -269,7 +307,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + return traceElements; + } + -+ if (this.mappings == null || traceElements.length == 0) { ++ final @Nullable Map mappings = ObfHelper.INSTANCE.mappings(); ++ if (mappings == null || traceElements.length == 0) { + return traceElements; + } + final StackTraceElement[] result = new StackTraceElement[traceElements.length]; @@ -279,21 +318,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + final String className = element.getClassName(); + final String methodName = element.getMethodName(); + -+ final ClassMapping classMapping = this.mappings.get(className); ++ final ObfHelper.ClassMapping classMapping = mappings.get(className); + if (classMapping == null) { + result[i] = element; + continue; + } + -+ final Pair nameDescriptorPair; ++ final Class clazz; + try { -+ final Class clazz = Class.forName(className); -+ nameDescriptorPair = this.determineMethodForLine(clazz, element.getLineNumber()); -+ } catch (final ReflectiveOperationException ex) { ++ clazz = Class.forName(className); ++ } catch (final ClassNotFoundException ex) { + throw new RuntimeException(ex); + } -+ -+ final MethodMapping methodMapping = classMapping.methodMappings().get(nameDescriptorPair); ++ final @Nullable Pair nameDescriptorPair = this.determineMethodForLine(clazz, element.getLineNumber()); ++ final ObfHelper.@Nullable MethodMapping methodMapping = nameDescriptorPair == null ++ ? null ++ : classMapping.methodMappings().get(nameDescriptorPair); + + result[i] = new StackTraceElement( + element.getClassLoaderName(), @@ -301,14 +341,38 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + element.getModuleVersion(), + classMapping.mojangName(), + methodMapping != null ? methodMapping.mojangName() : methodName, -+ this.mappedFileName(classMapping.mojangName()), ++ sourceFileName(classMapping.mojangName()), + element.getLineNumber() + ); + } + return result; + } + -+ private static @NotNull Map, IntList> buildLineMap(final @NotNull Class key) { ++ private @Nullable Pair determineMethodForLine(final Class clazz, final int lineNumber) { ++ final Map, IntList> lineMap = this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap); ++ for (final var entry : lineMap.entrySet()) { ++ final Pair pair = entry.getKey(); ++ final IntList lines = entry.getValue(); ++ for (int i = 0, linesSize = lines.size(); i < linesSize; i++) { ++ final int num = lines.getInt(i); ++ if (num == lineNumber) { ++ return pair; ++ } ++ } ++ } ++ return null; ++ } ++ ++ private static String sourceFileName(final String fullClassName) { ++ final int dot = fullClassName.lastIndexOf('.'); ++ final String className = dot == -1 ++ ? fullClassName ++ : fullClassName.substring(dot + 1); ++ final String rootClassName = className.split("\\$")[0]; ++ return rootClassName + ".java"; ++ } ++ ++ private static Map, IntList> buildLineMap(final Class key) { + final Map, IntList> lineMap = new HashMap<>(); + final class LineCollectingMethodVisitor extends MethodVisitor { + private final IntList lines = new IntArrayList(); @@ -347,48 +411,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + return lineMap; + } -+ -+ private @Nullable Pair determineMethodForLine(final @NotNull Class clazz, final int lineNumber) { -+ final Map, IntList> lineMap = this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap); -+ for (final var entry : lineMap.entrySet()) { -+ final Pair pair = entry.getKey(); -+ final IntList lines = entry.getValue(); -+ for (int i = 0, linesSize = lines.size(); i < linesSize; i++) { -+ final int num = lines.getInt(i); -+ if (num == lineNumber) { -+ return pair; -+ } -+ } -+ } -+ return null; -+ } -+ -+ private @NotNull String mappedFileName(final @NotNull String fullClassName) { -+ final int dot = fullClassName.lastIndexOf('.'); -+ final String className = dot == -1 -+ ? fullClassName -+ : fullClassName.substring(dot + 1); -+ final String rootClassName = className.split("\\$")[0]; -+ return rootClassName + ".java"; -+ } -+ -+ public record ClassMapping( -+ String obfName, -+ String mojangName, -+ Map, MethodMapping> methodMappings -+ ) { -+ } -+ -+ public record MethodMapping( -+ String obfName, -+ String mojangName, -+ String descriptor -+ ) { -+ } -+ -+ public @Nullable Map mappings() { -+ return mappings; -+ } +} diff --git a/src/main/java/io/papermc/paper/util/TraceUtil.java b/src/main/java/io/papermc/paper/util/TraceUtil.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 @@ -444,7 +466,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 com.destroystokyo.paper.PaperConfig.registerCommands(); com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // load version history now io.papermc.paper.brigadier.PaperBrigadierProviderImpl.INSTANCE.getClass(); // init PaperBrigadierProvider -+ io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.getClass(); // load mappings for stacktrace deobf ++ io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // load mappings for stacktrace deobf and etc. // Paper end this.setPvpAllowed(dedicatedserverproperties.pvp); diff --git a/patches/server/Rate-options-and-timings-for-sensors-and-behaviors.patch b/patches/server/Rate-options-and-timings-for-sensors-and-behaviors.patch index 3136dc5cf2..977eabbf72 100644 --- a/patches/server/Rate-options-and-timings-for-sensors-and-behaviors.patch +++ b/patches/server/Rate-options-and-timings-for-sensors-and-behaviors.patch @@ -130,16 +130,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 this.maxDuration = maxRunTime; this.entryCondition = requiredMemoryState; + // Paper start - configurable behavior tick rate and timings -+ Map mappings = io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.mappings(); -+ String key; ++ String key = this.getClass().getSimpleName(); ++ final var mappings = io.papermc.paper.util.ObfHelper.INSTANCE.mappings(); + if (mappings != null) { -+ key = mappings.get(getClass().getName()).mojangName(); -+ int lastSeparator = key.lastIndexOf('.'); -+ if (lastSeparator != -1) { -+ key = key.substring(lastSeparator + 1); ++ final var classMapping = mappings.get(this.getClass().getName()); ++ if (classMapping != null) { ++ key = classMapping.mojangName(); ++ int lastSeparator = key.lastIndexOf('.'); ++ if (lastSeparator != -1) { ++ key = key.substring(lastSeparator + 1); ++ } + } -+ } else { -+ key = getClass().getSimpleName(); + } + this.configKey = key.toLowerCase(java.util.Locale.ROOT); + this.timing = co.aikar.timings.MinecraftTimings.getBehaviorTimings(configKey); @@ -196,16 +197,17 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 public Sensor(int senseInterval) { + // Paper start - configurable sensor tick rate and timings -+ java.util.Map mappings = io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.mappings(); -+ String key; ++ String key = this.getClass().getSimpleName(); ++ final var mappings = io.papermc.paper.util.ObfHelper.INSTANCE.mappings(); + if (mappings != null) { -+ key = mappings.get(getClass().getName()).mojangName(); -+ int lastSeparator = key.lastIndexOf('.'); -+ if (lastSeparator != -1) { -+ key = key.substring(lastSeparator + 1); ++ final var classMapping = mappings.get(this.getClass().getName()); ++ if (classMapping != null) { ++ key = classMapping.mojangName(); ++ int lastSeparator = key.lastIndexOf('.'); ++ if (lastSeparator != -1) { ++ key = key.substring(lastSeparator + 1); ++ } + } -+ } else { -+ key = getClass().getSimpleName(); + } + this.configKey = key.toLowerCase(java.util.Locale.ROOT); + this.timing = co.aikar.timings.MinecraftTimings.getSensorTimings(configKey);