about summary refs log tree commit diff
diff options
context:
space:
mode:
authorYury Delendik <ydelendik@mozilla.com>2018-01-29 20:13:29 -0600
committerYury Delendik <ydelendik@mozilla.com>2018-01-30 20:10:58 -0600
commitcfe53c066646857a19046ebaf0cdc410c3d9f034 (patch)
treec2a4b883ac1861e17a244fe155e6501f9bab6f60
parenta0dcecff90c45ad5d4eb60859e22bb3f1b03842a (diff)
downloadrust-cfe53c066646857a19046ebaf0cdc410c3d9f034.tar.gz
rust-cfe53c066646857a19046ebaf0cdc410c3d9f034.zip
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.
-rw-r--r--src/librustc_binaryen/BinaryenWrapper.cpp34
-rw-r--r--src/librustc_binaryen/lib.rs22
-rw-r--r--src/librustc_trans/back/write.rs18
3 files changed, 68 insertions, 6 deletions
diff --git a/src/librustc_binaryen/BinaryenWrapper.cpp b/src/librustc_binaryen/BinaryenWrapper.cpp
index d1095a7819d..55f11665f6d 100644
--- a/src/librustc_binaryen/BinaryenWrapper.cpp
+++ b/src/librustc_binaryen/BinaryenWrapper.cpp
@@ -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("")
   {}
 
 };
@@ -74,6 +78,12 @@ BinaryenRustModuleOptionsSetStart(BinaryenRustModuleOptions *options,
 }
 
 extern "C" void
+BinaryenRustModuleOptionsSetSourceMapUrl(BinaryenRustModuleOptions *options,
+                                         char *sourceMapUrl) {
+  options->sourceMapUrl = sourceMapUrl;
+}
+
+extern "C" void
 BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options,
                                             uint64_t stack) {
   options->stackAllocation = 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;
diff --git a/src/librustc_binaryen/lib.rs b/src/librustc_binaryen/lib.rs
index 6c7feb6a7a9..36174e11ba0 100644
--- a/src/librustc_binaryen/lib.rs
+++ b/src/librustc_binaryen/lib.rs
@@ -51,6 +51,15 @@ impl Module {
             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 @@ impl ModuleOptions {
         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 @@ extern {
         -> *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 @@ extern {
                                              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,
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index a013af7a460..7a194a37c9c 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -748,7 +748,10 @@ unsafe fn codegen(cgcx: &CodegenContext,
 
         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 @@ unsafe fn codegen(cgcx: &CodegenContext,
 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));