wasm gc: more configuration options to set up stack trace deobfuscation

This commit is contained in:
Alexey Andreev 2024-10-13 19:05:44 +02:00
parent 40d2ab97ec
commit 4f9208c4d4
23 changed files with 287 additions and 26 deletions

View File

@ -16,7 +16,6 @@
package org.teavm.backend.wasm; package org.teavm.backend.wasm;
public enum WasmDebugInfoLevel { public enum WasmDebugInfoLevel {
NONE,
DEOBFUSCATION, DEOBFUSCATION,
FULL FULL
} }

View File

@ -76,8 +76,9 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion(); private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion();
private boolean strict; private boolean strict;
private boolean obfuscated; private boolean obfuscated;
private WasmDebugInfoLocation debugLocation; private boolean debugInfo;
private WasmDebugInfoLevel debugLevel; private WasmDebugInfoLocation debugLocation = WasmDebugInfoLocation.EXTERNAL;
private WasmDebugInfoLevel debugLevel = WasmDebugInfoLevel.FULL;
private List<WasmGCIntrinsicFactory> intrinsicFactories = new ArrayList<>(); private List<WasmGCIntrinsicFactory> intrinsicFactories = new ArrayList<>();
private Map<MethodReference, WasmGCIntrinsic> customIntrinsics = new HashMap<>(); private Map<MethodReference, WasmGCIntrinsic> customIntrinsics = new HashMap<>();
private List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories = new ArrayList<>(); private List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories = new ArrayList<>();
@ -94,11 +95,15 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
this.strict = strict; this.strict = strict;
} }
public void setDebugLevel(WasmDebugInfoLevel debugLevel) { public void setDebugInfo(boolean debug) {
this.debugInfo = debug;
}
public void setDebugInfoLevel(WasmDebugInfoLevel debugLevel) {
this.debugLevel = debugLevel; this.debugLevel = debugLevel;
} }
public void setDebugLocation(WasmDebugInfoLocation debugLocation) { public void setDebugInfoLocation(WasmDebugInfoLocation debugLocation) {
this.debugLocation = debugLocation; this.debugLocation = debugLocation;
} }
@ -331,7 +336,7 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
GCDebugInfoBuilder debugInfoBuilder) throws IOException { GCDebugInfoBuilder debugInfoBuilder) throws IOException {
var binaryWriter = new WasmBinaryWriter(); var binaryWriter = new WasmBinaryWriter();
DebugLines debugLines = null; DebugLines debugLines = null;
if (debugLevel != WasmDebugInfoLevel.NONE) { if (debugInfo) {
debugLines = debugInfoBuilder.lines(); debugLines = debugInfoBuilder.lines();
} }
var binaryRenderer = new WasmBinaryRenderer(binaryWriter, WasmBinaryVersion.V_0x1, obfuscated, var binaryRenderer = new WasmBinaryRenderer(binaryWriter, WasmBinaryVersion.V_0x1, obfuscated,
@ -353,7 +358,7 @@ public class WasmGCTarget implements TeaVMTarget, TeaVMWasmGCHost {
if (debugLocation == WasmDebugInfoLocation.EXTERNAL) { if (debugLocation == WasmDebugInfoLocation.EXTERNAL) {
var debugInfoData = ExternalDebugFile.write(debugInfoBuilder.build()); var debugInfoData = ExternalDebugFile.write(debugInfoBuilder.build());
if (debugInfoData != null) { if (debugInfoData != null) {
try (var output = buildTarget.createResource(outputName + ".tdbg")) { try (var output = buildTarget.createResource(outputName + ".teadbg")) {
output.write(debugInfoData); output.write(debugInfoData);
} }
} }

View File

@ -16,10 +16,15 @@
package org.teavm.backend.wasm.debug; package org.teavm.backend.wasm.debug;
import java.util.List; import java.util.List;
import java.util.function.Function;
import org.teavm.backend.wasm.model.WasmCustomSection; import org.teavm.backend.wasm.model.WasmCustomSection;
import org.teavm.backend.wasm.parser.AddressListener;
import org.teavm.backend.wasm.parser.WasmBinaryReader;
import org.teavm.backend.wasm.render.WasmBinaryWriter; import org.teavm.backend.wasm.render.WasmBinaryWriter;
public final class ExternalDebugFile { public final class ExternalDebugFile {
private static final int SIGNATURE = 0x67626474;
private ExternalDebugFile() { private ExternalDebugFile() {
} }
@ -28,8 +33,8 @@ public final class ExternalDebugFile {
return null; return null;
} }
var writer = new WasmBinaryWriter(); var writer = new WasmBinaryWriter();
writer.writeInt32(0x67626474); writer.writeInt32(SIGNATURE);
writer.writeInt32(1); writer.writeLEB(1);
for (var section : sections) { for (var section : sections) {
var data = section.getData(); var data = section.getData();
writer.writeAsciiString(section.getName()); writer.writeAsciiString(section.getName());
@ -38,4 +43,29 @@ public final class ExternalDebugFile {
} }
return writer.getData(); return writer.getData();
} }
public static boolean read(byte[] data, Function<String, SectionDataConsumer> consumer) {
if (data.length < 4) {
return false;
}
var reader = new WasmBinaryReader(AddressListener.EMPTY, data);
var header = reader.readInt32();
if (header != SIGNATURE) {
return false;
}
var version = reader.readLEB();
if (version != 1) {
return false;
}
while (reader.ptr < data.length) {
var name = reader.readString();
var length = reader.readLEB();
var sectionConsumer = consumer.apply(name);
if (sectionConsumer != null) {
sectionConsumer.accept(data, reader.ptr, reader.ptr + length);
}
reader.ptr += length;
}
return true;
}
} }

View File

@ -0,0 +1,20 @@
/*
* Copyright 2024 Alexey Andreev.
*
* 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 org.teavm.backend.wasm.debug;
public interface SectionDataConsumer {
void accept(byte[] data, int start, int end);
}

View File

@ -173,6 +173,13 @@ public class WasmBinaryReader {
return result; return result;
} }
public int readInt32() {
return (data[ptr++] & 0xFF)
| ((data[ptr++] & 0xFF) << 8)
| ((data[ptr++] & 0xFF) << 16)
| ((data[ptr++] & 0xFF) << 24);
}
public int readFixedInt() { public int readFixedInt() {
return ((data[ptr++] & 0xFF) << 24) return ((data[ptr++] & 0xFF) << 24)
| ((data[ptr++] & 0xFF) << 16) | ((data[ptr++] & 0xFF) << 16)

View File

@ -425,6 +425,9 @@ function jsoImports(imports, context) {
Object.defineProperty(cls, name, descriptor); Object.defineProperty(cls, name, descriptor);
}, },
javaObjectToJS(instance, cls) { javaObjectToJS(instance, cls) {
if (instance === null) {
return null;
}
let existing = jsWrappers.get(instance); let existing = jsWrappers.get(instance);
if (typeof existing != "undefined") { if (typeof existing != "undefined") {
let result = existing.deref(); let result = existing.deref();
@ -604,14 +607,18 @@ async function load(path, options) {
options.installImports(importObj); options.installImports(importObj);
} }
let [deobfuscatorFactory, { module, instance }] = await Promise.all([ let deobfuscatorOptions = options.stackDeobfuscator || {};
options.attachStackDeobfuscator ? getDeobfuscator(path, options) : Promise.resolve(null), let debugInfoLocation = deobfuscatorOptions.infoLocation || "auto";
WebAssembly.instantiateStreaming(fetch(path), importObj) let [deobfuscatorFactory, { module, instance }, debugInfo] = await Promise.all([
deobfuscatorOptions.enabled ? getDeobfuscator(path, deobfuscatorOptions) : Promise.resolve(null),
WebAssembly.instantiateStreaming(fetch(path), importObj),
fetchExternalDebugInfo(path, debugInfoLocation, deobfuscatorOptions)
]); ]);
defaultsResult.supplyExports(instance.exports); defaultsResult.supplyExports(instance.exports);
if (deobfuscatorFactory) { if (deobfuscatorFactory) {
let deobfuscator = createDeobfuscator(module, deobfuscatorFactory); let moduleToPass = debugInfoLocation === "auto" || debugInfoLocation === "embedded" ? module : null;
let deobfuscator = createDeobfuscator(moduleToPass, debugInfo, deobfuscatorFactory);
if (deobfuscator !== null) { if (deobfuscator !== null) {
defaultsResult.supplyStackDeobfuscator(deobfuscator); defaultsResult.supplyStackDeobfuscator(deobfuscator);
} }
@ -637,7 +644,8 @@ async function getDeobfuscator(path, options) {
try { try {
const importObj = {}; const importObj = {};
const defaultsResult = defaults(importObj, {}); const defaultsResult = defaults(importObj, {});
const { instance } = await WebAssembly.instantiateStreaming(fetch(path + "-deobfuscator.wasm"), importObj); const deobfuscatorPath = options.path || path + "-deobfuscator.wasm";
const { instance } = await WebAssembly.instantiateStreaming(fetch(deobfuscatorPath), importObj);
defaultsResult.supplyExports(instance.exports) defaultsResult.supplyExports(instance.exports)
return instance; return instance;
} catch (e) { } catch (e) {
@ -646,16 +654,25 @@ async function getDeobfuscator(path, options) {
} }
} }
function createDeobfuscator(module, deobfuscatorFactory) { function createDeobfuscator(module, externalData, deobfuscatorFactory) {
let deobfuscator = null; let deobfuscator = null;
let deobfuscatorInitialized = false; let deobfuscatorInitialized = false;
function ensureDeobfuscator() { function ensureDeobfuscator() {
if (!deobfuscatorInitialized) { if (!deobfuscatorInitialized) {
deobfuscatorInitialized = true; deobfuscatorInitialized = true;
try { if (externalData !== null) {
deobfuscator = deobfuscatorFactory.exports.createForModule.value(module); try {
} catch (e) { deobfuscator = deobfuscatorFactory.exports.createFromExternalFile.value(externalData);
console.warn("Could not load create deobfuscator", e); } catch (e) {
console.warn("Could not load create deobfuscator", e);
}
}
if (deobfuscator == null && module !== null) {
try {
deobfuscator = deobfuscatorFactory.exports.createForModule.value(module);
} catch (e) {
console.warn("Could not create deobfuscator from module data", e);
}
} }
} }
} }
@ -663,4 +680,19 @@ function createDeobfuscator(module, deobfuscatorFactory) {
ensureDeobfuscator(); ensureDeobfuscator();
return deobfuscator !== null ? deobfuscator.deobfuscate(addresses) : []; return deobfuscator !== null ? deobfuscator.deobfuscate(addresses) : [];
} }
}
async function fetchExternalDebugInfo(path, debugInfoLocation, options) {
if (!options.enabled) {
return null;
}
if (debugInfoLocation !== "auto" && debugInfoLocation !== "external") {
return null;
}
let location = options.externalInfoPath || path + ".teadbg";
let response = await fetch(location);
if (!response.ok) {
return null;
}
return new Int8Array(await response.arrayBuffer());
} }

View File

@ -171,8 +171,8 @@ public class ExportTest {
try { try {
var wasmGCTarget = new WasmGCTarget(); var wasmGCTarget = new WasmGCTarget();
wasmGCTarget.setObfuscated(false); wasmGCTarget.setObfuscated(false);
wasmGCTarget.setDebugLocation(WasmDebugInfoLocation.EMBEDDED); wasmGCTarget.setDebugInfoLocation(WasmDebugInfoLocation.EMBEDDED);
wasmGCTarget.setDebugLevel(WasmDebugInfoLevel.DEOBFUSCATION); wasmGCTarget.setDebugInfoLevel(WasmDebugInfoLevel.DEOBFUSCATION);
var teavm = new TeaVMBuilder(wasmGCTarget).build(); var teavm = new TeaVMBuilder(wasmGCTarget).build();
var outputDir = new File(wasmGCTargetFile, name); var outputDir = new File(wasmGCTargetFile, name);
teavm.installPlugins(); teavm.installPlugins();

View File

@ -211,7 +211,9 @@ function launchWasmGCTest(file, argument, callback) {
} }
TeaVM.wasmGC.load(file.path, { TeaVM.wasmGC.load(file.path, {
attachStackDeobfuscator: true, stackDeobfuscator: {
enabled: true
},
installImports: function(o) { installImports: function(o) {
o.teavmConsole.putcharStdout = putchar; o.teavmConsole.putcharStdout = putchar;
o.teavmConsole.putcharStderr = putcharStderr; o.teavmConsole.putcharStderr = putcharStderr;

View File

@ -38,6 +38,8 @@ import org.teavm.backend.c.generate.ShorteningFileNameProvider;
import org.teavm.backend.c.generate.SimpleFileNameProvider; import org.teavm.backend.c.generate.SimpleFileNameProvider;
import org.teavm.backend.javascript.JSModuleType; import org.teavm.backend.javascript.JSModuleType;
import org.teavm.backend.javascript.JavaScriptTarget; import org.teavm.backend.javascript.JavaScriptTarget;
import org.teavm.backend.wasm.WasmDebugInfoLevel;
import org.teavm.backend.wasm.WasmDebugInfoLocation;
import org.teavm.backend.wasm.WasmGCTarget; import org.teavm.backend.wasm.WasmGCTarget;
import org.teavm.backend.wasm.WasmRuntimeType; import org.teavm.backend.wasm.WasmRuntimeType;
import org.teavm.backend.wasm.WasmTarget; import org.teavm.backend.wasm.WasmTarget;
@ -108,6 +110,8 @@ public class TeaVMTool {
private JavaScriptTarget javaScriptTarget; private JavaScriptTarget javaScriptTarget;
private WasmTarget webAssemblyTarget; private WasmTarget webAssemblyTarget;
private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1; private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1;
private WasmDebugInfoLocation wasmDebugInfoLocation = WasmDebugInfoLocation.EXTERNAL;
private WasmDebugInfoLevel wasmDebugInfoLevel = WasmDebugInfoLevel.DEOBFUSCATION;
private boolean wasmExceptionsUsed; private boolean wasmExceptionsUsed;
private CTarget cTarget; private CTarget cTarget;
private Set<File> generatedFiles = new HashSet<>(); private Set<File> generatedFiles = new HashSet<>();
@ -281,6 +285,14 @@ public class TeaVMTool {
this.wasmExceptionsUsed = wasmExceptionsUsed; this.wasmExceptionsUsed = wasmExceptionsUsed;
} }
public void setWasmDebugInfoLocation(WasmDebugInfoLocation wasmDebugInfoLocation) {
this.wasmDebugInfoLocation = wasmDebugInfoLocation;
}
public void setWasmDebugInfoLevel(WasmDebugInfoLevel wasmDebugInfoLevel) {
this.wasmDebugInfoLevel = wasmDebugInfoLevel;
}
public void setHeapDump(boolean heapDump) { public void setHeapDump(boolean heapDump) {
this.heapDump = heapDump; this.heapDump = heapDump;
} }
@ -388,6 +400,9 @@ public class TeaVMTool {
var target = new WasmGCTarget(); var target = new WasmGCTarget();
target.setObfuscated(obfuscated); target.setObfuscated(obfuscated);
target.setStrict(strict); target.setStrict(strict);
target.setDebugInfo(debugInformationGenerated);
target.setDebugInfoLevel(debugInformationGenerated ? WasmDebugInfoLevel.FULL : wasmDebugInfoLevel);
target.setDebugInfoLocation(wasmDebugInfoLocation);
return target; return target;
} }

View File

@ -18,6 +18,8 @@ package org.teavm.tooling.builder;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.teavm.backend.javascript.JSModuleType; import org.teavm.backend.javascript.JSModuleType;
import org.teavm.backend.wasm.WasmDebugInfoLevel;
import org.teavm.backend.wasm.WasmDebugInfoLocation;
import org.teavm.backend.wasm.render.WasmBinaryVersion; import org.teavm.backend.wasm.render.WasmBinaryVersion;
import org.teavm.tooling.TeaVMSourceFilePolicy; import org.teavm.tooling.TeaVMSourceFilePolicy;
import org.teavm.tooling.TeaVMTargetType; import org.teavm.tooling.TeaVMTargetType;
@ -83,6 +85,10 @@ public interface BuildStrategy {
void setWasmExceptionsUsed(boolean wasmExceptionsUsed); void setWasmExceptionsUsed(boolean wasmExceptionsUsed);
void setWasmDebugInfoLevel(WasmDebugInfoLevel wasmDebugInfoLevel);
void setWasmDebugInfoLocation(WasmDebugInfoLocation wasmDebugInfoLocation);
void setMinHeapSize(int minHeapSize); void setMinHeapSize(int minHeapSize);
void setMaxHeapSize(int maxHeapSize); void setMaxHeapSize(int maxHeapSize);

View File

@ -25,6 +25,8 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.teavm.backend.javascript.JSModuleType; import org.teavm.backend.javascript.JSModuleType;
import org.teavm.backend.wasm.WasmDebugInfoLevel;
import org.teavm.backend.wasm.WasmDebugInfoLocation;
import org.teavm.backend.wasm.render.WasmBinaryVersion; import org.teavm.backend.wasm.render.WasmBinaryVersion;
import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraph;
import org.teavm.diagnostics.ProblemProvider; import org.teavm.diagnostics.ProblemProvider;
@ -62,6 +64,8 @@ public class InProcessBuildStrategy implements BuildStrategy {
private String[] classesToPreserve = new String[0]; private String[] classesToPreserve = new String[0];
private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1; private WasmBinaryVersion wasmVersion = WasmBinaryVersion.V_0x1;
private boolean wasmExceptionsUsed; private boolean wasmExceptionsUsed;
private WasmDebugInfoLevel wasmDebugInfoLevel;
private WasmDebugInfoLocation wasmDebugInfoLocation;
private int minHeapSize = 4 * 1024 * 1024; private int minHeapSize = 4 * 1024 * 1024;
private int maxHeapSize = 128 * 1024 * 1024; private int maxHeapSize = 128 * 1024 * 1024;
private final List<SourceFileProvider> sourceFileProviders = new ArrayList<>(); private final List<SourceFileProvider> sourceFileProviders = new ArrayList<>();
@ -219,6 +223,16 @@ public class InProcessBuildStrategy implements BuildStrategy {
this.wasmExceptionsUsed = wasmExceptionsUsed; this.wasmExceptionsUsed = wasmExceptionsUsed;
} }
@Override
public void setWasmDebugInfoLevel(WasmDebugInfoLevel wasmDebugInfoLevel) {
this.wasmDebugInfoLevel = wasmDebugInfoLevel;
}
@Override
public void setWasmDebugInfoLocation(WasmDebugInfoLocation wasmDebugInfoLocation) {
this.wasmDebugInfoLocation = wasmDebugInfoLocation;
}
@Override @Override
public void setMinHeapSize(int minHeapSize) { public void setMinHeapSize(int minHeapSize) {
this.minHeapSize = minHeapSize; this.minHeapSize = minHeapSize;
@ -273,6 +287,8 @@ public class InProcessBuildStrategy implements BuildStrategy {
tool.setCacheDirectory(cacheDirectory != null ? new File(cacheDirectory) : null); tool.setCacheDirectory(cacheDirectory != null ? new File(cacheDirectory) : null);
tool.setWasmVersion(wasmVersion); tool.setWasmVersion(wasmVersion);
tool.setWasmExceptionsUsed(wasmExceptionsUsed); tool.setWasmExceptionsUsed(wasmExceptionsUsed);
tool.setWasmDebugInfoLevel(wasmDebugInfoLevel);
tool.setWasmDebugInfoLocation(wasmDebugInfoLocation);
tool.setMinHeapSize(minHeapSize); tool.setMinHeapSize(minHeapSize);
tool.setMaxHeapSize(maxHeapSize); tool.setMaxHeapSize(maxHeapSize);
tool.setHeapDump(heapDump); tool.setHeapDump(heapDump);

View File

@ -20,6 +20,8 @@ import java.rmi.server.UnicastRemoteObject;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.teavm.backend.javascript.JSModuleType; import org.teavm.backend.javascript.JSModuleType;
import org.teavm.backend.wasm.WasmDebugInfoLevel;
import org.teavm.backend.wasm.WasmDebugInfoLocation;
import org.teavm.backend.wasm.render.WasmBinaryVersion; import org.teavm.backend.wasm.render.WasmBinaryVersion;
import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.CallGraph;
import org.teavm.diagnostics.Problem; import org.teavm.diagnostics.Problem;
@ -192,6 +194,16 @@ public class RemoteBuildStrategy implements BuildStrategy {
request.wasmExceptionsUsed = wasmExceptionsUsed; request.wasmExceptionsUsed = wasmExceptionsUsed;
} }
@Override
public void setWasmDebugInfoLevel(WasmDebugInfoLevel wasmDebugInfoLevel) {
request.wasmDebugInfoLevel = wasmDebugInfoLevel;
}
@Override
public void setWasmDebugInfoLocation(WasmDebugInfoLocation wasmDebugInfoLocation) {
request.wasmDebugInfoLocation = wasmDebugInfoLocation;
}
@Override @Override
public void setMinHeapSize(int minHeapSize) { public void setMinHeapSize(int minHeapSize) {
request.minHeapSize = minHeapSize; request.minHeapSize = minHeapSize;

View File

@ -162,6 +162,8 @@ public class BuildDaemon extends UnicastRemoteObject implements RemoteBuildServi
tool.setStrict(request.strict); tool.setStrict(request.strict);
tool.setWasmVersion(request.wasmVersion); tool.setWasmVersion(request.wasmVersion);
tool.setWasmExceptionsUsed(request.wasmExceptionsUsed); tool.setWasmExceptionsUsed(request.wasmExceptionsUsed);
tool.setWasmDebugInfoLocation(request.wasmDebugInfoLocation);
tool.setWasmDebugInfoLevel(request.wasmDebugInfoLevel);
tool.setMinHeapSize(request.minHeapSize); tool.setMinHeapSize(request.minHeapSize);
tool.setMaxHeapSize(request.maxHeapSize); tool.setMaxHeapSize(request.maxHeapSize);
tool.setHeapDump(request.heapDump); tool.setHeapDump(request.heapDump);

View File

@ -20,6 +20,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.teavm.backend.javascript.JSModuleType; import org.teavm.backend.javascript.JSModuleType;
import org.teavm.backend.wasm.WasmDebugInfoLevel;
import org.teavm.backend.wasm.WasmDebugInfoLocation;
import org.teavm.backend.wasm.render.WasmBinaryVersion; import org.teavm.backend.wasm.render.WasmBinaryVersion;
import org.teavm.tooling.TeaVMSourceFilePolicy; import org.teavm.tooling.TeaVMSourceFilePolicy;
import org.teavm.tooling.TeaVMTargetType; import org.teavm.tooling.TeaVMTargetType;
@ -50,6 +52,8 @@ public class RemoteBuildRequest implements Serializable {
public boolean fastDependencyAnalysis; public boolean fastDependencyAnalysis;
public WasmBinaryVersion wasmVersion; public WasmBinaryVersion wasmVersion;
public boolean wasmExceptionsUsed; public boolean wasmExceptionsUsed;
public WasmDebugInfoLocation wasmDebugInfoLocation;
public WasmDebugInfoLevel wasmDebugInfoLevel;
public int minHeapSize; public int minHeapSize;
public int maxHeapSize; public int maxHeapSize;
public boolean heapDump; public boolean heapDump;

View File

@ -43,6 +43,7 @@ public final class Compiler {
tool.setTargetFileName(args[2]); tool.setTargetFileName(args[2]);
tool.setObfuscated(true); tool.setObfuscated(true);
tool.setOptimizationLevel(TeaVMOptimizationLevel.ADVANCED); tool.setOptimizationLevel(TeaVMOptimizationLevel.ADVANCED);
tool.setStrict(false);
tool.generate(); tool.generate();
TeaVMProblemRenderer.describeProblems(tool.getDependencyInfo().getCallGraph(), tool.getProblemProvider(), log); TeaVMProblemRenderer.describeProblems(tool.getDependencyInfo().getCallGraph(), tool.getProblemProvider(), log);

View File

@ -15,6 +15,8 @@
*/ */
package org.teavm.tooling.deobfuscate.wasmgc; package org.teavm.tooling.deobfuscate.wasmgc;
import java.util.Arrays;
import org.teavm.backend.wasm.debug.ExternalDebugFile;
import org.teavm.backend.wasm.debug.parser.LinesDeobfuscationParser; import org.teavm.backend.wasm.debug.parser.LinesDeobfuscationParser;
import org.teavm.jso.JSBody; import org.teavm.jso.JSBody;
import org.teavm.jso.JSExport; import org.teavm.jso.JSExport;
@ -42,9 +44,29 @@ public final class DeobfuscatorFactory {
} }
return bytes; return bytes;
}); });
return new Deobfuscator(parser.getLineInfo()); var lineInfo = parser.getLineInfo();
return lineInfo != null ? new Deobfuscator(parser.getLineInfo()) : null;
} }
@JSBody(params = { "module", "name"}, script = "return WebAssembly.Module.customSections(module, name);") @JSBody(params = { "module", "name"}, script = "return WebAssembly.Module.customSections(module, name);")
private static native JSArrayReader<ArrayBuffer> getSection(JSObject module, String name); private static native JSArrayReader<ArrayBuffer> getSection(JSObject module, String name);
@JSExport
public static Deobfuscator createFromExternalFile(byte[] data) {
var parser = new LinesDeobfuscationParser();
var success = ExternalDebugFile.read(data, sectionName -> {
if (!parser.canHandleSection(sectionName)) {
return null;
}
return (bytes, start, end) -> parser.applySection(sectionName, Arrays.copyOfRange(bytes, start, end));
});
if (!success) {
return null;
}
var lineInfo = parser.getLineInfo();
if (lineInfo == null) {
return null;
}
return new Deobfuscator(lineInfo);
}
} }

