Skip to content

Commit cfe53c0

Browse files
committed
Export wasm source map when debug information is enabled
We use binaryen's linker to produce a wasm file (via s2wasm). The wasm writer has capabilities to export source maps. The produced source map contains references to the original file, that might require additional source map file processing to include / package original files with it.
1 parent a0dcecf commit cfe53c0

File tree

3 files changed

+68
-6
lines changed

3 files changed

+68
-6
lines changed

src/librustc_binaryen/BinaryenWrapper.cpp

+31-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <stdint.h>
1616
#include <string>
17+
#include <sstream>
1718
#include <stdlib.h>
1819

1920
#include "s2wasm.h"
@@ -24,6 +25,7 @@ using namespace wasm;
2425

2526
struct BinaryenRustModule {
2627
BufferWithRandomAccess buffer;
28+
std::string sourceMapJSON;
2729
};
2830

2931
struct BinaryenRustModuleOptions {
@@ -36,6 +38,7 @@ struct BinaryenRustModuleOptions {
3638
bool ignoreUnknownSymbols;
3739
bool debugInfo;
3840
std::string startFunction;
41+
std::string sourceMapUrl;
3942

4043
BinaryenRustModuleOptions() :
4144
globalBase(0),
@@ -46,7 +49,8 @@ struct BinaryenRustModuleOptions {
4649
importMemory(false),
4750
ignoreUnknownSymbols(false),
4851
debugInfo(false),
49-
startFunction("")
52+
startFunction(""),
53+
sourceMapUrl("")
5054
{}
5155

5256
};
@@ -73,6 +77,12 @@ BinaryenRustModuleOptionsSetStart(BinaryenRustModuleOptions *options,
7377
options->startFunction = start;
7478
}
7579

80+
extern "C" void
81+
BinaryenRustModuleOptionsSetSourceMapUrl(BinaryenRustModuleOptions *options,
82+
char *sourceMapUrl) {
83+
options->sourceMapUrl = sourceMapUrl;
84+
}
85+
7686
extern "C" void
7787
BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options,
7888
uint64_t stack) {
@@ -106,12 +116,20 @@ BinaryenRustModuleCreate(const BinaryenRustModuleOptions *options,
106116
{
107117
WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug);
108118
writer.setNamesSection(options->debugInfo);
109-
// FIXME: support source maps?
110-
// writer.setSourceMap(sourceMapStream.get(), sourceMapUrl);
119+
120+
std::unique_ptr<std::ostringstream> sourceMapStream = nullptr;
121+
{
122+
sourceMapStream = make_unique<std::ostringstream>();
123+
writer.setSourceMap(sourceMapStream.get(), options->sourceMapUrl);
124+
}
111125

112126
// FIXME: support symbol maps?
113127
// writer.setSymbolMap(symbolMap);
114128
writer.write();
129+
130+
if (sourceMapStream) {
131+
ret->sourceMapJSON = sourceMapStream->str();
132+
}
115133
}
116134
return ret.release();
117135
}
@@ -126,6 +144,16 @@ BinaryenRustModuleLen(const BinaryenRustModule *M) {
126144
return M->buffer.size();
127145
}
128146

147+
extern "C" const char*
148+
BinaryenRustModuleSourceMapPtr(const BinaryenRustModule *M) {
149+
return M->sourceMapJSON.data();
150+
}
151+
152+
extern "C" size_t
153+
BinaryenRustModuleSourceMapLen(const BinaryenRustModule *M) {
154+
return M->sourceMapJSON.length();
155+
}
156+
129157
extern "C" void
130158
BinaryenRustModuleFree(BinaryenRustModule *M) {
131159
delete M;

src/librustc_binaryen/lib.rs

+22
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ impl Module {
5151
slice::from_raw_parts(ptr, len)
5252
}
5353
}
54+
55+
/// Returns the data of the source map JSON.
56+
pub fn source_map(&self) -> &[u8] {
57+
unsafe {
58+
let ptr = BinaryenRustModuleSourceMapPtr(self.ptr);
59+
let len = BinaryenRustModuleSourceMapLen(self.ptr);
60+
slice::from_raw_parts(ptr, len)
61+
}
62+
}
5463
}
5564

