diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 310544c9451..8dbce498357 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -94,6 +94,7 @@ int main(int argc, const char* argv[]) { std::string outputSourceMapFilename; std::string outputSourceMapUrl; bool emitExnref = false; + bool needCodeLocations = false; const std::string WasmOptOption = "wasm-opt options"; @@ -280,7 +281,21 @@ For more on how to optimize effectively, see "post-translation optimizations.", WasmOptOption, Options::Arguments::Zero, - [&emitExnref](Options*, const std::string&) { emitExnref = true; }); + [&emitExnref](Options*, const std::string&) { emitExnref = true; }) + .add("--print-binary-offsets", + "-pbo", + "Print wat text annotated with binary offsets", + WasmOptOption, + Options::Arguments::Zero, + [&](Options*, const std::string&) { + // Track code locations, so we can print them. + needCodeLocations = true; + // Enable debugInfo, so that we print code locations (which are part + // of debugInfo). + options.passOptions.debugInfo = true; + // Run the print pass, to do the printing. + options.passes.push_back("print"); + }); options.parse(argc, argv); Module wasm; @@ -315,6 +330,7 @@ For more on how to optimize effectively, see reader.setDWARF(options.passOptions.debugInfo && !willRemoveDebugInfo(options.passes)); reader.setProfile(options.profile); + reader.setNeedCodeLocations(needCodeLocations); try { reader.read(inputFile, wasm, inputSourceMapFilename); } catch (ParseException& p) { @@ -335,6 +351,15 @@ For more on how to optimize effectively, see "request for silly amounts of memory)"; } + if (needCodeLocations) { + if (auto codeSectionLocation = reader.getCodeSectionLocation()) { + std::cout << ";; Code section offset: 0x" << std::hex + << *codeSectionLocation << std::dec << '\n' + << ";; (binary offsets in VM stack traces include this;" + << " add it to the offsets below)\n"; + } + } + options.applyOptionsAfterParse(wasm); if (options.passOptions.validate) { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 5a1f618da3d..b781ee65bdb 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1572,6 +1572,8 @@ class WasmBinaryReader { void setSkipFunctionBodies(bool skipFunctionBodies_) { skipFunctionBodies = skipFunctionBodies_; } + void setNeedCodeLocations(bool value) { needCodeLocations = value; } + void read(); void readCustomSection(size_t payloadLen); @@ -1746,6 +1748,8 @@ class WasmBinaryReader { // Allow users to query the target features section features after parsing. FeatureSet getFeaturesSectionFeatures() { return featuresSectionFeatures; } + size_t getCodeSectionLocation() { return codeSectionLocation; } + private: // In certain modes we need to note the locations of expressions, to match // them against sections like DWARF or custom annotations. As this incurs diff --git a/src/wasm-io.h b/src/wasm-io.h index 01d9462a5ca..c863536888a 100644 --- a/src/wasm-io.h +++ b/src/wasm-io.h @@ -53,6 +53,10 @@ class ModuleReader : public ModuleIOBase { skipFunctionBodies = skipFunctionBodies_; } + void setNeedCodeLocations(bool needCodeLocations_) { + needCodeLocations = needCodeLocations_; + } + // read text void readText(std::string filename, Module& wasm); // read binary @@ -68,15 +72,22 @@ class ModuleReader : public ModuleIOBase { FeatureSet getFeaturesSectionFeatures() { return featuresSectionFeatures; } + // Return the offset of the code section, or nothing if we did not read a + // binary. + std::optional getCodeSectionLocation() { return codeSectionLocation; } + private: bool DWARF = false; IRProfile profile = IRProfile::Normal; bool skipFunctionBodies = false; + bool needCodeLocations = false; FeatureSet featuresSectionFeatures = FeatureSet::MVP; + std::optional codeSectionLocation; + void readStdin(Module& wasm, std::string sourceMapFilename); void readBinaryData(std::vector& input, diff --git a/src/wasm/wasm-io.cpp b/src/wasm/wasm-io.cpp index 77fc57e57b7..c4ad030e0d3 100644 --- a/src/wasm/wasm-io.cpp +++ b/src/wasm/wasm-io.cpp @@ -64,10 +64,12 @@ void ModuleReader::readBinaryData(std::vector& input, parser.setDebugInfo(debugInfo); parser.setDWARF(DWARF); parser.setSkipFunctionBodies(skipFunctionBodies); + parser.setNeedCodeLocations(needCodeLocations); parser.read(); if (wasm.hasFeaturesSection) { featuresSectionFeatures = parser.getFeaturesSectionFeatures(); } + codeSectionLocation = parser.getCodeSectionLocation(); } void ModuleReader::readBinary(std::string filename, diff --git a/test/lit/debug/print-binary-offsets.wat b/test/lit/debug/print-binary-offsets.wat new file mode 100644 index 00000000000..531e7cf5b6f --- /dev/null +++ b/test/lit/debug/print-binary-offsets.wat @@ -0,0 +1,20 @@ +;; RUN: wasm-opt %s -o %t.wasm +;; RUN: wasm-opt %t.wasm --print-binary-offsets | filecheck %s + +;; The command makes us print binary offsets in wat text. Note that it works +;; even without -g for the names section. + +(module + (func $test + (call $test) + ) +) + +;; CHECK: ;; Code section offset: 0x14 +;; CHECK-NEXT: ;; (binary offsets in VM stack traces include this; add it to the offsets below) + +;; CHECK: (func $0 +;; CHECK-NEXT: ;; code offset: 0x3 +;; CHECK-NEXT: (call $0) +;; CHECK-NEXT: ) +