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