View File

@ -31,6 +31,8 @@ import org.teavm.gradle.api.TeaVMJSConfiguration;
import org.teavm.gradle.api.TeaVMWasiConfiguration; import org.teavm.gradle.api.TeaVMWasiConfiguration;
import org.teavm.gradle.api.TeaVMWasmConfiguration; import org.teavm.gradle.api.TeaVMWasmConfiguration;
import org.teavm.gradle.api.TeaVMWasmGCConfiguration; import org.teavm.gradle.api.TeaVMWasmGCConfiguration;
import org.teavm.gradle.api.WasmDebugInfoLevel;
import org.teavm.gradle.api.WasmDebugInfoLocation;
class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtension { class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtension {
private TeaVMJSConfiguration js; private TeaVMJSConfiguration js;
@ -111,6 +113,12 @@ class TeaVMExtensionImpl extends TeaVMBaseExtensionImpl implements TeaVMExtensio
wasmGC.getCopyRuntime().convention(property("wasm-gc.copyRuntime").map(Boolean::parseBoolean).orElse(true)); wasmGC.getCopyRuntime().convention(property("wasm-gc.copyRuntime").map(Boolean::parseBoolean).orElse(true));
wasmGC.getObfuscated().convention(property("wasm-gc.obfuscated").map(Boolean::parseBoolean).orElse(true)); wasmGC.getObfuscated().convention(property("wasm-gc.obfuscated").map(Boolean::parseBoolean).orElse(true));
wasmGC.getDisassembly().convention(property("wasm-gc.disassembly").map(Boolean::parseBoolean).orElse(false)); wasmGC.getDisassembly().convention(property("wasm-gc.disassembly").map(Boolean::parseBoolean).orElse(false));
wasmGC.getDebugInformation().convention(property("wasm-gc.debugInformation").map(Boolean::parseBoolean)
.orElse(false));
wasmGC.getDebugInfoLocation().convention(property("wasm-gc.debugInformation.location")
.map(v -> WasmDebugInfoLocation.valueOf(v.toUpperCase())).orElse(WasmDebugInfoLocation.EXTERNAL));
wasmGC.getDebugInfoLevel().convention(property("wasm-gc.debugInformation.level")
.map(v -> WasmDebugInfoLevel.valueOf(v.toUpperCase())).orElse(WasmDebugInfoLevel.DEOBFUSCATION));
} }
private void setupWasiDefaults() { private void setupWasiDefaults() {

View File

@ -27,4 +27,8 @@ public interface TeaVMWasmGCConfiguration extends TeaVMCommonConfiguration, TeaV
Property<Boolean> getDisassembly(); Property<Boolean> getDisassembly();
Property<String> getTargetFileName(); Property<String> getTargetFileName();
Property<WasmDebugInfoLocation> getDebugInfoLocation();
Property<WasmDebugInfoLevel> getDebugInfoLevel();
} }

