1use 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}
37const MAX_SECTION_ID: usize = SectionId::Tag as usize;
39
40#[derive(Debug)]
42pub struct WasmFile<'data, R = &'data [u8]> {
43 data: &'data [u8],
44 has_memory64: bool,
45 sections: Vec<SectionHeader<'data>>,
47 id_sections: Box<[Option<usize>; MAX_SECTION_ID + 1]>,
49 has_debug_symbols: bool,
51 symbols: Vec<WasmSymbolInternal<'data>>,
53 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,
69}
70
71impl<T> ReadError<T> for wasmparser::Result<T> {
72 fn read_error(self, error: &'static str) -> Result<T> {
73 self.map_err(|_| Error(error))
74 }
75}
76
77impl<'data, R: ReadRef<'data>> WasmFile<'data, R> {
78 pub fn parse(data: R) -> Result<Self> {
80 let len = data.len().read_error("Unknown Wasm file size")?;
81 let data = data.read_bytes_at(0, len).read_error("Wasm read failed")?;
82 let parser = wp::Parser::new(0).parse_all(data);
83
84 let mut file = WasmFile {
85 data,
86 has_memory64: false,
87 sections: Vec::new(),
88 id_sections: Default::default(),
89 has_debug_symbols: false,
90 symbols: Vec::new(),
91 entry: 0,
92 marker: PhantomData,
93 };
94
95 let mut main_file_symbol = Some(WasmSymbolInternal {
96 name: "",
97 address: 0,
98 size: 0,
99 kind: SymbolKind::File,
100 section: SymbolSection::None,
101 scope: SymbolScope::Compilation,
102 weak: false,
103 });
104
105 let mut local_func_kinds = Vec::new();
106 let mut entry_func_id = None;
107 let mut code_range_start = 0;
108 let mut code_ranges = Vec::new();
109 let mut imports = None;
110 let mut exports = None;
111 let mut names = None;
112 let mut symbols = None;
113 let mut global_values = Vec::new();
115
116 for payload in parser {
117 let payload = payload.read_error("Invalid Wasm section header")?;
118
119 match payload {
120 wp::Payload::Version { encoding, .. } => {
121 if encoding != wp::Encoding::Module {
122 return Err(Error("Unsupported Wasm encoding"));
123 }
124 }
125 wp::Payload::TypeSection(section) => {
126 file.add_section(SectionId::Type, section.range(), "");
127 }
128 wp::Payload::ImportSection(section) => {
129 file.add_section(SectionId::Import, section.range(), "");
130 imports = Some(section);
131 }
132 wp::Payload::FunctionSection(section) => {
133 file.add_section(SectionId::Function, section.range(), "");
134 local_func_kinds =
135 vec![LocalFunctionKind::Unknown; section.into_iter().count()];
136 }
137 wp::Payload::TableSection(section) => {
138 file.add_section(SectionId::Table, section.range(), "");
139 }
140 wp::Payload::MemorySection(section) => {
141 file.add_section(SectionId::Memory, section.range(), "");
142 for memory in section {
143 let memory = memory.read_error("Couldn't read a memory item")?;
144 file.has_memory64 |= memory.memory64;
145 }
146 }
147 wp::Payload::GlobalSection(section) => {
148 file.add_section(SectionId::Global, section.range(), "");
149 for global in section {
150 let global = global.read_error("Couldn't read a global item")?;
151 let mut address = None;
152 if !global.ty.mutable {
153 let init = global.init_expr.get_operators_reader().read();
155 address = match init.read_error("Couldn't read a global init expr")? {
156 wp::Operator::I32Const { value } => Some(value as u64),
157 wp::Operator::I64Const { value } => Some(value as u64),
158 _ => None,
159 };
160 }
161 global_values.push(address);
162 }
163 }
164 wp::Payload::ExportSection(section) => {
165 file.add_section(SectionId::Export, section.range(), "");
166 exports = Some(section);
167 }
168 wp::Payload::StartSection { func, range, .. } => {
169 file.add_section(SectionId::Start, range, "");
170 entry_func_id = Some(func);
171 }
172 wp::Payload::ElementSection(section) => {
173 file.add_section(SectionId::Element, section.range(), "");
174 }
175 wp::Payload::CodeSectionStart { range, .. } => {
176 code_range_start = range.start;
177 file.add_section(SectionId::Code, range, "");
178 }
179 wp::Payload::CodeSectionEntry(body) => {
180 let range = body.range();
181 let address = range.start as u64 - code_range_start as u64;
182 let size = (range.end - range.start) as u64;
183 code_ranges.push((address, size));
184 }
185 wp::Payload::DataSection(section) => {
186 file.add_section(SectionId::Data, section.range(), "");
187 }
188 wp::Payload::DataCountSection { range, .. } => {
189 file.add_section(SectionId::DataCount, range, "");
190 }
191 wp::Payload::TagSection(section) => {
192 file.add_section(SectionId::Tag, section.range(), "");
193 }
194 wp::Payload::CustomSection(section) => {
195 let name = section.name();
196 let size = section.data().len();
197 let mut range = section.range();
198 range.start = range.end - size;
199 file.add_section(SectionId::Custom, range, name);
200 if name == "name" {
201 let reader = wp::BinaryReader::new(section.data(), section.data_offset());
202 names = Some(wp::NameSectionReader::new(reader));
203 } else if name == "linking" {
204 let reader = wp::BinaryReader::new(section.data(), section.data_offset());
206 let linking = wp::LinkingSectionReader::new(reader)
207 .read_error("Invalid Wasm linking section")?;
208 for subsection in linking {
209 let subsection =
210 subsection.read_error("Invalid Wasm linking subsection")?;
211 if let wp::Linking::SymbolTable(s) = subsection {
212 symbols = Some(s);
213 }
214 }
215 } else if name.starts_with(".debug_") {
216 file.has_debug_symbols = true;
217 }
218 }
219 _ => {}
220 }
221 }
222
223 if let Some(entry_func_id) = entry_func_id {
224 if let Some(range) = code_ranges.get(entry_func_id as usize) {
225 file.entry = range.0;
226 }
227 }
228
229 let mut import_func_names = Vec::new();
230 let mut import_global_names = Vec::new();
231 if let Some(imports) = imports {
232 let mut last_module_name = None;
233
234 for import in imports {
235 let import = import.read_error("Couldn't read an import item")?;
236 let kind = match import.ty {
237 wp::TypeRef::Func(_) => {
238 import_func_names.push(import.name);
239 SymbolKind::Text
240 }
241 wp::TypeRef::Memory(memory) => {
242 file.has_memory64 |= memory.memory64;
243 SymbolKind::Data
244 }
245 wp::TypeRef::Global(_) => {
246 import_global_names.push(import.name);
247 SymbolKind::Data
248 }
249 wp::TypeRef::Table(_) => SymbolKind::Data,
250 wp::TypeRef::Tag(_) => SymbolKind::Unknown,
251 };
252
253 if symbols.is_some() {
254 continue;
257 }
258
259 let module_name = import.module;
260 if last_module_name != Some(module_name) {
261 file.symbols.push(WasmSymbolInternal {
262 name: module_name,
263 address: 0,
264 size: 0,
265 kind: SymbolKind::File,
266 section: SymbolSection::None,
267 scope: SymbolScope::Dynamic,
268 weak: false,
269 });
270 last_module_name = Some(module_name);
271 }
272
273 file.symbols.push(WasmSymbolInternal {
274 name: import.name,
275 address: 0,
276 size: 0,
277 kind,
278 section: SymbolSection::Undefined,
279 scope: SymbolScope::Dynamic,
280 weak: false,
281 });
282 }
283 }
284
285 if let Some(symbols) = symbols {
286 exports = None;
290 names = None;
291
292 for symbol in symbols {
293 let symbol = symbol.read_error("Invalid Wasm linking symbol")?;
294 let flags = match symbol {
295 wp::SymbolInfo::Func { flags, .. } => flags,
296 wp::SymbolInfo::Data { flags, .. } => flags,
297 wp::SymbolInfo::Global { flags, .. } => flags,
298 wp::SymbolInfo::Section { flags, .. } => flags,
299 wp::SymbolInfo::Event { flags, .. } => flags,
300 wp::SymbolInfo::Table { flags, .. } => flags,
301 };
302 let kind = if flags.contains(wp::SymbolFlags::TLS) {
303 SymbolKind::Tls
304 } else {
305 match symbol {
306 wp::SymbolInfo::Func { .. } => SymbolKind::Text,
307 wp::SymbolInfo::Data { .. } => SymbolKind::Data,
308 wp::SymbolInfo::Global { .. } => SymbolKind::Data,
309 wp::SymbolInfo::Section { .. } => SymbolKind::Section,
310 wp::SymbolInfo::Event { .. } => SymbolKind::Unknown,
311 wp::SymbolInfo::Table { .. } => SymbolKind::Data,
312 }
313 };
314 let section = if flags.contains(wp::SymbolFlags::UNDEFINED) {
315 SymbolSection::Undefined
316 } else if flags.contains(wp::SymbolFlags::ABSOLUTE) {
317 SymbolSection::Absolute
318 } else {
319 match symbol {
320 wp::SymbolInfo::Func { .. } => {
321 SymbolSection::Section(SectionIndex(SectionId::Code as usize))
322 }
323 _ => {
324 SymbolSection::Unknown
327 }
328 }
329 };
330 let scope = if flags.contains(wp::SymbolFlags::BINDING_LOCAL) {
331 SymbolScope::Compilation
332 } else if flags.contains(wp::SymbolFlags::VISIBILITY_HIDDEN) {
333 SymbolScope::Linkage
334 } else {
335 SymbolScope::Dynamic
336 };
337 let weak = flags.contains(wp::SymbolFlags::BINDING_WEAK);
338
339 let mut address = 0;
340 let mut size = 0;
341 let name = match symbol {
342 wp::SymbolInfo::Func {
343 index, mut name, ..
344 } => {
345 if let Some(local_index) = index.checked_sub(import_func_names.len() as u32)
346 {
347 if let Some(range) = code_ranges.get(local_index as usize).copied() {
348 address = range.0;
349 size = range.1;
350 }
351 } else {
352 if !flags.contains(wp::SymbolFlags::EXPLICIT_NAME) {
353 name = Some(import_func_names[index as usize]);
354 }
355 }
356 name
357 }
358 wp::SymbolInfo::Data { name, symbol, .. } => {
359 if let Some(symbol) = symbol {
360 address = symbol.offset.into();
363 size = symbol.size.into();
364 }
365 Some(name)
366 }
367 wp::SymbolInfo::Section { .. } => {
368 None
370 }
371 wp::SymbolInfo::Global { name, index, .. } => {
372 if !flags.contains(wp::SymbolFlags::EXPLICIT_NAME) {
373 import_global_names.get(index as usize).copied()
374 } else {
375 name
376 }
377 }
378 wp::SymbolInfo::Event { name, .. } | wp::SymbolInfo::Table { name, .. } => name,
379 };
380
381 file.symbols.push(WasmSymbolInternal {
382 name: name.unwrap_or(""),
383 address,
384 size,
385 kind,
386 section,
387 scope,
388 weak,
389 });
390 }
391 }
392
393 if let Some(exports) = exports {
394 if let Some(main_file_symbol) = main_file_symbol.take() {
395 file.symbols.push(main_file_symbol);
396 }
397
398 for export in exports {
399 let export = export.read_error("Couldn't read an export item")?;
400
401 let (kind, section_idx) = match export.kind {
402 wp::ExternalKind::Func => {
403 if let Some(local_func_id) =
404 export.index.checked_sub(import_func_names.len() as u32)
405 {
406 let local_func_kind = local_func_kinds
407 .get_mut(local_func_id as usize)
408 .read_error("Invalid Wasm export index")?;
409 *local_func_kind = LocalFunctionKind::Exported;
410 }
411 (SymbolKind::Text, SectionId::Code)
412 }
413 wp::ExternalKind::Table
414 | wp::ExternalKind::Memory
415 | wp::ExternalKind::Global => (SymbolKind::Data, SectionId::Data),
416 wp::ExternalKind::Tag => continue,
418 };
419
420 let mut address = 0;
423 let mut size = 0;
424 if export.kind == wp::ExternalKind::Global {
425 if let Some(&Some(x)) = global_values.get(export.index as usize) {
426 address = x;
427 }
428 }
429 if export.kind == wp::ExternalKind::Func {
430 if let Some(local_func_id) =
431 export.index.checked_sub(import_func_names.len() as u32)
432 {
433 if let Some(range) = code_ranges.get(local_func_id as usize) {
434 address = range.0;
435 size = range.1
436 }
437 }
438 }
439
440 file.symbols.push(WasmSymbolInternal {
441 name: export.name,
442 address,
443 size,
444 kind,
445 section: SymbolSection::Section(SectionIndex(section_idx as usize)),
446 scope: SymbolScope::Dynamic,
447 weak: false,
448 });
449 }
450 }
451 if let Some(names) = names {
452 if let Some(main_file_symbol) = main_file_symbol.take() {
453 file.symbols.push(main_file_symbol);
454 }
455 for name in names {
456 let name = name.read_error("Invalid wasm name section")?;
457 let wp::Name::Function(name_map) = name else {
458 continue;
459 };
460 for naming in name_map {
461 let naming = naming.read_error("Couldn't read a function name")?;
462 let Some(local_index) =
463 naming.index.checked_sub(import_func_names.len() as u32)
464 else {
465 continue;
466 };
467 let Some(LocalFunctionKind::Unknown) =
468 local_func_kinds.get(local_index as usize)
469 else {
470 continue;
471 };
472 let Some((address, size)) = code_ranges.get(local_index as usize).copied()
473 else {
474 continue;
475 };
476 file.symbols.push(WasmSymbolInternal {
477 name: naming.name,
478 address,
479 size,
480 kind: SymbolKind::Text,
481 section: SymbolSection::Section(SectionIndex(SectionId::Code as usize)),
482 scope: SymbolScope::Compilation,
483 weak: false,
484 });
485 }
486 }
487 }
488
489 Ok(file)
490 }
491
492 fn add_section(&mut self, id: SectionId, range: Range<usize>, name: &'data str) {
493 let section = SectionHeader { id, range, name };
494 self.id_sections[id as usize] = Some(self.sections.len());
495 self.sections.push(section);
496 }
497}
498
499impl<'data, R> read::private::Sealed for WasmFile<'data, R> {}
500
501impl<'data, R: ReadRef<'data>> Object<'data> for WasmFile<'data, R> {
502 type Segment<'file>
503 = WasmSegment<'data, 'file, R>
504 where
505 Self: 'file,
506 'data: 'file;
507 type SegmentIterator<'file>
508 = WasmSegmentIterator<'data, 'file, R>
509 where
510 Self: 'file,
511 'data: 'file;
512 type Section<'file>
513 = WasmSection<'data, 'file, R>
514 where
515 Self: 'file,
516 'data: 'file;
517 type SectionIterator<'file>
518 = WasmSectionIterator<'data, 'file, R>
519 where
520 Self: 'file,
521 'data: 'file;
522 type Comdat<'file>
523 = WasmComdat<'data, 'file, R>
524 where
525 Self: 'file,
526 'data: 'file;
527 type ComdatIterator<'file>
528 = WasmComdatIterator<'data, 'file, R>
529 where
530 Self: 'file,
531 'data: 'file;
532 type Symbol<'file>
533 = WasmSymbol<'data, 'file>
534 where
535 Self: 'file,
536 'data: 'file;
537 type SymbolIterator<'file>
538 = WasmSymbolIterator<'data, 'file>
539 where
540 Self: 'file,
541 'data: 'file;
542 type SymbolTable<'file>
543 = WasmSymbolTable<'data, 'file>
544 where
545 Self: 'file,
546 'data: 'file;
547 type DynamicRelocationIterator<'file>
548 = NoDynamicRelocationIterator
549 where
550 Self: 'file,
551 'data: 'file;
552
553 #[inline]
554 fn architecture(&self) -> Architecture {
555 if self.has_memory64 {
556 Architecture::Wasm64
557 } else {
558 Architecture::Wasm32
559 }
560 }
561
562 #[inline]
563 fn is_little_endian(&self) -> bool {
564 true
565 }
566
567 #[inline]
568 fn is_64(&self) -> bool {
569 self.has_memory64
570 }
571
572 fn kind(&self) -> ObjectKind {
573 ObjectKind::Unknown
575 }
576
577 fn segments(&self) -> Self::SegmentIterator<'_> {
578 WasmSegmentIterator { file: self }
579 }
580
581 fn section_by_name_bytes<'file>(
582 &'file self,
583 section_name: &[u8],
584 ) -> Option<WasmSection<'data, 'file, R>> {
585 self.sections()
586 .find(|section| section.name_bytes() == Ok(section_name))
587 }
588
589 fn section_by_index(&self, index: SectionIndex) -> Result<WasmSection<'data, '_, R>> {
590 let id_section = self
592 .id_sections
593 .get(index.0)
594 .and_then(|x| *x)
595 .read_error("Invalid Wasm section index")?;
596 let section = self.sections.get(id_section).unwrap();
597 Ok(WasmSection {
598 file: self,
599 section,
600 })
601 }
602
603 fn sections(&self) -> Self::SectionIterator<'_> {
604 WasmSectionIterator {
605 file: self,
606 sections: self.sections.iter(),
607 }
608 }
609
610 fn comdats(&self) -> Self::ComdatIterator<'_> {
611 WasmComdatIterator { file: self }
612 }
613
614 #[inline]
615 fn symbol_by_index(&self, index: SymbolIndex) -> Result<WasmSymbol<'data, '_>> {
616 let symbol = self
617 .symbols
618 .get(index.0)
619 .read_error("Invalid Wasm symbol index")?;
620 Ok(WasmSymbol { index, symbol })
621 }
622
623 fn symbols(&self) -> Self::SymbolIterator<'_> {
624 WasmSymbolIterator {
625 symbols: self.symbols.iter().enumerate(),
626 }
627 }
628
629 fn symbol_table(&self) -> Option<WasmSymbolTable<'data, '_>> {
630 Some(WasmSymbolTable {
631 symbols: &self.symbols,
632 })
633 }
634
635 fn dynamic_symbols(&self) -> Self::SymbolIterator<'_> {
636 WasmSymbolIterator {
637 symbols: [].iter().enumerate(),
638 }
639 }
640
641 #[inline]
642 fn dynamic_symbol_table(&self) -> Option<WasmSymbolTable<'data, '_>> {
643 None
644 }
645
646 #[inline]
647 fn dynamic_relocations(&self) -> Option<NoDynamicRelocationIterator> {
648 None
649 }
650
651 fn imports(&self) -> Result<Vec<Import<'data>>> {
652 Ok(Vec::new())
654 }
655
656 fn exports(&self) -> Result<Vec<Export<'data>>> {
657 Ok(Vec::new())
659 }
660
661 fn has_debug_symbols(&self) -> bool {
662 self.has_debug_symbols
663 }
664
665 fn relative_address_base(&self) -> u64 {
666 0
667 }
668
669 #[inline]
670 fn entry(&self) -> u64 {
671 self.entry
672 }
673
674 #[inline]
675 fn flags(&self) -> FileFlags {
676 FileFlags::None
677 }
678}
679
680#[derive(Debug)]
684pub struct WasmSegmentIterator<'data, 'file, R = &'data [u8]> {
685 #[allow(unused)]
686 file: &'file WasmFile<'data, R>,
687}
688
689impl<'data, 'file, R> Iterator for WasmSegmentIterator<'data, 'file, R> {
690 type Item = WasmSegment<'data, 'file, R>;
691
692 #[inline]
693 fn next(&mut self) -> Option<Self::Item> {
694 None
695 }
696}
697
698#[derive(Debug)]
702pub struct WasmSegment<'data, 'file, R = &'data [u8]> {
703 #[allow(unused)]
704 file: &'file WasmFile<'data, R>,
705}
706
707impl<'data, 'file, R> read::private::Sealed for WasmSegment<'data, 'file, R> {}
708
709impl<'data, 'file, R> ObjectSegment<'data> for WasmSegment<'data, 'file, R> {
710 #[inline]
711 fn address(&self) -> u64 {
712 unreachable!()
713 }
714
715 #[inline]
716 fn size(&self) -> u64 {
717 unreachable!()
718 }
719
720 #[inline]
721 fn align(&self) -> u64 {
722 unreachable!()
723 }
724
725 #[inline]
726 fn file_range(&self) -> (u64, u64) {
727 unreachable!()
728 }
729
730 fn data(&self) -> Result<&'data [u8]> {
731 unreachable!()
732 }
733
734 fn data_range(&self, _address: u64, _size: u64) -> Result<Option<&'data [u8]>> {
735 unreachable!()
736 }
737
738 #[inline]
739 fn name_bytes(&self) -> Result<Option<&[u8]>> {
740 unreachable!()
741 }
742
743 #[inline]
744 fn name(&self) -> Result<Option<&str>> {
745 unreachable!()
746 }
747
748 #[inline]
749 fn flags(&self) -> SegmentFlags {
750 unreachable!()
751 }
752}
753
754#[derive(Debug)]
756pub struct WasmSectionIterator<'data, 'file, R = &'data [u8]> {
757 file: &'file WasmFile<'data, R>,
758 sections: slice::Iter<'file, SectionHeader<'data>>,
759}
760
761impl<'data, 'file, R> Iterator for WasmSectionIterator<'data, 'file, R> {
762 type Item = WasmSection<'data, 'file, R>;
763
764 fn next(&mut self) -> Option<Self::Item> {
765 let section = self.sections.next()?;
766 Some(WasmSection {
767 file: self.file,
768 section,
769 })
770 }
771}
772
773#[derive(Debug)]
777pub struct WasmSection<'data, 'file, R = &'data [u8]> {
778 file: &'file WasmFile<'data, R>,
779 section: &'file SectionHeader<'data>,
780}
781
782impl<'data, 'file, R> read::private::Sealed for WasmSection<'data, 'file, R> {}
783
784impl<'data, 'file, R: ReadRef<'data>> ObjectSection<'data> for WasmSection<'data, 'file, R> {
785 type RelocationIterator = WasmRelocationIterator<'data, 'file, R>;
786
787 #[inline]
788 fn index(&self) -> SectionIndex {
789 SectionIndex(self.section.id as usize)
792 }
793
794 #[inline]
795 fn address(&self) -> u64 {
796 0
797 }
798
799 #[inline]
800 fn size(&self) -> u64 {
801 let range = &self.section.range;
802 (range.end - range.start) as u64
803 }
804
805 #[inline]
806 fn align(&self) -> u64 {
807 1
808 }
809
810 #[inline]
811 fn file_range(&self) -> Option<(u64, u64)> {
812 let range = &self.section.range;
813 Some((range.start as _, range.end as _))
814 }
815
816 #[inline]
817 fn data(&self) -> Result<&'data [u8]> {
818 let range = &self.section.range;
819 self.file
820 .data
821 .read_bytes_at(range.start as u64, range.end as u64 - range.start as u64)
822 .read_error("Invalid Wasm section size or offset")
823 }
824
825 fn data_range(&self, _address: u64, _size: u64) -> Result<Option<&'data [u8]>> {
826 unimplemented!()
827 }
828
829 #[inline]
830 fn compressed_file_range(&self) -> Result<CompressedFileRange> {
831 Ok(CompressedFileRange::none(self.file_range()))
832 }
833
834 #[inline]
835 fn compressed_data(&self) -> Result<CompressedData<'data>> {
836 self.data().map(CompressedData::none)
837 }
838
839 #[inline]
840 fn name_bytes(&self) -> Result<&'data [u8]> {
841 self.name().map(str::as_bytes)
842 }
843
844 #[inline]
845 fn name(&self) -> Result<&'data str> {
846 Ok(match self.section.id {
847 SectionId::Custom => self.section.name,
848 SectionId::Type => "<type>",
849 SectionId::Import => "<import>",
850 SectionId::Function => "<function>",
851 SectionId::Table => "<table>",
852 SectionId::Memory => "<memory>",
853 SectionId::Global => "<global>",
854 SectionId::Export => "<export>",
855 SectionId::Start => "<start>",
856 SectionId::Element => "<element>",
857 SectionId::Code => "<code>",
858 SectionId::Data => "<data>",
859 SectionId::DataCount => "<data_count>",
860 SectionId::Tag => "<tag>",
861 })
862 }
863
864 #[inline]
865 fn segment_name_bytes(&self) -> Result<Option<&[u8]>> {
866 Ok(None)
867 }
868
869 #[inline]
870 fn segment_name(&self) -> Result<Option<&str>> {
871 Ok(None)
872 }
873
874 #[inline]
875 fn kind(&self) -> SectionKind {
876 match self.section.id {
877 SectionId::Custom => match self.section.name {
878 "reloc." | "linking" => SectionKind::Linker,
879 _ => SectionKind::Other,
880 },
881 SectionId::Type => SectionKind::Metadata,
882 SectionId::Import => SectionKind::Linker,
883 SectionId::Function => SectionKind::Metadata,
884 SectionId::Table => SectionKind::UninitializedData,
885 SectionId::Memory => SectionKind::UninitializedData,
886 SectionId::Global => SectionKind::Data,
887 SectionId::Export => SectionKind::Linker,
888 SectionId::Start => SectionKind::Linker,
889 SectionId::Element => SectionKind::Data,
890 SectionId::Code => SectionKind::Text,
891 SectionId::Data => SectionKind::Data,
892 SectionId::DataCount => SectionKind::UninitializedData,
893 SectionId::Tag => SectionKind::Data,
894 }
895 }
896
897 #[inline]
898 fn relocations(&self) -> WasmRelocationIterator<'data, 'file, R> {
899 WasmRelocationIterator(PhantomData)
900 }
901
902 fn relocation_map(&self) -> read::Result<RelocationMap> {
903 RelocationMap::new(self.file, self)
904 }
905
906 #[inline]
907 fn flags(&self) -> SectionFlags {
908 SectionFlags::None
909 }
910}
911
912#[derive(Debug)]
916pub struct WasmComdatIterator<'data, 'file, R = &'data [u8]> {
917 #[allow(unused)]
918 file: &'file WasmFile<'data, R>,
919}
920
921impl<'data, 'file, R> Iterator for WasmComdatIterator<'data, 'file, R> {
922 type Item = WasmComdat<'data, 'file, R>;
923
924 #[inline]
925 fn next(&mut self) -> Option<Self::Item> {
926 None
927 }
928}
929
930#[derive(Debug)]
934pub struct WasmComdat<'data, 'file, R = &'data [u8]> {
935 #[allow(unused)]
936 file: &'file WasmFile<'data, R>,
937}
938
939impl<'data, 'file, R> read::private::Sealed for WasmComdat<'data, 'file, R> {}
940
941impl<'data, 'file, R> ObjectComdat<'data> for WasmComdat<'data, 'file, R> {
942 type SectionIterator = WasmComdatSectionIterator<'data, 'file, R>;
943
944 #[inline]
945 fn kind(&self) -> ComdatKind {
946 unreachable!();
947 }
948
949 #[inline]
950 fn symbol(&self) -> SymbolIndex {
951 unreachable!();
952 }
953
954 #[inline]
955 fn name_bytes(&self) -> Result<&'data [u8]> {
956 unreachable!();
957 }
958
959 #[inline]
960 fn name(&self) -> Result<&'data str> {
961 unreachable!();
962 }
963
964 #[inline]
965 fn sections(&self) -> Self::SectionIterator {
966 unreachable!();
967 }
968}
969
970#[derive(Debug)]
974pub struct WasmComdatSectionIterator<'data, 'file, R = &'data [u8]> {
975 #[allow(unused)]
976 file: &'file WasmFile<'data, R>,
977}
978
979impl<'data, 'file, R> Iterator for WasmComdatSectionIterator<'data, 'file, R> {
980 type Item = SectionIndex;
981
982 fn next(&mut self) -> Option<Self::Item> {
983 None
984 }
985}
986
987#[derive(Debug)]
989pub struct WasmSymbolTable<'data, 'file> {
990 symbols: &'file [WasmSymbolInternal<'data>],
991}
992
993impl<'data, 'file> read::private::Sealed for WasmSymbolTable<'data, 'file> {}
994
995impl<'data, 'file> ObjectSymbolTable<'data> for WasmSymbolTable<'data, 'file> {
996 type Symbol = WasmSymbol<'data, 'file>;
997 type SymbolIterator = WasmSymbolIterator<'data, 'file>;
998
999 fn symbols(&self) -> Self::SymbolIterator {
1000 WasmSymbolIterator {
1001 symbols: self.symbols.iter().enumerate(),
1002 }
1003 }
1004
1005 fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> {
1006 let symbol = self
1007 .symbols
1008 .get(index.0)
1009 .read_error("Invalid Wasm symbol index")?;
1010 Ok(WasmSymbol { index, symbol })
1011 }
1012}
1013
1014#[derive(Debug)]
1016pub struct WasmSymbolIterator<'data, 'file> {
1017 symbols: core::iter::Enumerate<slice::Iter<'file, WasmSymbolInternal<'data>>>,
1018}
1019
1020impl<'data, 'file> Iterator for WasmSymbolIterator<'data, 'file> {
1021 type Item = WasmSymbol<'data, 'file>;
1022
1023 fn next(&mut self) -> Option<Self::Item> {
1024 let (index, symbol) = self.symbols.next()?;
1025 Some(WasmSymbol {
1026 index: SymbolIndex(index),
1027 symbol,
1028 })
1029 }
1030}
1031
1032#[derive(Clone, Copy, Debug)]
1036pub struct WasmSymbol<'data, 'file> {
1037 index: SymbolIndex,
1038 symbol: &'file WasmSymbolInternal<'data>,
1039}
1040
1041#[derive(Clone, Debug)]
1042struct WasmSymbolInternal<'data> {
1043 name: &'data str,
1044 address: u64,
1045 size: u64,
1046 kind: SymbolKind,
1047 section: SymbolSection,
1048 scope: SymbolScope,
1049 weak: bool,
1050}
1051
1052impl<'data, 'file> read::private::Sealed for WasmSymbol<'data, 'file> {}
1053
1054impl<'data, 'file> ObjectSymbol<'data> for WasmSymbol<'data, 'file> {
1055 #[inline]
1056 fn index(&self) -> SymbolIndex {
1057 self.index
1058 }
1059
1060 #[inline]
1061 fn name_bytes(&self) -> read::Result<&'data [u8]> {
1062 Ok(self.symbol.name.as_bytes())
1063 }
1064
1065 #[inline]
1066 fn name(&self) -> read::Result<&'data str> {
1067 Ok(self.symbol.name)
1068 }
1069
1070 #[inline]
1071 fn address(&self) -> u64 {
1072 self.symbol.address
1073 }
1074
1075 #[inline]
1076 fn size(&self) -> u64 {
1077 self.symbol.size
1078 }
1079
1080 #[inline]
1081 fn kind(&self) -> SymbolKind {
1082 self.symbol.kind
1083 }
1084
1085 #[inline]
1086 fn section(&self) -> SymbolSection {
1087 self.symbol.section
1088 }
1089
1090 #[inline]
1091 fn is_undefined(&self) -> bool {
1092 self.symbol.section == SymbolSection::Undefined
1093 }
1094
1095 #[inline]
1096 fn is_definition(&self) -> bool {
1097 (self.symbol.kind == SymbolKind::Text || self.symbol.kind == SymbolKind::Data)
1098 && self.symbol.section != SymbolSection::Undefined
1099 }
1100
1101 #[inline]
1102 fn is_common(&self) -> bool {
1103 self.symbol.section == SymbolSection::Common
1104 }
1105
1106 #[inline]
1107 fn is_weak(&self) -> bool {
1108 self.symbol.weak
1109 }
1110
1111 #[inline]
1112 fn scope(&self) -> SymbolScope {
1113 self.symbol.scope
1114 }
1115
1116 #[inline]
1117 fn is_global(&self) -> bool {
1118 self.symbol.scope != SymbolScope::Compilation
1119 }
1120
1121 #[inline]
1122 fn is_local(&self) -> bool {
1123 self.symbol.scope == SymbolScope::Compilation
1124 }
1125
1126 #[inline]
1127 fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
1128 SymbolFlags::None
1129 }
1130}
1131
1132#[derive(Debug)]
1136pub struct WasmRelocationIterator<'data, 'file, R = &'data [u8]>(
1137 PhantomData<(&'data (), &'file (), R)>,
1138);
1139
1140impl<'data, 'file, R> Iterator for WasmRelocationIterator<'data, 'file, R> {
1141 type Item = (u64, Relocation);
1142
1143 #[inline]
1144 fn next(&mut self) -> Option<Self::Item> {
1145 None
1146 }
1147}