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