@@ -17,6 +17,7 @@ use serialize::leb128;
17
17
18
18
// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec
19
19
const WASM_IMPORT_SECTION_ID : u8 = 2 ;
20
+ const WASM_CUSTOM_SECTION_ID : u8 = 0 ;
20
21
21
22
const WASM_EXTERNAL_KIND_FUNCTION : u8 = 0 ;
22
23
const WASM_EXTERNAL_KIND_TABLE : u8 = 1 ;
@@ -121,6 +122,112 @@ pub fn rewrite_imports(path: &Path, import_map: &FxHashMap<String, String>) {
121
122
}
122
123
}
123
124
125
+ /// Add or augment the existing `producers` section to encode information about
126
+ /// the Rust compiler used to produce the wasm file.
127
+ pub fn add_producer_section (
128
+ path : & Path ,
129
+ rust_version : & str ,
130
+ rustc_version : & str ,
131
+ ) {
132
+ struct Field < ' a > {
133
+ name : & ' a str ,
134
+ values : Vec < FieldValue < ' a > > ,
135
+ }
136
+
137
+ #[ derive( Copy , Clone ) ]
138
+ struct FieldValue < ' a > {
139
+ name : & ' a str ,
140
+ version : & ' a str ,
141
+ }
142
+
143
+ let wasm = fs:: read ( path) . expect ( "failed to read wasm output" ) ;
144
+ let mut ret = WasmEncoder :: new ( ) ;
145
+ ret. data . extend ( & wasm[ ..8 ] ) ;
146
+
147
+ // skip the 8 byte wasm/version header
148
+ let rustc_value = FieldValue {
149
+ name : "rustc" ,
150
+ version : rustc_version,
151
+ } ;
152
+ let rust_value = FieldValue {
153
+ name : "Rust" ,
154
+ version : rust_version,
155
+ } ;
156
+ let mut fields = Vec :: new ( ) ;
157
+ let mut wrote_rustc = false ;
158
+ let mut wrote_rust = false ;
159
+
160
+ // Move all sections from the original wasm file to our output, skipping
161
+ // everything except the producers section
162
+ for ( id, raw) in WasmSections ( WasmDecoder :: new ( & wasm[ 8 ..] ) ) {
163
+ if id != WASM_CUSTOM_SECTION_ID {
164
+ ret. byte ( id) ;
165
+ ret. bytes ( raw) ;
166
+ continue
167
+ }
168
+ let mut decoder = WasmDecoder :: new ( raw) ;
169
+ if decoder. str ( ) != "producers" {
170
+ ret. byte ( id) ;
171
+ ret. bytes ( raw) ;
172
+ continue
173
+ }
174
+
175
+ // Read off the producers section into our fields outside the loop,
176
+ // we'll re-encode the producers section when we're done (to handle an
177
+ // entirely missing producers section as well).
178
+ info ! ( "rewriting existing producers section" ) ;
179
+
180
+ for _ in 0 ..decoder. u32 ( ) {
181
+ let name = decoder. str ( ) ;
182
+ let mut values = Vec :: new ( ) ;
183
+ for _ in 0 ..decoder. u32 ( ) {
184
+ let name = decoder. str ( ) ;
185
+ let version = decoder. str ( ) ;
186
+ values. push ( FieldValue { name, version } ) ;
187
+ }
188
+
189
+ if name == "language" {
190
+ values. push ( rust_value) ;
191
+ wrote_rust = true ;
192
+ } else if name == "processed-by" {
193
+ values. push ( rustc_value) ;
194
+ wrote_rustc = true ;
195
+ }
196
+ fields. push ( Field { name, values } ) ;
197
+ }
198
+ }
199
+
200
+ if !wrote_rust {
201
+ fields. push ( Field {
202
+ name : "language" ,
203
+ values : vec ! [ rust_value] ,
204
+ } ) ;
205
+ }
206
+ if !wrote_rustc {
207
+ fields. push ( Field {
208
+ name : "processed-by" ,
209
+ values : vec ! [ rustc_value] ,
210
+ } ) ;
211
+ }
212
+
213
+ // Append the producers section to the end of the wasm file.
214
+ let mut section = WasmEncoder :: new ( ) ;
215
+ section. str ( "producers" ) ;
216
+ section. u32 ( fields. len ( ) as u32 ) ;
217
+ for field in fields {
218
+ section. str ( field. name ) ;
219
+ section. u32 ( field. values . len ( ) as u32 ) ;
220
+ for value in field. values {
221
+ section. str ( value. name ) ;
222
+ section. str ( value. version ) ;
223
+ }
224
+ }
225
+ ret. byte ( WASM_CUSTOM_SECTION_ID ) ;
226
+ ret. bytes ( & section. data ) ;
227
+
228
+ fs:: write ( path, & ret. data ) . expect ( "failed to write wasm output" ) ;
229
+ }
230
+
124
231
struct WasmSections < ' a > ( WasmDecoder < ' a > ) ;
125
232
126
233
impl < ' a > Iterator for WasmSections < ' a > {
0 commit comments