]> git.lizzy.rs Git - rust.git/commitdiff
Export wasm source map when debug information is enabled
authorYury Delendik <ydelendik@mozilla.com>
Tue, 30 Jan 2018 02:13:29 +0000 (20:13 -0600)
committerYury Delendik <ydelendik@mozilla.com>
Wed, 31 Jan 2018 02:10:58 +0000 (20:10 -0600)
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.

src/librustc_binaryen/BinaryenWrapper.cpp
src/librustc_binaryen/lib.rs
src/librustc_trans/back/write.rs

index d1095a7819d4aa3729486c5f6d3ed639dfa0ca6c..55f11665f6d0ba83a157680b9ce433bfeab5f02a 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <stdint.h>
 #include <string>
+#include <sstream>
 #include <stdlib.h>
 
 #include "s2wasm.h"
@@ -24,6 +25,7 @@ using namespace wasm;
 
 struct BinaryenRustModule {
   BufferWithRandomAccess buffer;
+  std::string sourceMapJSON;
 };
 
 struct BinaryenRustModuleOptions {
@@ -36,6 +38,7 @@ struct BinaryenRustModuleOptions {
   bool ignoreUnknownSymbols;
   bool debugInfo;
   std::string startFunction;
+  std::string sourceMapUrl;
 
   BinaryenRustModuleOptions() :
     globalBase(0),
@@ -46,7 +49,8 @@ struct BinaryenRustModuleOptions {
     importMemory(false),
     ignoreUnknownSymbols(false),
     debugInfo(false),
-    startFunction("")
+    startFunction(""),
+    sourceMapUrl("")
   {}
 
 };
@@ -73,6 +77,12 @@ BinaryenRustModuleOptionsSetStart(BinaryenRustModuleOptions *options,
   options->startFunction = start;
 }
 
+extern "C" void
+BinaryenRustModuleOptionsSetSourceMapUrl(BinaryenRustModuleOptions *options,
+                                         char *sourceMapUrl) {
+  options->sourceMapUrl = sourceMapUrl;
+}
+
 extern "C" void
 BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options,
                                             uint64_t stack) {
@@ -106,12 +116,20 @@ BinaryenRustModuleCreate(const BinaryenRustModuleOptions *options,
   {
     WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug);
     writer.setNamesSection(options->debugInfo);
-    // FIXME: support source maps?
-    // writer.setSourceMap(sourceMapStream.get(), sourceMapUrl);
+
+    std::unique_ptr<std::ostringstream> sourceMapStream = nullptr;
+    {
+      sourceMapStream = make_unique<std::ostringstream>();
+      writer.setSourceMap(sourceMapStream.get(), options->sourceMapUrl);
+    }
 
     // FIXME: support symbol maps?
     // writer.setSymbolMap(symbolMap);
     writer.write();
+
+    if (sourceMapStream) {
+      ret->sourceMapJSON = sourceMapStream->str();
+    }
   }
   return ret.release();
 }
@@ -126,6 +144,16 @@ BinaryenRustModuleLen(const BinaryenRustModule *M) {
   return M->buffer.size();
 }
 
+extern "C" const char*
+BinaryenRustModuleSourceMapPtr(const BinaryenRustModule *M) {
+  return M->sourceMapJSON.data();
+}
+
+extern "C" size_t
+BinaryenRustModuleSourceMapLen(const BinaryenRustModule *M) {
+  return M->sourceMapJSON.length();
+}
+
 extern "C" void
 BinaryenRustModuleFree(BinaryenRustModule *M) {
   delete M;
index 6c7feb6a7a9d36200cb1bf65d0c3c69a730e9679..36174e11ba04a988012f7724e537dd41c0bfb339 100644 (file)
@@ -51,6 +51,15 @@ pub fn data(&self) -> &[u8] {
             slice::from_raw_parts(ptr, len)
         }
     }
+
+    /// Returns the data of the source map JSON.
+    pub fn source_map(&self) -> &[u8] {
+        unsafe {
+            let ptr = BinaryenRustModuleSourceMapPtr(self.ptr);
+            let len = BinaryenRustModuleSourceMapLen(self.ptr);
+            slice::from_raw_parts(ptr, len)
+        }
+    }
 }
 
 impl Drop for Module {
@@ -94,6 +103,15 @@ pub fn start(&mut self, func: &str) -> &mut Self {
         self
     }
 
+    /// Configures a `sourceMappingURL` custom section value for the module.
+    pub fn source_map_url(&mut self, url: &str) -> &mut Self {
+        let url = CString::new(url).unwrap();
+        unsafe {
+            BinaryenRustModuleOptionsSetSourceMapUrl(self.ptr, url.as_ptr());
+        }
+        self
+    }
+
     /// Configures how much stack is initially allocated for the module. 1MB is
     /// probably good enough for now.
     pub fn stack(&mut self, amt: u64) -> &mut Self {
@@ -130,6 +148,8 @@ fn BinaryenRustModuleCreate(opts: *const BinaryenRustModuleOptions,
         -> *mut BinaryenRustModule;
     fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8;
     fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize;
+    fn BinaryenRustModuleSourceMapPtr(module: *const BinaryenRustModule) -> *const u8;
+    fn BinaryenRustModuleSourceMapLen(module: *const BinaryenRustModule) -> usize;
     fn BinaryenRustModuleFree(module: *mut BinaryenRustModule);
 
     fn BinaryenRustModuleOptionsCreate()
@@ -138,6 +158,8 @@ fn BinaryenRustModuleOptionsSetDebugInfo(module: *mut BinaryenRustModuleOptions,
                                              debuginfo: bool);
     fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions,
                                          start: *const libc::c_char);
+    fn BinaryenRustModuleOptionsSetSourceMapUrl(module: *mut BinaryenRustModuleOptions,
+                                                sourceMapUrl: *const libc::c_char);
     fn BinaryenRustModuleOptionsSetStackAllocation(
         module: *mut BinaryenRustModuleOptions,
         stack: u64,
index a013af7a4600ef342218823abbbea1d890e26de1..7a194a37c9c5500dc2ee820510ad85c0bf2599fa 100644 (file)
@@ -748,7 +748,10 @@ extern "C" fn demangle_callback(input_ptr: *const c_char,
 
         if asm2wasm && config.emit_obj {
             let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
-            binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out);
+            let suffix = ".wasm.map"; // FIXME use target suffix
+            let map = cgcx.output_filenames.path(OutputType::Exe)
+                .with_extension(&suffix[1..]);
+            binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out, &map);
             timeline.record("binaryen");
 
             if !config.emit_asm {
@@ -795,7 +798,8 @@ extern "C" fn demangle_callback(input_ptr: *const c_char,
 fn binaryen_assemble(cgcx: &CodegenContext,
                      handler: &Handler,
                      assembly: &Path,
-                     object: &Path) {
+                     object: &Path,
+                     map: &Path) {
     use rustc_binaryen::{Module, ModuleOptions};
 
     let input = fs::read(&assembly).and_then(|contents| {
@@ -804,6 +808,8 @@ fn binaryen_assemble(cgcx: &CodegenContext,
     let mut options = ModuleOptions::new();
     if cgcx.debuginfo != config::NoDebugInfo {
         options.debuginfo(true);
+        let map_file_name = map.file_name().unwrap();
+        options.source_map_url(map_file_name.to_str().unwrap());
     }
     if cgcx.crate_types.contains(&config::CrateTypeExecutable) {
         options.start("main");
@@ -815,7 +821,13 @@ fn binaryen_assemble(cgcx: &CodegenContext,
             .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
     });
     let err = assembled.and_then(|binary| {
-        fs::write(&object, binary.data())
+        fs::write(&object, binary.data()).and_then(|()| {
+            if cgcx.debuginfo != config::NoDebugInfo {
+                fs::write(map, binary.source_map())
+            } else {
+                Ok(())
+            }
+        })
     });
     if let Err(e) = err {
         handler.err(&format!("failed to run binaryen assembler: {}", e));