parity_wasm/elements/
name_section.rs

1use crate::io;
2use alloc::string::String;
3
4use super::{
5	index_map::IndexMap, Deserialize, Error, Module, Serialize, Type, VarUint32, VarUint7,
6};
7
8const NAME_TYPE_MODULE: u8 = 0;
9const NAME_TYPE_FUNCTION: u8 = 1;
10const NAME_TYPE_LOCAL: u8 = 2;
11
12/// Debug name information.
13#[derive(Clone, Debug, PartialEq)]
14pub struct NameSection {
15	/// Module name subsection.
16	module: Option<ModuleNameSubsection>,
17
18	/// Function name subsection.
19	functions: Option<FunctionNameSubsection>,
20
21	/// Local name subsection.
22	locals: Option<LocalNameSubsection>,
23}
24
25impl NameSection {
26	/// Creates a new name section.
27	pub fn new(
28		module: Option<ModuleNameSubsection>,
29		functions: Option<FunctionNameSubsection>,
30		locals: Option<LocalNameSubsection>,
31	) -> Self {
32		Self { module, functions, locals }
33	}
34
35	/// Module name subsection of this section.
36	pub fn module(&self) -> Option<&ModuleNameSubsection> {
37		self.module.as_ref()
38	}
39
40	/// Module name subsection of this section (mutable).
41	pub fn module_mut(&mut self) -> &mut Option<ModuleNameSubsection> {
42		&mut self.module
43	}
44
45	/// Functions name subsection of this section.
46	pub fn functions(&self) -> Option<&FunctionNameSubsection> {
47		self.functions.as_ref()
48	}
49
50	/// Functions name subsection of this section (mutable).
51	pub fn functions_mut(&mut self) -> &mut Option<FunctionNameSubsection> {
52		&mut self.functions
53	}
54
55	/// Local name subsection of this section.
56	pub fn locals(&self) -> Option<&LocalNameSubsection> {
57		self.locals.as_ref()
58	}
59
60	/// Local name subsection of this section (mutable).
61	pub fn locals_mut(&mut self) -> &mut Option<LocalNameSubsection> {
62		&mut self.locals
63	}
64}
65
66impl NameSection {
67	/// Deserialize a name section.
68	pub fn deserialize<R: io::Read>(module: &Module, rdr: &mut R) -> Result<Self, Error> {
69		let mut module_name: Option<ModuleNameSubsection> = None;
70		let mut function_names: Option<FunctionNameSubsection> = None;
71		let mut local_names: Option<LocalNameSubsection> = None;
72
73		while let Ok(raw_subsection_type) = VarUint7::deserialize(rdr) {
74			let subsection_type = raw_subsection_type.into();
75			// deserialize the section size
76			let size: usize = VarUint32::deserialize(rdr)?.into();
77
78			match subsection_type {
79				NAME_TYPE_MODULE => {
80					if module_name.is_some() {
81						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION))
82					}
83					module_name = Some(ModuleNameSubsection::deserialize(rdr)?);
84				},
85
86				NAME_TYPE_FUNCTION => {
87					if function_names.is_some() {
88						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION))
89					}
90					function_names = Some(FunctionNameSubsection::deserialize(module, rdr)?);
91				},
92
93				NAME_TYPE_LOCAL => {
94					if local_names.is_some() {
95						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_LOCAL))
96					}
97					local_names = Some(LocalNameSubsection::deserialize(module, rdr)?);
98				},
99
100				_ => {
101					// Consume the entire subsection size and drop it. This allows other sections to still be
102					// consumed if there are any.
103					let mut buf = vec![0; size];
104					rdr.read(&mut buf)?;
105				},
106			};
107		}
108
109		Ok(Self { module: module_name, functions: function_names, locals: local_names })
110	}
111}
112
113impl Serialize for NameSection {
114	type Error = Error;
115
116	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
117		fn serialize_subsection<W: io::Write>(
118			wtr: &mut W,
119			name_type: u8,
120			name_payload: &[u8],
121		) -> Result<(), Error> {
122			VarUint7::from(name_type).serialize(wtr)?;
123			VarUint32::from(name_payload.len()).serialize(wtr)?;
124			wtr.write(name_payload).map_err(Into::into)
125		}
126
127		if let Some(module_name_subsection) = self.module {
128			let mut buffer = vec![];
129			module_name_subsection.serialize(&mut buffer)?;
130			serialize_subsection(wtr, NAME_TYPE_MODULE, &buffer)?;
131		}
132
133		if let Some(function_name_subsection) = self.functions {
134			let mut buffer = vec![];
135			function_name_subsection.serialize(&mut buffer)?;
136			serialize_subsection(wtr, NAME_TYPE_FUNCTION, &buffer)?;
137		}
138
139		if let Some(local_name_subsection) = self.locals {
140			let mut buffer = vec![];
141			local_name_subsection.serialize(&mut buffer)?;
142			serialize_subsection(wtr, NAME_TYPE_LOCAL, &buffer)?;
143		}
144
145		Ok(())
146	}
147}
148
149/// The name of this module.
150#[derive(Clone, Debug, PartialEq)]
151pub struct ModuleNameSubsection {
152	name: String,
153}
154
155impl ModuleNameSubsection {
156	/// Create a new module name section with the specified name.
157	pub fn new<S: Into<String>>(name: S) -> ModuleNameSubsection {
158		ModuleNameSubsection { name: name.into() }
159	}
160
161	/// The name of this module.
162	pub fn name(&self) -> &str {
163		&self.name
164	}
165
166	/// The name of this module (mutable).
167	pub fn name_mut(&mut self) -> &mut String {
168		&mut self.name
169	}
170}
171
172impl Serialize for ModuleNameSubsection {
173	type Error = Error;
174
175	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
176		self.name.serialize(wtr)
177	}
178}
179
180impl Deserialize for ModuleNameSubsection {
181	type Error = Error;
182
183	fn deserialize<R: io::Read>(rdr: &mut R) -> Result<ModuleNameSubsection, Error> {
184		let name = String::deserialize(rdr)?;
185		Ok(ModuleNameSubsection { name })
186	}
187}
188
189/// The names of the functions in this module.
190#[derive(Clone, Debug, Default, PartialEq)]
191pub struct FunctionNameSubsection {
192	names: NameMap,
193}
194
195impl FunctionNameSubsection {
196	/// A map from function indices to names.
197	pub fn names(&self) -> &NameMap {
198		&self.names
199	}
200
201	/// A map from function indices to names (mutable).
202	pub fn names_mut(&mut self) -> &mut NameMap {
203		&mut self.names
204	}
205
206	/// Deserialize names, making sure that all names correspond to functions.
207	pub fn deserialize<R: io::Read>(
208		module: &Module,
209		rdr: &mut R,
210	) -> Result<FunctionNameSubsection, Error> {
211		let names = IndexMap::deserialize(module.functions_space(), rdr)?;
212		Ok(FunctionNameSubsection { names })
213	}
214}
215
216impl Serialize for FunctionNameSubsection {
217	type Error = Error;
218
219	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
220		self.names.serialize(wtr)
221	}
222}
223
224/// The names of the local variables in this module's functions.
225#[derive(Clone, Debug, Default, PartialEq)]
226pub struct LocalNameSubsection {
227	local_names: IndexMap<NameMap>,
228}
229
230impl LocalNameSubsection {
231	/// A map from function indices to a map from variables indices to names.
232	pub fn local_names(&self) -> &IndexMap<NameMap> {
233		&self.local_names
234	}
235
236	/// A map from function indices to a map from variables indices to names
237	/// (mutable).
238	pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> {
239		&mut self.local_names
240	}
241
242	/// Deserialize names, making sure that all names correspond to local
243	/// variables.
244	pub fn deserialize<R: io::Read>(
245		module: &Module,
246		rdr: &mut R,
247	) -> Result<LocalNameSubsection, Error> {
248		let max_entry_space = module.functions_space();
249
250		let max_signature_args = module
251			.type_section()
252			.map(|ts| {
253				ts.types()
254					.iter()
255					.map(|x| {
256						let Type::Function(ref func) = *x;
257						func.params().len()
258					})
259					.max()
260					.unwrap_or(0)
261			})
262			.unwrap_or(0);
263
264		let max_locals = module
265			.code_section()
266			.map(|cs| {
267				cs.bodies()
268					.iter()
269					.map(|f| f.locals().iter().map(|l| l.count() as usize).sum())
270					.max()
271					.unwrap_or(0)
272			})
273			.unwrap_or(0);
274
275		let max_space = max_signature_args + max_locals;
276
277		let deserialize_locals = |_: u32, rdr: &mut R| IndexMap::deserialize(max_space, rdr);
278
279		let local_names = IndexMap::deserialize_with(max_entry_space, &deserialize_locals, rdr)?;
280		Ok(LocalNameSubsection { local_names })
281	}
282}
283
284impl Serialize for LocalNameSubsection {
285	type Error = Error;
286
287	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
288		self.local_names.serialize(wtr)
289	}
290}
291
292/// A map from indices to names.
293pub type NameMap = IndexMap<String>;
294
295#[cfg(test)]
296mod tests {
297	use super::*;
298
299	// A helper function for the tests. Serialize a section, deserialize it,
300	// and make sure it matches the original.
301	fn serialize_test(original: NameSection) -> Vec<u8> {
302		let mut buffer = vec![];
303		original.serialize(&mut buffer).expect("serialize error");
304		buffer
305		// todo: add deserialization to this test
306	}
307
308	#[test]
309	fn serialize_module_name() {
310		let module_name_subsection = ModuleNameSubsection::new("my_mod");
311		let original = NameSection::new(Some(module_name_subsection), None, None);
312		serialize_test(original);
313	}
314
315	#[test]
316	fn serialize_function_names() {
317		let mut function_name_subsection = FunctionNameSubsection::default();
318		function_name_subsection.names_mut().insert(0, "hello_world".to_string());
319		let name_section = NameSection::new(None, Some(function_name_subsection), None);
320		serialize_test(name_section);
321	}
322
323	#[test]
324	fn serialize_local_names() {
325		let mut local_name_subsection = LocalNameSubsection::default();
326		let mut locals = NameMap::default();
327		locals.insert(0, "msg".to_string());
328		local_name_subsection.local_names_mut().insert(0, locals);
329
330		let name_section = NameSection::new(None, None, Some(local_name_subsection));
331		serialize_test(name_section);
332	}
333
334	#[test]
335	fn serialize_all_subsections() {
336		let module_name_subsection = ModuleNameSubsection::new("ModuleNameSubsection");
337
338		let mut function_name_subsection = FunctionNameSubsection::default();
339		function_name_subsection.names_mut().insert(0, "foo".to_string());
340		function_name_subsection.names_mut().insert(1, "bar".to_string());
341
342		let mut local_name_subsection = LocalNameSubsection::default();
343		let mut locals = NameMap::default();
344		locals.insert(0, "msg1".to_string());
345		locals.insert(1, "msg2".to_string());
346		local_name_subsection.local_names_mut().insert(0, locals);
347
348		let name_section = NameSection::new(
349			Some(module_name_subsection),
350			Some(function_name_subsection),
351			Some(local_name_subsection),
352		);
353		serialize_test(name_section);
354	}
355
356	#[test]
357	fn deserialize_local_names() {
358		let module = super::super::deserialize_file("./res/cases/v1/names_with_imports.wasm")
359			.expect("Should be deserialized")
360			.parse_names()
361			.expect("Names to be parsed");
362
363		let name_section = module.names_section().expect("name_section should be present");
364		let local_names = name_section.locals().expect("local_name_section should be present");
365
366		let locals = local_names.local_names().get(0).expect("entry #0 should be present");
367		assert_eq!(locals.get(0).expect("entry #0 should be present"), "abc");
368
369		let locals = local_names.local_names().get(1).expect("entry #1 should be present");
370		assert_eq!(locals.get(0).expect("entry #0 should be present"), "def");
371	}
372}