5665
impl Drop for Module {
@@ -94,6 +103,15 @@ impl ModuleOptions {
94103
self
95104
}
96105

106+
/// Configures a `sourceMappingURL` custom section value for the module.
107+
pub fn source_map_url(&mut self, url: &str) -> &mut Self {
108+
let url = CString::new(url).unwrap();
109+
unsafe {
110+
BinaryenRustModuleOptionsSetSourceMapUrl(self.ptr, url.as_ptr());
111+
}
112+
self
113+
}
114+
97115
/// Configures how much stack is initially allocated for the module. 1MB is
98116
/// probably good enough for now.
99117
pub fn stack(&mut self, amt: u64) -> &mut Self {
@@ -130,6 +148,8 @@ extern {
130148
-> *mut BinaryenRustModule;
131149
fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8;
132150
fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize;
151+
fn BinaryenRustModuleSourceMapPtr(module: *const BinaryenRustModule) -> *const u8;
152+
fn BinaryenRustModuleSourceMapLen(module: *const BinaryenRustModule) -> usize;
133153
fn BinaryenRustModuleFree(module: *mut BinaryenRustModule);
134154

135155
fn BinaryenRustModuleOptionsCreate()
@@ -138,6 +158,8 @@ extern {
138158
debuginfo: bool);
139159
fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions,
140160
start: *const libc::c_char);
161+
fn BinaryenRustModuleOptionsSetSourceMapUrl(module: *mut BinaryenRustModuleOptions,
162+
sourceMapUrl: *const libc::c_char);
141163
fn BinaryenRustModuleOptionsSetStackAllocation(
142164
module: *mut BinaryenRustModuleOptions,
143165
stack: u64,

src/librustc_trans/back/write.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,10 @@ unsafe fn codegen(cgcx: &CodegenContext,
748748

749749
if asm2wasm && config.emit_obj {
750750
let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
751-
binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out);
751+
let suffix = ".wasm.map"; // FIXME use target suffix
752+
let map = cgcx.output_filenames.path(OutputType::Exe)
753+
.with_extension(&suffix[1..]);
754+
binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out, &map);
752755
timeline.record("binaryen");
753756

754757
if !config.emit_asm {
@@ -795,7 +798,8 @@ unsafe fn codegen(cgcx: &CodegenContext,
795798
fn binaryen_assemble(cgcx: &CodegenContext,
796799
handler: &Handler,
797800
assembly: &Path,
798-
object: &Path) {
801+
object: &Path,
802+
map: &Path) {
799803
use rustc_binaryen::{Module, ModuleOptions};
800804

801805
let input = fs::read(&assembly).and_then(|contents| {
@@ -804,6 +808,8 @@ fn binaryen_assemble(cgcx: &CodegenContext,
804808
let mut options = ModuleOptions::new();
805809
if cgcx.debuginfo != config::NoDebugInfo {
806810
options.debuginfo(true);
811+
let map_file_name = map.file_name().unwrap();
812+
options.source_map_url(map_file_name.to_str().unwrap());
807813
}
808814
if cgcx.crate_types.contains(&config::CrateTypeExecutable) {
809815
options.start("main");
@@ -815,7 +821,13 @@ fn binaryen_assemble(cgcx: &CodegenContext,
815821
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
816822
});
817823
let err = assembled.and_then(|binary| {
818-
fs::write(&object, binary.data())
824+
fs::write(&object, binary.data()).and_then(|()| {
825+
if cgcx.debuginfo != config::NoDebugInfo {
826+
fs::write(map, binary.source_map())
827+
} else {
828+
Ok(())
829+
}
830+
})
819831
});
820832
if let Err(e) = err {
821833
handler.err(&format!("failed to run binaryen assembler: {}", e));

0 commit comments

Comments
 (0)