1 | use crate::{BinaryReader, Result}; |
2 | use core::fmt; |
3 | use core::ops::Range; |
4 | |
5 | /// A reader for custom sections of a WebAssembly module. |
6 | #[derive (Clone)] |
7 | pub struct CustomSectionReader<'a> { |
8 | name: &'a str, |
9 | reader: BinaryReader<'a>, |
10 | } |
11 | |
12 | impl<'a> CustomSectionReader<'a> { |
13 | /// Constructs a new `CustomSectionReader` for the given data and offset. |
14 | pub fn new(mut reader: BinaryReader<'a>) -> Result<CustomSectionReader<'a>> { |
15 | let name = reader.read_string()?; |
16 | Ok(CustomSectionReader { name, reader }) |
17 | } |
18 | |
19 | /// The name of the custom section. |
20 | pub fn name(&self) -> &'a str { |
21 | self.name |
22 | } |
23 | |
24 | /// The offset, relative to the start of the original module or component, |
25 | /// that the `data` payload for this custom section starts at. |
26 | pub fn data_offset(&self) -> usize { |
27 | self.reader.original_position() |
28 | } |
29 | |
30 | /// The actual contents of the custom section. |
31 | pub fn data(&self) -> &'a [u8] { |
32 | self.reader.remaining_buffer() |
33 | } |
34 | |
35 | /// The range of bytes that specify this whole custom section (including |
36 | /// both the name of this custom section and its data) specified in |
37 | /// offsets relative to the start of the byte stream. |
38 | pub fn range(&self) -> Range<usize> { |
39 | self.reader.range() |
40 | } |
41 | |
42 | /// Attempts to match and see if this custom section is statically known to |
43 | /// `wasmparser` with any known section reader. |
44 | /// |
45 | /// This will inspect `self.name()` and return a [`KnownCustom`] if the name |
46 | /// matches a known custom section where there is a parser available for it. |
47 | /// This can also be used as a convenience function for creating such |
48 | /// parsers. |
49 | /// |
50 | /// If the custom section name is not known, or if a reader could not be |
51 | /// created, then `KnownCustom::Unknown` is returned. |
52 | pub fn as_known(&self) -> KnownCustom<'a> { |
53 | match self.name() { |
54 | "name" => KnownCustom::Name(crate::NameSectionReader::new(self.reader.shrink())), |
55 | #[cfg (feature = "component-model" )] |
56 | "component-name" => KnownCustom::ComponentName(crate::ComponentNameSectionReader::new( |
57 | self.reader.shrink(), |
58 | )), |
59 | "metadata.code.branch_hint" => { |
60 | match crate::BranchHintSectionReader::new(self.reader.shrink()) { |
61 | Ok(s) => KnownCustom::BranchHints(s), |
62 | Err(_) => KnownCustom::Unknown, |
63 | } |
64 | } |
65 | "producers" => match crate::ProducersSectionReader::new(self.reader.shrink()) { |
66 | Ok(s) => KnownCustom::Producers(s), |
67 | Err(_) => KnownCustom::Unknown, |
68 | }, |
69 | "dylink.0" => { |
70 | KnownCustom::Dylink0(crate::Dylink0SectionReader::new(self.reader.shrink())) |
71 | } |
72 | "core" => match crate::CoreDumpSection::new(self.reader.shrink()) { |
73 | Ok(s) => KnownCustom::CoreDump(s), |
74 | Err(_) => KnownCustom::Unknown, |
75 | }, |
76 | "coremodules" => match crate::CoreDumpModulesSection::new(self.reader.shrink()) { |
77 | Ok(s) => KnownCustom::CoreDumpModules(s), |
78 | Err(_) => KnownCustom::Unknown, |
79 | }, |
80 | "coreinstances" => match crate::CoreDumpInstancesSection::new(self.reader.shrink()) { |
81 | Ok(s) => KnownCustom::CoreDumpInstances(s), |
82 | Err(_) => KnownCustom::Unknown, |
83 | }, |
84 | "corestack" => match crate::CoreDumpStackSection::new(self.reader.shrink()) { |
85 | Ok(s) => KnownCustom::CoreDumpStack(s), |
86 | Err(_) => KnownCustom::Unknown, |
87 | }, |
88 | "linking" => match crate::LinkingSectionReader::new(self.reader.shrink()) { |
89 | Ok(s) => KnownCustom::Linking(s), |
90 | Err(_) => KnownCustom::Unknown, |
91 | }, |
92 | s if s.starts_with("reloc." ) => { |
93 | match crate::RelocSectionReader::new(self.reader.shrink()) { |
94 | Ok(s) => KnownCustom::Reloc(s), |
95 | Err(_) => KnownCustom::Unknown, |
96 | } |
97 | } |
98 | _ => KnownCustom::Unknown, |
99 | } |
100 | } |
101 | } |
102 | |
103 | /// Return value of [`CustomSectionReader::as_known`]. |
104 | /// |
105 | /// Note that this is `#[non_exhaustive]` because depending on crate features |
106 | /// this enumeration will different entries. |
107 | #[allow (missing_docs)] |
108 | #[non_exhaustive ] |
109 | pub enum KnownCustom<'a> { |
110 | Name(crate::NameSectionReader<'a>), |
111 | #[cfg (feature = "component-model" )] |
112 | ComponentName(crate::ComponentNameSectionReader<'a>), |
113 | BranchHints(crate::BranchHintSectionReader<'a>), |
114 | Producers(crate::ProducersSectionReader<'a>), |
115 | Dylink0(crate::Dylink0SectionReader<'a>), |
116 | CoreDump(crate::CoreDumpSection<'a>), |
117 | CoreDumpStack(crate::CoreDumpStackSection<'a>), |
118 | CoreDumpInstances(crate::CoreDumpInstancesSection), |
119 | CoreDumpModules(crate::CoreDumpModulesSection<'a>), |
120 | Linking(crate::LinkingSectionReader<'a>), |
121 | Reloc(crate::RelocSectionReader<'a>), |
122 | Unknown, |
123 | } |
124 | |
125 | impl<'a> fmt::Debug for CustomSectionReader<'a> { |
126 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
127 | f&mut DebugStruct<'_, '_>.debug_struct("CustomSectionReader" ) |
128 | .field("name" , &self.name) |
129 | .field("data_offset" , &self.data_offset()) |
130 | .field("data" , &"..." ) |
131 | .field(name:"range" , &self.range()) |
132 | .finish() |
133 | } |
134 | } |
135 | |