]>
Commit | Line | Data |
---|---|---|
a2a8927a XL |
1 | //! Support for reading Wasm files. |
2 | //! | |
3 | //! Provides `WasmFile` and related types which implement the `Object` trait. | |
4 | //! | |
5 | //! Currently implements the minimum required to access DWARF debugging information. | |
6 | use alloc::boxed::Box; | |
7 | use alloc::vec::Vec; | |
8 | use core::marker::PhantomData; | |
9 | use core::{slice, str}; | |
10 | use wasmparser as wp; | |
11 | ||
12 | use crate::read::{ | |
13 | self, Architecture, ComdatKind, CompressedData, CompressedFileRange, Error, Export, FileFlags, | |
14 | Import, NoDynamicRelocationIterator, Object, ObjectComdat, ObjectKind, ObjectSection, | |
15 | ObjectSegment, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Relocation, Result, | |
16 | SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, | |
17 | SymbolSection, | |
18 | }; | |
19 | ||
20 | const SECTION_CUSTOM: usize = 0; | |
21 | const SECTION_TYPE: usize = 1; | |
22 | const SECTION_IMPORT: usize = 2; | |
23 | const SECTION_FUNCTION: usize = 3; | |
24 | const SECTION_TABLE: usize = 4; | |
25 | const SECTION_MEMORY: usize = 5; | |
26 | const SECTION_GLOBAL: usize = 6; | |
27 | const SECTION_EXPORT: usize = 7; | |
28 | const SECTION_START: usize = 8; | |
29 | const SECTION_ELEMENT: usize = 9; | |
30 | const SECTION_CODE: usize = 10; | |
31 | const SECTION_DATA: usize = 11; | |
32 | const SECTION_DATA_COUNT: usize = 12; | |
33 | // Update this constant when adding new section id: | |
34 | const MAX_SECTION_ID: usize = SECTION_DATA_COUNT; | |
35 | ||
36 | /// A WebAssembly object file. | |
37 | #[derive(Debug)] | |
38 | pub struct WasmFile<'data, R = &'data [u8]> { | |
39 | // All sections, including custom sections. | |
40 | sections: Vec<wp::Section<'data>>, | |
41 | // Indices into `sections` of sections with a non-zero id. | |
42 | id_sections: Box<[Option<usize>; MAX_SECTION_ID + 1]>, | |
43 | // Whether the file has DWARF information. | |
44 | has_debug_symbols: bool, | |
45 | // Symbols collected from imports, exports, code and name sections. | |
46 | symbols: Vec<WasmSymbolInternal<'data>>, | |
47 | // Address of the function body for the entry point. | |
48 | entry: u64, | |
49 | marker: PhantomData<R>, | |
50 | } | |
51 | ||
52 | #[derive(Clone)] | |
53 | enum LocalFunctionKind { | |
54 | Unknown, | |
55 | Exported { symbol_ids: Vec<u32> }, | |
56 | Local { symbol_id: u32 }, | |
57 | } | |
58 | ||
59 | impl<T> ReadError<T> for wasmparser::Result<T> { | |
60 | fn read_error(self, error: &'static str) -> Result<T> { | |
61 | self.map_err(|_| Error(error)) | |
62 | } | |
63 | } | |
64 | ||
65 | impl<'data, R: ReadRef<'data>> WasmFile<'data, R> { | |
66 | /// Parse the raw wasm data. | |
67 | pub fn parse(data: R) -> Result<Self> { | |
68 | let len = data.len().read_error("Unknown Wasm file size")?; | |
69 | let data = data.read_bytes_at(0, len).read_error("Wasm read failed")?; | |
70 | let module = wp::ModuleReader::new(data).read_error("Invalid Wasm header")?; | |
71 | ||
72 | let mut file = WasmFile { | |
73 | sections: Vec::new(), | |
74 | id_sections: Default::default(), | |
75 | has_debug_symbols: false, | |
76 | symbols: Vec::new(), | |
77 | entry: 0, | |
78 | marker: PhantomData, | |
79 | }; | |
80 | ||
81 | let mut main_file_symbol = Some(WasmSymbolInternal { | |
82 | name: "", | |
83 | address: 0, | |
84 | size: 0, | |
85 | kind: SymbolKind::File, | |
86 | section: SymbolSection::None, | |
87 | scope: SymbolScope::Compilation, | |
88 | }); | |
89 | ||
90 | let mut imported_funcs_count = 0; | |
91 | let mut local_func_kinds = Vec::new(); | |
92 | let mut entry_func_id = None; | |
93 | ||
94 | for section in module { | |
95 | let section = section.read_error("Invalid Wasm section header")?; | |
96 | ||
97 | match section.code { | |
98 | wp::SectionCode::Import => { | |
99 | let mut last_module_name = None; | |
100 | ||
101 | for import in section | |
102 | .get_import_section_reader() | |
103 | .read_error("Couldn't read header of the import section")? | |
104 | { | |
105 | let import = import.read_error("Couldn't read an import item")?; | |
106 | let module_name = import.module; | |
107 | ||
108 | if last_module_name != Some(module_name) { | |
109 | file.symbols.push(WasmSymbolInternal { | |
110 | name: module_name, | |
111 | address: 0, | |
112 | size: 0, | |
113 | kind: SymbolKind::File, | |
114 | section: SymbolSection::None, | |
115 | scope: SymbolScope::Dynamic, | |
116 | }); | |
117 | last_module_name = Some(module_name); | |
118 | } | |
119 | ||
120 | let kind = match import.ty { | |
121 | wp::ImportSectionEntryType::Function(_) => { | |
122 | imported_funcs_count += 1; | |
123 | SymbolKind::Text | |
124 | } | |
125 | wp::ImportSectionEntryType::Table(_) | |
126 | | wp::ImportSectionEntryType::Memory(_) | |
127 | | wp::ImportSectionEntryType::Global(_) => SymbolKind::Data, | |
128 | }; | |
129 | ||
130 | file.symbols.push(WasmSymbolInternal { | |
131 | name: import.field, | |
132 | address: 0, | |
133 | size: 0, | |
134 | kind, | |
135 | section: SymbolSection::Undefined, | |
136 | scope: SymbolScope::Dynamic, | |
137 | }); | |
138 | } | |
139 | } | |
140 | wp::SectionCode::Function => { | |
141 | local_func_kinds = vec![ | |
142 | LocalFunctionKind::Unknown; | |
143 | section | |
144 | .get_function_section_reader() | |
145 | .read_error("Couldn't read header of the function section")? | |
146 | .get_count() as usize | |
147 | ]; | |
148 | } | |
149 | wp::SectionCode::Export => { | |
150 | if let Some(main_file_symbol) = main_file_symbol.take() { | |
151 | file.symbols.push(main_file_symbol); | |
152 | } | |
153 | ||
154 | for export in section | |
155 | .get_export_section_reader() | |
156 | .read_error("Couldn't read header of the export section")? | |
157 | { | |
158 | let export = export.read_error("Couldn't read an export item")?; | |
159 | ||
160 | let (kind, section_idx) = match export.kind { | |
161 | wp::ExternalKind::Function => { | |
162 | if let Some(local_func_id) = | |
163 | export.index.checked_sub(imported_funcs_count) | |
164 | { | |
165 | let local_func_kind = | |
166 | &mut local_func_kinds[local_func_id as usize]; | |
167 | if let LocalFunctionKind::Unknown = local_func_kind { | |
168 | *local_func_kind = LocalFunctionKind::Exported { | |
169 | symbol_ids: Vec::new(), | |
170 | }; | |
171 | } | |
172 | let symbol_ids = match local_func_kind { | |
173 | LocalFunctionKind::Exported { symbol_ids } => symbol_ids, | |
174 | _ => unreachable!(), | |
175 | }; | |
176 | symbol_ids.push(file.symbols.len() as u32); | |
177 | } | |
178 | (SymbolKind::Text, SECTION_CODE) | |
179 | } | |
180 | wp::ExternalKind::Table | |
181 | | wp::ExternalKind::Memory | |
182 | | wp::ExternalKind::Global => (SymbolKind::Data, SECTION_DATA), | |
183 | }; | |
184 | ||
185 | file.symbols.push(WasmSymbolInternal { | |
186 | name: export.field, | |
187 | address: 0, | |
188 | size: 0, | |
189 | kind, | |
190 | section: SymbolSection::Section(SectionIndex(section_idx)), | |
191 | scope: SymbolScope::Dynamic, | |
192 | }); | |
193 | } | |
194 | } | |
195 | wp::SectionCode::Start => { | |
196 | entry_func_id = Some( | |
197 | section | |
198 | .get_start_section_content() | |
199 | .read_error("Couldn't read contents of the start section")?, | |
200 | ); | |
201 | } | |
202 | wp::SectionCode::Code => { | |
203 | if let Some(main_file_symbol) = main_file_symbol.take() { | |
204 | file.symbols.push(main_file_symbol); | |
205 | } | |
206 | ||
207 | for (i, (body, local_func_kind)) in section | |
208 | .get_code_section_reader() | |
209 | .read_error("Couldn't read header of the code section")? | |
210 | .into_iter() | |
211 | .zip(&mut local_func_kinds) | |
212 | .enumerate() | |
213 | { | |
214 | let body = body.read_error("Couldn't read a function body")?; | |
215 | let range = body.range(); | |
216 | ||
217 | let address = range.start as u64 - section.range().start as u64; | |
218 | let size = (range.end - range.start) as u64; | |
219 | ||
220 | if entry_func_id == Some(i as u32) { | |
221 | file.entry = address; | |
222 | } | |
223 | ||
224 | match local_func_kind { | |
225 | LocalFunctionKind::Unknown => { | |
226 | *local_func_kind = LocalFunctionKind::Local { | |
227 | symbol_id: file.symbols.len() as u32, | |
228 | }; | |
229 | file.symbols.push(WasmSymbolInternal { | |
230 | name: "", | |
231 | address, | |
232 | size, | |
233 | kind: SymbolKind::Text, | |
234 | section: SymbolSection::Section(SectionIndex(SECTION_CODE)), | |
235 | scope: SymbolScope::Compilation, | |
236 | }); | |
237 | } | |
238 | LocalFunctionKind::Exported { symbol_ids } => { | |
239 | for symbol_id in core::mem::take(symbol_ids) { | |
240 | let export_symbol = &mut file.symbols[symbol_id as usize]; | |
241 | export_symbol.address = address; | |
242 | export_symbol.size = size; | |
243 | } | |
244 | } | |
245 | _ => unreachable!(), | |
246 | } | |
247 | } | |
248 | } | |
249 | wp::SectionCode::Custom { | |
250 | kind: wp::CustomSectionKind::Name, | |
251 | .. | |
252 | } => { | |
253 | for name in section | |
254 | .get_name_section_reader() | |
255 | .read_error("Couldn't read header of the name section")? | |
256 | { | |
257 | let name = | |
258 | match name.read_error("Couldn't read header of a name subsection")? { | |
259 | wp::Name::Function(name) => name, | |
260 | _ => continue, | |
261 | }; | |
262 | let mut name_map = name | |
263 | .get_map() | |
264 | .read_error("Couldn't read header of the function name subsection")?; | |
265 | for _ in 0..name_map.get_count() { | |
266 | let naming = name_map | |
267 | .read() | |
268 | .read_error("Couldn't read a function name")?; | |
269 | if let Some(local_index) = | |
270 | naming.index.checked_sub(imported_funcs_count) | |
271 | { | |
272 | if let LocalFunctionKind::Local { symbol_id } = | |
273 | local_func_kinds[local_index as usize] | |
274 | { | |
275 | file.symbols[symbol_id as usize].name = naming.name; | |
276 | } | |
277 | } | |
278 | } | |
279 | } | |
280 | } | |
281 | wp::SectionCode::Custom { name, .. } if name.starts_with(".debug_") => { | |
282 | file.has_debug_symbols = true; | |
283 | } | |
284 | _ => {} | |
285 | } | |
286 | ||
287 | let id = section_code_to_id(section.code); | |
288 | file.id_sections[id] = Some(file.sections.len()); | |
289 | ||
290 | file.sections.push(section); | |
291 | } | |
292 | ||
293 | Ok(file) | |
294 | } | |
295 | } | |
296 | ||
297 | impl<'data, R> read::private::Sealed for WasmFile<'data, R> {} | |
298 | ||
299 | impl<'data, 'file, R> Object<'data, 'file> for WasmFile<'data, R> | |
300 | where | |
301 | 'data: 'file, | |
302 | R: 'file, | |
303 | { | |
304 | type Segment = WasmSegment<'data, 'file, R>; | |
305 | type SegmentIterator = WasmSegmentIterator<'data, 'file, R>; | |
306 | type Section = WasmSection<'data, 'file, R>; | |
307 | type SectionIterator = WasmSectionIterator<'data, 'file, R>; | |
308 | type Comdat = WasmComdat<'data, 'file, R>; | |
309 | type ComdatIterator = WasmComdatIterator<'data, 'file, R>; | |
310 | type Symbol = WasmSymbol<'data, 'file>; | |
311 | type SymbolIterator = WasmSymbolIterator<'data, 'file>; | |
312 | type SymbolTable = WasmSymbolTable<'data, 'file>; | |
313 | type DynamicRelocationIterator = NoDynamicRelocationIterator; | |
314 | ||
315 | #[inline] | |
316 | fn architecture(&self) -> Architecture { | |
317 | Architecture::Wasm32 | |
318 | } | |
319 | ||
320 | #[inline] | |
321 | fn is_little_endian(&self) -> bool { | |
322 | true | |
323 | } | |
324 | ||
325 | #[inline] | |
326 | fn is_64(&self) -> bool { | |
327 | false | |
328 | } | |
329 | ||
330 | fn kind(&self) -> ObjectKind { | |
331 | // TODO: check for `linking` custom section | |
332 | ObjectKind::Unknown | |
333 | } | |
334 | ||
335 | fn segments(&'file self) -> Self::SegmentIterator { | |
336 | WasmSegmentIterator { file: self } | |
337 | } | |
338 | ||
339 | fn section_by_name_bytes( | |
340 | &'file self, | |
341 | section_name: &[u8], | |
342 | ) -> Option<WasmSection<'data, 'file, R>> { | |
343 | self.sections() | |
344 | .find(|section| section.name_bytes() == Ok(section_name)) | |
345 | } | |
346 | ||
347 | fn section_by_index(&'file self, index: SectionIndex) -> Result<WasmSection<'data, 'file, R>> { | |
348 | // TODO: Missing sections should return an empty section. | |
349 | let id_section = self | |
350 | .id_sections | |
351 | .get(index.0) | |
352 | .and_then(|x| *x) | |
353 | .read_error("Invalid Wasm section index")?; | |
354 | let section = self.sections.get(id_section).unwrap(); | |
355 | Ok(WasmSection { | |
356 | section, | |
357 | marker: PhantomData, | |
358 | }) | |
359 | } | |
360 | ||
361 | fn sections(&'file self) -> Self::SectionIterator { | |
362 | WasmSectionIterator { | |
363 | sections: self.sections.iter(), | |
364 | marker: PhantomData, | |
365 | } | |
366 | } | |
367 | ||
368 | fn comdats(&'file self) -> Self::ComdatIterator { | |
369 | WasmComdatIterator { file: self } | |
370 | } | |
371 | ||
372 | #[inline] | |
373 | fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<WasmSymbol<'data, 'file>> { | |
374 | let symbol = self | |
375 | .symbols | |
376 | .get(index.0) | |
377 | .read_error("Invalid Wasm symbol index")?; | |
378 | Ok(WasmSymbol { index, symbol }) | |
379 | } | |
380 | ||
381 | fn symbols(&'file self) -> Self::SymbolIterator { | |
382 | WasmSymbolIterator { | |
383 | symbols: self.symbols.iter().enumerate(), | |
384 | } | |
385 | } | |
386 | ||
387 | fn symbol_table(&'file self) -> Option<WasmSymbolTable<'data, 'file>> { | |
388 | Some(WasmSymbolTable { | |
389 | symbols: &self.symbols, | |
390 | }) | |
391 | } | |
392 | ||
393 | fn dynamic_symbols(&'file self) -> Self::SymbolIterator { | |
394 | WasmSymbolIterator { | |
395 | symbols: [].iter().enumerate(), | |
396 | } | |
397 | } | |
398 | ||
399 | #[inline] | |
400 | fn dynamic_symbol_table(&'file self) -> Option<WasmSymbolTable<'data, 'file>> { | |
401 | None | |
402 | } | |
403 | ||
404 | #[inline] | |
405 | fn dynamic_relocations(&self) -> Option<NoDynamicRelocationIterator> { | |
406 | None | |
407 | } | |
408 | ||
409 | fn imports(&self) -> Result<Vec<Import<'data>>> { | |
410 | // TODO: return entries in the import section | |
411 | Ok(Vec::new()) | |
412 | } | |
413 | ||
414 | fn exports(&self) -> Result<Vec<Export<'data>>> { | |
415 | // TODO: return entries in the export section | |
416 | Ok(Vec::new()) | |
417 | } | |
418 | ||
419 | fn has_debug_symbols(&self) -> bool { | |
420 | self.has_debug_symbols | |
421 | } | |
422 | ||
423 | fn relative_address_base(&self) -> u64 { | |
424 | 0 | |
425 | } | |
426 | ||
427 | #[inline] | |
428 | fn entry(&'file self) -> u64 { | |
429 | self.entry | |
430 | } | |
431 | ||
432 | #[inline] | |
433 | fn flags(&self) -> FileFlags { | |
434 | FileFlags::None | |
435 | } | |
436 | } | |
437 | ||
438 | /// An iterator over the segments of a `WasmFile`. | |
439 | #[derive(Debug)] | |
440 | pub struct WasmSegmentIterator<'data, 'file, R = &'data [u8]> { | |
441 | file: &'file WasmFile<'data, R>, | |
442 | } | |
443 | ||
444 | impl<'data, 'file, R> Iterator for WasmSegmentIterator<'data, 'file, R> { | |
445 | type Item = WasmSegment<'data, 'file, R>; | |
446 | ||
447 | #[inline] | |
448 | fn next(&mut self) -> Option<Self::Item> { | |
449 | None | |
450 | } | |
451 | } | |
452 | ||
453 | /// A segment of a `WasmFile`. | |
454 | #[derive(Debug)] | |
455 | pub struct WasmSegment<'data, 'file, R = &'data [u8]> { | |
456 | file: &'file WasmFile<'data, R>, | |
457 | } | |
458 | ||
459 | impl<'data, 'file, R> read::private::Sealed for WasmSegment<'data, 'file, R> {} | |
460 | ||
461 | impl<'data, 'file, R> ObjectSegment<'data> for WasmSegment<'data, 'file, R> { | |
462 | #[inline] | |
463 | fn address(&self) -> u64 { | |
464 | unreachable!() | |
465 | } | |
466 | ||
467 | #[inline] | |
468 | fn size(&self) -> u64 { | |
469 | unreachable!() | |
470 | } | |
471 | ||
472 | #[inline] | |
473 | fn align(&self) -> u64 { | |
474 | unreachable!() | |
475 | } | |
476 | ||
477 | #[inline] | |
478 | fn file_range(&self) -> (u64, u64) { | |
479 | unreachable!() | |
480 | } | |
481 | ||
482 | fn data(&self) -> Result<&'data [u8]> { | |
483 | unreachable!() | |
484 | } | |
485 | ||
486 | fn data_range(&self, _address: u64, _size: u64) -> Result<Option<&'data [u8]>> { | |
487 | unreachable!() | |
488 | } | |
489 | ||
490 | #[inline] | |
491 | fn name_bytes(&self) -> Result<Option<&[u8]>> { | |
492 | unreachable!() | |
493 | } | |
494 | ||
495 | #[inline] | |
496 | fn name(&self) -> Result<Option<&str>> { | |
497 | unreachable!() | |
498 | } | |
499 | } | |
500 | ||
501 | /// An iterator over the sections of a `WasmFile`. | |
502 | #[derive(Debug)] | |
503 | pub struct WasmSectionIterator<'data, 'file, R = &'data [u8]> { | |
504 | sections: slice::Iter<'file, wp::Section<'data>>, | |
505 | marker: PhantomData<R>, | |
506 | } | |
507 | ||
508 | impl<'data, 'file, R> Iterator for WasmSectionIterator<'data, 'file, R> { | |
509 | type Item = WasmSection<'data, 'file, R>; | |
510 | ||
511 | fn next(&mut self) -> Option<Self::Item> { | |
512 | let section = self.sections.next()?; | |
513 | Some(WasmSection { | |
514 | section, | |
515 | marker: PhantomData, | |
516 | }) | |
517 | } | |
518 | } | |
519 | ||
520 | /// A section of a `WasmFile`. | |
521 | #[derive(Debug)] | |
522 | pub struct WasmSection<'data, 'file, R = &'data [u8]> { | |
523 | section: &'file wp::Section<'data>, | |
524 | marker: PhantomData<R>, | |
525 | } | |
526 | ||
527 | impl<'data, 'file, R> read::private::Sealed for WasmSection<'data, 'file, R> {} | |
528 | ||
529 | impl<'data, 'file, R> ObjectSection<'data> for WasmSection<'data, 'file, R> { | |
530 | type RelocationIterator = WasmRelocationIterator<'data, 'file, R>; | |
531 | ||
532 | #[inline] | |
533 | fn index(&self) -> SectionIndex { | |
534 | // Note that we treat all custom sections as index 0. | |
535 | // This is ok because they are never looked up by index. | |
536 | SectionIndex(section_code_to_id(self.section.code)) | |
537 | } | |
538 | ||
539 | #[inline] | |
540 | fn address(&self) -> u64 { | |
541 | 0 | |
542 | } | |
543 | ||
544 | #[inline] | |
545 | fn size(&self) -> u64 { | |
546 | let range = self.section.range(); | |
547 | (range.end - range.start) as u64 | |
548 | } | |
549 | ||
550 | #[inline] | |
551 | fn align(&self) -> u64 { | |
552 | 1 | |
553 | } | |
554 | ||
555 | #[inline] | |
556 | fn file_range(&self) -> Option<(u64, u64)> { | |
557 | let range = self.section.range(); | |
558 | Some((range.start as _, range.end as _)) | |
559 | } | |
560 | ||
561 | #[inline] | |
562 | fn data(&self) -> Result<&'data [u8]> { | |
563 | let mut reader = self.section.get_binary_reader(); | |
564 | // TODO: raise a feature request upstream to be able | |
565 | // to get remaining slice from a BinaryReader directly. | |
566 | Ok(reader.read_bytes(reader.bytes_remaining()).unwrap()) | |
567 | } | |
568 | ||
569 | fn data_range(&self, _address: u64, _size: u64) -> Result<Option<&'data [u8]>> { | |
570 | unimplemented!() | |
571 | } | |
572 | ||
573 | #[inline] | |
574 | fn compressed_file_range(&self) -> Result<CompressedFileRange> { | |
575 | Ok(CompressedFileRange::none(self.file_range())) | |
576 | } | |
577 | ||
578 | #[inline] | |
579 | fn compressed_data(&self) -> Result<CompressedData<'data>> { | |
580 | self.data().map(CompressedData::none) | |
581 | } | |
582 | ||
583 | #[inline] | |
584 | fn name_bytes(&self) -> Result<&[u8]> { | |
585 | self.name().map(str::as_bytes) | |
586 | } | |
587 | ||
588 | #[inline] | |
589 | fn name(&self) -> Result<&str> { | |
590 | Ok(match self.section.code { | |
591 | wp::SectionCode::Custom { name, .. } => name, | |
592 | wp::SectionCode::Type => "<type>", | |
593 | wp::SectionCode::Import => "<import>", | |
594 | wp::SectionCode::Function => "<function>", | |
595 | wp::SectionCode::Table => "<table>", | |
596 | wp::SectionCode::Memory => "<memory>", | |
597 | wp::SectionCode::Global => "<global>", | |
598 | wp::SectionCode::Export => "<export>", | |
599 | wp::SectionCode::Start => "<start>", | |
600 | wp::SectionCode::Element => "<element>", | |
601 | wp::SectionCode::Code => "<code>", | |
602 | wp::SectionCode::Data => "<data>", | |
603 | wp::SectionCode::DataCount => "<data_count>", | |
604 | }) | |
605 | } | |
606 | ||
607 | #[inline] | |
608 | fn segment_name_bytes(&self) -> Result<Option<&[u8]>> { | |
609 | Ok(None) | |
610 | } | |
611 | ||
612 | #[inline] | |
613 | fn segment_name(&self) -> Result<Option<&str>> { | |
614 | Ok(None) | |
615 | } | |
616 | ||
617 | #[inline] | |
618 | fn kind(&self) -> SectionKind { | |
619 | match self.section.code { | |
620 | wp::SectionCode::Custom { kind, .. } => match kind { | |
621 | wp::CustomSectionKind::Reloc | wp::CustomSectionKind::Linking => { | |
622 | SectionKind::Linker | |
623 | } | |
624 | _ => SectionKind::Other, | |
625 | }, | |
626 | wp::SectionCode::Type => SectionKind::Metadata, | |
627 | wp::SectionCode::Import => SectionKind::Linker, | |
628 | wp::SectionCode::Function => SectionKind::Metadata, | |
629 | wp::SectionCode::Table => SectionKind::UninitializedData, | |
630 | wp::SectionCode::Memory => SectionKind::UninitializedData, | |
631 | wp::SectionCode::Global => SectionKind::Data, | |
632 | wp::SectionCode::Export => SectionKind::Linker, | |
633 | wp::SectionCode::Start => SectionKind::Linker, | |
634 | wp::SectionCode::Element => SectionKind::Data, | |
635 | wp::SectionCode::Code => SectionKind::Text, | |
636 | wp::SectionCode::Data => SectionKind::Data, | |
637 | wp::SectionCode::DataCount => SectionKind::UninitializedData, | |
638 | } | |
639 | } | |
640 | ||
641 | #[inline] | |
642 | fn relocations(&self) -> WasmRelocationIterator<'data, 'file, R> { | |
643 | WasmRelocationIterator(PhantomData) | |
644 | } | |
645 | ||
646 | #[inline] | |
647 | fn flags(&self) -> SectionFlags { | |
648 | SectionFlags::None | |
649 | } | |
650 | } | |
651 | ||
652 | /// An iterator over the COMDAT section groups of a `WasmFile`. | |
653 | #[derive(Debug)] | |
654 | pub struct WasmComdatIterator<'data, 'file, R = &'data [u8]> { | |
655 | file: &'file WasmFile<'data, R>, | |
656 | } | |
657 | ||
658 | impl<'data, 'file, R> Iterator for WasmComdatIterator<'data, 'file, R> { | |
659 | type Item = WasmComdat<'data, 'file, R>; | |
660 | ||
661 | #[inline] | |
662 | fn next(&mut self) -> Option<Self::Item> { | |
663 | None | |
664 | } | |
665 | } | |
666 | ||
667 | /// A COMDAT section group of a `WasmFile`. | |
668 | #[derive(Debug)] | |
669 | pub struct WasmComdat<'data, 'file, R = &'data [u8]> { | |
670 | file: &'file WasmFile<'data, R>, | |
671 | } | |
672 | ||
673 | impl<'data, 'file, R> read::private::Sealed for WasmComdat<'data, 'file, R> {} | |
674 | ||
675 | impl<'data, 'file, R> ObjectComdat<'data> for WasmComdat<'data, 'file, R> { | |
676 | type SectionIterator = WasmComdatSectionIterator<'data, 'file, R>; | |
677 | ||
678 | #[inline] | |
679 | fn kind(&self) -> ComdatKind { | |
680 | unreachable!(); | |
681 | } | |
682 | ||
683 | #[inline] | |
684 | fn symbol(&self) -> SymbolIndex { | |
685 | unreachable!(); | |
686 | } | |
687 | ||
688 | #[inline] | |
689 | fn name_bytes(&self) -> Result<&[u8]> { | |
690 | unreachable!(); | |
691 | } | |
692 | ||
693 | #[inline] | |
694 | fn name(&self) -> Result<&str> { | |
695 | unreachable!(); | |
696 | } | |
697 | ||
698 | #[inline] | |
699 | fn sections(&self) -> Self::SectionIterator { | |
700 | unreachable!(); | |
701 | } | |
702 | } | |
703 | ||
704 | /// An iterator over the sections in a COMDAT section group of a `WasmFile`. | |
705 | #[derive(Debug)] | |
706 | pub struct WasmComdatSectionIterator<'data, 'file, R = &'data [u8]> | |
707 | where | |
708 | 'data: 'file, | |
709 | { | |
710 | file: &'file WasmFile<'data, R>, | |
711 | } | |
712 | ||
713 | impl<'data, 'file, R> Iterator for WasmComdatSectionIterator<'data, 'file, R> { | |
714 | type Item = SectionIndex; | |
715 | ||
716 | fn next(&mut self) -> Option<Self::Item> { | |
717 | None | |
718 | } | |
719 | } | |
720 | ||
721 | /// A symbol table of a `WasmFile`. | |
722 | #[derive(Debug)] | |
723 | pub struct WasmSymbolTable<'data, 'file> { | |
724 | symbols: &'file [WasmSymbolInternal<'data>], | |
725 | } | |
726 | ||
727 | impl<'data, 'file> read::private::Sealed for WasmSymbolTable<'data, 'file> {} | |
728 | ||
729 | impl<'data, 'file> ObjectSymbolTable<'data> for WasmSymbolTable<'data, 'file> { | |
730 | type Symbol = WasmSymbol<'data, 'file>; | |
731 | type SymbolIterator = WasmSymbolIterator<'data, 'file>; | |
732 | ||
733 | fn symbols(&self) -> Self::SymbolIterator { | |
734 | WasmSymbolIterator { | |
735 | symbols: self.symbols.iter().enumerate(), | |
736 | } | |
737 | } | |
738 | ||
739 | fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> { | |
740 | let symbol = self | |
741 | .symbols | |
742 | .get(index.0) | |
743 | .read_error("Invalid Wasm symbol index")?; | |
744 | Ok(WasmSymbol { index, symbol }) | |
745 | } | |
746 | } | |
747 | ||
748 | /// An iterator over the symbols of a `WasmFile`. | |
749 | #[derive(Debug)] | |
750 | pub struct WasmSymbolIterator<'data, 'file> { | |
751 | symbols: core::iter::Enumerate<slice::Iter<'file, WasmSymbolInternal<'data>>>, | |
752 | } | |
753 | ||
754 | impl<'data, 'file> Iterator for WasmSymbolIterator<'data, 'file> { | |
755 | type Item = WasmSymbol<'data, 'file>; | |
756 | ||
757 | fn next(&mut self) -> Option<Self::Item> { | |
758 | let (index, symbol) = self.symbols.next()?; | |
759 | Some(WasmSymbol { | |
760 | index: SymbolIndex(index), | |
761 | symbol, | |
762 | }) | |
763 | } | |
764 | } | |
765 | ||
766 | /// A symbol of a `WasmFile`. | |
767 | #[derive(Clone, Copy, Debug)] | |
768 | pub struct WasmSymbol<'data, 'file> { | |
769 | index: SymbolIndex, | |
770 | symbol: &'file WasmSymbolInternal<'data>, | |
771 | } | |
772 | ||
773 | #[derive(Clone, Debug)] | |
774 | struct WasmSymbolInternal<'data> { | |
775 | name: &'data str, | |
776 | address: u64, | |
777 | size: u64, | |
778 | kind: SymbolKind, | |
779 | section: SymbolSection, | |
780 | scope: SymbolScope, | |
781 | } | |
782 | ||
783 | impl<'data, 'file> read::private::Sealed for WasmSymbol<'data, 'file> {} | |
784 | ||
785 | impl<'data, 'file> ObjectSymbol<'data> for WasmSymbol<'data, 'file> { | |
786 | #[inline] | |
787 | fn index(&self) -> SymbolIndex { | |
788 | self.index | |
789 | } | |
790 | ||
791 | #[inline] | |
792 | fn name_bytes(&self) -> read::Result<&'data [u8]> { | |
793 | Ok(self.symbol.name.as_bytes()) | |
794 | } | |
795 | ||
796 | #[inline] | |
797 | fn name(&self) -> read::Result<&'data str> { | |
798 | Ok(self.symbol.name) | |
799 | } | |
800 | ||
801 | #[inline] | |
802 | fn address(&self) -> u64 { | |
803 | self.symbol.address | |
804 | } | |
805 | ||
806 | #[inline] | |
807 | fn size(&self) -> u64 { | |
808 | self.symbol.size | |
809 | } | |
810 | ||
811 | #[inline] | |
812 | fn kind(&self) -> SymbolKind { | |
813 | self.symbol.kind | |
814 | } | |
815 | ||
816 | #[inline] | |
817 | fn section(&self) -> SymbolSection { | |
818 | self.symbol.section | |
819 | } | |
820 | ||
821 | #[inline] | |
822 | fn is_undefined(&self) -> bool { | |
823 | self.symbol.section == SymbolSection::Undefined | |
824 | } | |
825 | ||
826 | #[inline] | |
827 | fn is_definition(&self) -> bool { | |
828 | self.symbol.kind == SymbolKind::Text && self.symbol.section != SymbolSection::Undefined | |
829 | } | |
830 | ||
831 | #[inline] | |
832 | fn is_common(&self) -> bool { | |
833 | self.symbol.section == SymbolSection::Common | |
834 | } | |
835 | ||
836 | #[inline] | |
837 | fn is_weak(&self) -> bool { | |
838 | false | |
839 | } | |
840 | ||
841 | #[inline] | |
842 | fn scope(&self) -> SymbolScope { | |
843 | self.symbol.scope | |
844 | } | |
845 | ||
846 | #[inline] | |
847 | fn is_global(&self) -> bool { | |
848 | self.symbol.scope != SymbolScope::Compilation | |
849 | } | |
850 | ||
851 | #[inline] | |
852 | fn is_local(&self) -> bool { | |
853 | self.symbol.scope == SymbolScope::Compilation | |
854 | } | |
855 | ||
856 | #[inline] | |
857 | fn flags(&self) -> SymbolFlags<SectionIndex> { | |
858 | SymbolFlags::None | |
859 | } | |
860 | } | |
861 | ||
862 | /// An iterator over the relocations in a `WasmSection`. | |
863 | #[derive(Debug)] | |
864 | pub struct WasmRelocationIterator<'data, 'file, R = &'data [u8]>( | |
865 | PhantomData<(&'data (), &'file (), R)>, | |
866 | ); | |
867 | ||
868 | impl<'data, 'file, R> Iterator for WasmRelocationIterator<'data, 'file, R> { | |
869 | type Item = (u64, Relocation); | |
870 | ||
871 | #[inline] | |
872 | fn next(&mut self) -> Option<Self::Item> { | |
873 | None | |
874 | } | |
875 | } | |
876 | ||
877 | fn section_code_to_id(code: wp::SectionCode) -> usize { | |
878 | match code { | |
879 | wp::SectionCode::Custom { .. } => SECTION_CUSTOM, | |
880 | wp::SectionCode::Type => SECTION_TYPE, | |
881 | wp::SectionCode::Import => SECTION_IMPORT, | |
882 | wp::SectionCode::Function => SECTION_FUNCTION, | |
883 | wp::SectionCode::Table => SECTION_TABLE, | |
884 | wp::SectionCode::Memory => SECTION_MEMORY, | |
885 | wp::SectionCode::Global => SECTION_GLOBAL, | |
886 | wp::SectionCode::Export => SECTION_EXPORT, | |
887 | wp::SectionCode::Start => SECTION_START, | |
888 | wp::SectionCode::Element => SECTION_ELEMENT, | |
889 | wp::SectionCode::Code => SECTION_CODE, | |
890 | wp::SectionCode::Data => SECTION_DATA, | |
891 | wp::SectionCode::DataCount => SECTION_DATA_COUNT, | |
892 | } | |
893 | } |