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