5 use rustc_serialize::leb128;
7 // https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec
8 const WASM_CUSTOM_SECTION_ID: u8 = 0;
10 /// Adds or augment the existing `producers` section to encode information about
11 /// the Rust compiler used to produce the wasm file.
12 pub fn add_producer_section(
19 values: Vec<FieldValue<'a>>,
22 #[derive(Copy, Clone)]
23 struct FieldValue<'a> {
28 let wasm = fs::read(path).expect("failed to read wasm output");
29 let mut ret = WasmEncoder::new();
30 ret.data.extend(&wasm[..8]);
32 // skip the 8 byte wasm/version header
33 let rustc_value = FieldValue {
35 version: rustc_version,
37 let rust_value = FieldValue {
39 version: rust_version,
41 let mut fields = Vec::new();
42 let mut wrote_rustc = false;
43 let mut wrote_rust = false;
45 // Move all sections from the original wasm file to our output, skipping
46 // everything except the producers section
47 for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) {
48 if id != WASM_CUSTOM_SECTION_ID {
53 let mut decoder = WasmDecoder::new(raw);
54 if decoder.str() != "producers" {
60 // Read off the producers section into our fields outside the loop,
61 // we'll re-encode the producers section when we're done (to handle an
62 // entirely missing producers section as well).
63 info!("rewriting existing producers section");
65 for _ in 0..decoder.u32() {
66 let name = decoder.str();
67 let mut values = Vec::new();
68 for _ in 0..decoder.u32() {
69 let name = decoder.str();
70 let version = decoder.str();
71 values.push(FieldValue { name, version });
74 if name == "language" {
75 values.push(rust_value);
77 } else if name == "processed-by" {
78 values.push(rustc_value);
81 fields.push(Field { name, values });
88 values: vec![rust_value],
94 values: vec![rustc_value],
98 // Append the producers section to the end of the wasm file.
99 let mut section = WasmEncoder::new();
100 section.str("producers");
101 section.u32(fields.len() as u32);
102 for field in fields {
103 section.str(field.name);
104 section.u32(field.values.len() as u32);
105 for value in field.values {
106 section.str(value.name);
107 section.str(value.version);
110 ret.byte(WASM_CUSTOM_SECTION_ID);
111 ret.bytes(§ion.data);
113 fs::write(path, &ret.data).expect("failed to write wasm output");
116 struct WasmSections<'a>(WasmDecoder<'a>);
118 impl<'a> Iterator for WasmSections<'a> {
119 type Item = (u8, &'a [u8]);
121 fn next(&mut self) -> Option<(u8, &'a [u8])> {
122 if self.0.data.is_empty() {
126 // see https://webassembly.github.io/spec/core/binary/modules.html#sections
127 let id = self.0.byte();
128 let section_len = self.0.u32();
129 info!("new section {} / {} bytes", id, section_len);
130 let section = self.0.skip(section_len as usize);
135 struct WasmDecoder<'a> {
139 impl<'a> WasmDecoder<'a> {
140 fn new(data: &'a [u8]) -> WasmDecoder<'a> {
144 fn byte(&mut self) -> u8 {
148 fn u32(&mut self) -> u32 {
149 let (n, l1) = leb128::read_u32_leb128(self.data);
150 self.data = &self.data[l1..];
154 fn skip(&mut self, amt: usize) -> &'a [u8] {
155 let (data, rest) = self.data.split_at(amt);
160 fn str(&mut self) -> &'a str {
161 let len = self.u32();
162 str::from_utf8(self.skip(len as usize)).unwrap()
171 fn new() -> WasmEncoder {
172 WasmEncoder { data: Vec::new() }
175 fn u32(&mut self, val: u32) {
176 leb128::write_u32_leb128(&mut self.data, val);
179 fn byte(&mut self, val: u8) {
183 fn bytes(&mut self, val: &[u8]) {
184 self.u32(val.len() as u32);
185 self.data.extend_from_slice(val);
188 fn str(&mut self, val: &str) {
189 self.bytes(val.as_bytes())