View File

@ -0,0 +1,21 @@
/*
* Copyright 2024 Alexey Andreev.
*
* 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 org.teavm.gradle.api;
public enum WasmDebugInfoLevel {
DEOBFUSCATION,
FULL
}

View File

@ -0,0 +1,21 @@
/*
* Copyright 2024 Alexey Andreev.
*
* 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 org.teavm.gradle.api;
public enum WasmDebugInfoLocation {
EMBEDDED,
EXTERNAL
}

View File

@ -17,6 +17,8 @@ package org.teavm.gradle.tasks;
import org.gradle.api.provider.Property; import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Input;
import org.teavm.gradle.api.WasmDebugInfoLevel;
import org.teavm.gradle.api.WasmDebugInfoLocation;
import org.teavm.tooling.TeaVMTargetType; import org.teavm.tooling.TeaVMTargetType;
import org.teavm.tooling.builder.BuildStrategy; import org.teavm.tooling.builder.BuildStrategy;
@ -24,6 +26,9 @@ public abstract class GenerateWasmGCTask extends TeaVMTask {
public GenerateWasmGCTask() { public GenerateWasmGCTask() {
getStrict().convention(true); getStrict().convention(true);
getObfuscated().convention(true); getObfuscated().convention(true);
getDebugInfo().convention(true);
getDebugInfoLevel().convention(WasmDebugInfoLevel.DEOBFUSCATION);
getDebugInfoLocation().convention(WasmDebugInfoLocation.EXTERNAL);
} }
@Input @Input
@ -32,10 +37,36 @@ public abstract class GenerateWasmGCTask extends TeaVMTask {
@Input @Input
public abstract Property<Boolean> getObfuscated(); public abstract Property<Boolean> getObfuscated();
@Input
public abstract Property<Boolean> getDebugInfo();
@Input
public abstract Property<WasmDebugInfoLevel> getDebugInfoLevel();
@Input
public abstract Property<WasmDebugInfoLocation> getDebugInfoLocation();
@Override @Override
protected void setupBuilder(BuildStrategy builder) { protected void setupBuilder(BuildStrategy builder) {
builder.setStrict(getStrict().get()); builder.setStrict(getStrict().get());
builder.setObfuscated(getObfuscated().get()); builder.setObfuscated(getObfuscated().get());
builder.setDebugInformationGenerated(getDebugInfo().get());
switch (getDebugInfoLevel().get()) {
case FULL:
builder.setWasmDebugInfoLevel(org.teavm.backend.wasm.WasmDebugInfoLevel.FULL);
break;
case DEOBFUSCATION:
builder.setWasmDebugInfoLevel(org.teavm.backend.wasm.WasmDebugInfoLevel.DEOBFUSCATION);
break;
}
switch (getDebugInfoLocation().get()) {
case EMBEDDED:
builder.setWasmDebugInfoLocation(org.teavm.backend.wasm.WasmDebugInfoLocation.EMBEDDED);
break;
case EXTERNAL:
builder.setWasmDebugInfoLocation(org.teavm.backend.wasm.WasmDebugInfoLocation.EXTERNAL);
break;
}
builder.setTargetType(TeaVMTargetType.WEBASSEMBLY_GC); builder.setTargetType(TeaVMTargetType.WEBASSEMBLY_GC);
} }
} }

View File

@ -71,8 +71,9 @@ class WebAssemblyGCPlatformSupport extends TestPlatformSupport<WasmGCTarget> {
var target = new WasmGCTarget(); var target = new WasmGCTarget();
target.setObfuscated(false); target.setObfuscated(false);
target.setStrict(true); target.setStrict(true);
target.setDebugLevel(WasmDebugInfoLevel.DEOBFUSCATION); target.setDebugInfo(true);
target.setDebugLocation(WasmDebugInfoLocation.EMBEDDED); target.setDebugInfoLevel(WasmDebugInfoLevel.DEOBFUSCATION);
target.setDebugInfoLocation(WasmDebugInfoLocation.EMBEDDED);
var sourceDirs = System.getProperty(SOURCE_DIRS); var sourceDirs = System.getProperty(SOURCE_DIRS);
if (sourceDirs != null) { if (sourceDirs != null) {
var dirs = new ArrayList<File>(); var dirs = new ArrayList<File>();

View File

@ -25,7 +25,9 @@
<script type="text/javascript"> <script type="text/javascript">
let instance; let instance;
TeaVM.wasmGC.load("${SCRIPT}", { TeaVM.wasmGC.load("${SCRIPT}", {
attachStackDeobfuscator: true, stackDeobfuscator: {
enabled: true
},
installImports(o) { installImports(o) {
o.teavmTest = { o.teavmTest = {
success() { success() {