From a5810aac8f3a0605881c1ae33ba4e8102d2ef269 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 13 Jan 2026 13:21:42 -0800 Subject: [PATCH 1/7] Add wasm-opt flag to print 0x1234 binary offsets in wat output --- src/tools/wasm-opt.cpp | 16 +++++++++++++++- src/wasm-binary.h | 2 ++ src/wasm-io.h | 5 +++++ src/wasm/wasm-binary.cpp | 1 + src/wasm/wasm-io.cpp | 1 + 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 310544c9451..d05b9d41380 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,19 @@ 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("--show-binary-offsets", + "-sbo", + "Show binary offsets when printing wat text", + 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; + }); options.parse(argc, argv); Module wasm; @@ -315,6 +328,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) { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 5a1f618da3d..9b596b94c07 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); diff --git a/src/wasm-io.h b/src/wasm-io.h index 01d9462a5ca..51fc92ce583 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 @@ -74,6 +78,7 @@ class ModuleReader : public ModuleIOBase { IRProfile profile = IRProfile::Normal; bool skipFunctionBodies = false; + bool needCodeLocations = false; FeatureSet featuresSectionFeatures = FeatureSet::MVP; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 96fd205f908..0afb6947fd1 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2023,6 +2023,7 @@ void WasmBinaryReader::preScan() { getInt32(); // version bool foundDWARF = false; +//needCodeLocations = true; while (more()) { uint8_t sectionCode = getInt8(); diff --git a/src/wasm/wasm-io.cpp b/src/wasm/wasm-io.cpp index 77fc57e57b7..f83b56614a6 100644 --- a/src/wasm/wasm-io.cpp +++ b/src/wasm/wasm-io.cpp @@ -64,6 +64,7 @@ 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(); From 097d8b2a703b31ee4ce02820b1ccfdb8a2dc6032 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 13 Jan 2026 15:46:24 -0800 Subject: [PATCH 2/7] lean --- src/wasm/wasm-binary.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 0afb6947fd1..96fd205f908 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2023,7 +2023,6 @@ void WasmBinaryReader::preScan() { getInt32(); // version bool foundDWARF = false; -//needCodeLocations = true; while (more()) { uint8_t sectionCode = getInt8(); From fb5b7ba152b575188d7e56371c8ade70b89ca816 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 13 Jan 2026 15:56:01 -0800 Subject: [PATCH 3/7] test --- test/lit/debug/show-binary-offsets.wat | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 test/lit/debug/show-binary-offsets.wat diff --git a/test/lit/debug/show-binary-offsets.wat b/test/lit/debug/show-binary-offsets.wat new file mode 100644 index 00000000000..acb710dae23 --- /dev/null +++ b/test/lit/debug/show-binary-offsets.wat @@ -0,0 +1,28 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. + +;; RUN: wasm-opt %s -o %t.wasm +;; RUN: wasm-opt %t.wasm --show-binary-offsets --print | filecheck %s + +;; The -sbo flag makes us print binary offsets in wat text. Note that this works +;; even without -g for the names section (this is the reason for the name $0 +;; below - it matches the name from the binary, so auto-updating this test +;; works properly). + +(module + ;; CHECK: (func $0 + ;; CHECK-NEXT: ;; code offset: 0x5 + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: ;; code offset: 0x3 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ;; code offset: 0x6 + ;; CHECK-NEXT: (call $0) + ;; CHECK-NEXT: ) + (func $0 + (drop + (i32.const 0) + ) + (call $0) + ) +) + From bec8a04659545d303588a1c51a8785b6ee197c83 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 13 Jan 2026 16:43:55 -0800 Subject: [PATCH 4/7] simpl? --- src/tools/wasm-opt.cpp | 2 ++ test/lit/debug/show-binary-offsets.wat | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index d05b9d41380..05f4083f1ac 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -293,6 +293,8 @@ For more on how to optimize effectively, see // 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); diff --git a/test/lit/debug/show-binary-offsets.wat b/test/lit/debug/show-binary-offsets.wat index acb710dae23..e6e1b8cb912 100644 --- a/test/lit/debug/show-binary-offsets.wat +++ b/test/lit/debug/show-binary-offsets.wat @@ -1,7 +1,7 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. ;; RUN: wasm-opt %s -o %t.wasm -;; RUN: wasm-opt %t.wasm --show-binary-offsets --print | filecheck %s +;; RUN: wasm-opt %t.wasm --show-binary-offsets | filecheck %s ;; The -sbo flag makes us print binary offsets in wat text. Note that this works ;; even without -g for the names section (this is the reason for the name $0 From a96038726cc8a832aeaab818d2d393c3a278dbcc Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 13 Jan 2026 16:48:45 -0800 Subject: [PATCH 5/7] rename --- src/tools/wasm-opt.cpp | 6 +++--- .../{show-binary-offsets.wat => print-binary-offsets.wat} | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename test/lit/debug/{show-binary-offsets.wat => print-binary-offsets.wat} (81%) diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 05f4083f1ac..029b1e70d04 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -282,9 +282,9 @@ For more on how to optimize effectively, see WasmOptOption, Options::Arguments::Zero, [&emitExnref](Options*, const std::string&) { emitExnref = true; }) - .add("--show-binary-offsets", - "-sbo", - "Show binary offsets when printing wat text", + .add("--print-binary-offsets", + "-pbo", + "Print wat text annotated with binary offsets", WasmOptOption, Options::Arguments::Zero, [&](Options*, const std::string&) { diff --git a/test/lit/debug/show-binary-offsets.wat b/test/lit/debug/print-binary-offsets.wat similarity index 81% rename from test/lit/debug/show-binary-offsets.wat rename to test/lit/debug/print-binary-offsets.wat index e6e1b8cb912..c03619d77ac 100644 --- a/test/lit/debug/show-binary-offsets.wat +++ b/test/lit/debug/print-binary-offsets.wat @@ -1,9 +1,9 @@ ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. ;; RUN: wasm-opt %s -o %t.wasm -;; RUN: wasm-opt %t.wasm --show-binary-offsets | filecheck %s +;; RUN: wasm-opt %t.wasm --print-binary-offsets | filecheck %s -;; The -sbo flag makes us print binary offsets in wat text. Note that this works +;; The command makes us print binary offsets in wat text. Note that this works ;; even without -g for the names section (this is the reason for the name $0 ;; below - it matches the name from the binary, so auto-updating this test ;; works properly). From f4f38f2049782028304915405f366c2d39f62ede Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 14 Jan 2026 10:50:25 -0800 Subject: [PATCH 6/7] fix --- src/tools/wasm-opt.cpp | 9 +++++++++ src/wasm-binary.h | 2 ++ src/wasm-io.h | 6 ++++++ src/wasm/wasm-io.cpp | 1 + 4 files changed, 18 insertions(+) diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 029b1e70d04..8dbce498357 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -351,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 9b596b94c07..b781ee65bdb 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1748,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 51fc92ce583..c863536888a 100644 --- a/src/wasm-io.h +++ b/src/wasm-io.h @@ -72,6 +72,10 @@ 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; @@ -82,6 +86,8 @@ class ModuleReader : public ModuleIOBase { 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 f83b56614a6..c4ad030e0d3 100644 --- a/src/wasm/wasm-io.cpp +++ b/src/wasm/wasm-io.cpp @@ -69,6 +69,7 @@ void ModuleReader::readBinaryData(std::vector& input, if (wasm.hasFeaturesSection) { featuresSectionFeatures = parser.getFeaturesSectionFeatures(); } + codeSectionLocation = parser.getCodeSectionLocation(); } void ModuleReader::readBinary(std::string filename, From a33dcac3d50d761eab913b69de44347c87fd63cf Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 14 Jan 2026 11:16:15 -0800 Subject: [PATCH 7/7] test --- test/lit/debug/print-binary-offsets.wat | 32 ++++++++++--------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/test/lit/debug/print-binary-offsets.wat b/test/lit/debug/print-binary-offsets.wat index c03619d77ac..531e7cf5b6f 100644 --- a/test/lit/debug/print-binary-offsets.wat +++ b/test/lit/debug/print-binary-offsets.wat @@ -1,28 +1,20 @@ -;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. - ;; 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 this works -;; even without -g for the names section (this is the reason for the name $0 -;; below - it matches the name from the binary, so auto-updating this test -;; works properly). +;; The command makes us print binary offsets in wat text. Note that it works +;; even without -g for the names section. (module - ;; CHECK: (func $0 - ;; CHECK-NEXT: ;; code offset: 0x5 - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: ;; code offset: 0x3 - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ;; code offset: 0x6 - ;; CHECK-NEXT: (call $0) - ;; CHECK-NEXT: ) - (func $0 - (drop - (i32.const 0) - ) - (call $0) + (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: ) +