1 //! Support for reading Wasm files.
3 //! Provides `WasmFile` and related types which implement the `Object` trait.
5 //! Currently implements the minimum required to access DWARF debugging information.
8 use core
::marker
::PhantomData
;
9 use core
::{slice, str}
;
13 self, Architecture
, ComdatKind
, CompressedData
, Error
, FileFlags
, Object
, ObjectComdat
,
14 ObjectSection
, ObjectSegment
, ObjectSymbol
, ObjectSymbolTable
, ReadError
, Relocation
, Result
,
15 SectionFlags
, SectionIndex
, SectionKind
, SymbolFlags
, SymbolIndex
, SymbolKind
, SymbolScope
,
19 const SECTION_CUSTOM
: usize = 0;
20 const SECTION_TYPE
: usize = 1;
21 const SECTION_IMPORT
: usize = 2;
22 const SECTION_FUNCTION
: usize = 3;
23 const SECTION_TABLE
: usize = 4;
24 const SECTION_MEMORY
: usize = 5;
25 const SECTION_GLOBAL
: usize = 6;
26 const SECTION_EXPORT
: usize = 7;
27 const SECTION_START
: usize = 8;
28 const SECTION_ELEMENT
: usize = 9;
29 const SECTION_CODE
: usize = 10;
30 const SECTION_DATA
: usize = 11;
31 const SECTION_DATA_COUNT
: usize = 12;
32 // Update this constant when adding new section id:
33 const MAX_SECTION_ID
: usize = SECTION_DATA_COUNT
;
35 /// A WebAssembly object file.
36 #[derive(Debug, Default)]
37 pub struct WasmFile
<'data
> {
38 // All sections, including custom sections.
39 sections
: Vec
<wp
::Section
<'data
>>,
40 // Indices into `sections` of sections with a non-zero id.
41 id_sections
: Box
<[Option
<usize>; MAX_SECTION_ID
+ 1]>,
42 // Whether the file has DWARF information.
43 has_debug_symbols
: bool
,
44 // Symbols collected from imports, exports, code and name sections.
45 symbols
: Vec
<WasmSymbolInternal
<'data
>>,
46 // Address of the function body for the entry point.
51 enum LocalFunctionKind
{
53 Exported { symbol_ids: Vec<u32> }
,
54 Local { symbol_id: u32 }
,
57 impl<T
> ReadError
<T
> for wasmparser
::Result
<T
> {
58 fn read_error(self, error
: &'
static str) -> Result
<T
> {
59 self.map_err(|_
| Error(error
))
63 impl<'data
> WasmFile
<'data
> {
64 /// Parse the raw wasm data.
65 pub fn parse(data
: &'data
[u8]) -> Result
<Self> {
66 let module
= wp
::ModuleReader
::new(data
).read_error("Invalid Wasm header")?
;
68 let mut file
= WasmFile
::default();
70 let mut main_file_symbol
= Some(WasmSymbolInternal
{
74 kind
: SymbolKind
::File
,
75 section
: SymbolSection
::None
,
76 scope
: SymbolScope
::Compilation
,
79 let mut imported_funcs_count
= 0;
80 let mut local_func_kinds
= Vec
::new();
81 let mut entry_func_id
= None
;
83 for section
in module
{
84 let section
= section
.read_error("Invalid Wasm section header")?
;
87 wp
::SectionCode
::Import
=> {
88 let mut last_module_name
= None
;
91 .get_import_section_reader()
92 .read_error("Couldn't read header of the import section")?
94 let import
= import
.read_error("Couldn't read an import item")?
;
95 let module_name
= import
.module
;
97 if last_module_name
!= Some(module_name
) {
98 file
.symbols
.push(WasmSymbolInternal
{
102 kind
: SymbolKind
::File
,
103 section
: SymbolSection
::None
,
104 scope
: SymbolScope
::Dynamic
,
106 last_module_name
= Some(module_name
);
109 let kind
= match import
.ty
{
110 wp
::ImportSectionEntryType
::Function(_
) => {
111 imported_funcs_count
+= 1;
114 wp
::ImportSectionEntryType
::Table(_
)
115 | wp
::ImportSectionEntryType
::Memory(_
)
116 | wp
::ImportSectionEntryType
::Global(_
) => SymbolKind
::Data
,
119 file
.symbols
.push(WasmSymbolInternal
{
124 section
: SymbolSection
::Undefined
,
125 scope
: SymbolScope
::Dynamic
,
129 wp
::SectionCode
::Function
=> {
130 local_func_kinds
= vec
![
131 LocalFunctionKind
::Unknown
;
133 .get_function_section_reader()
134 .read_error("Couldn't read header of the function section")?
135 .get_count() as usize
138 wp
::SectionCode
::Export
=> {
139 if let Some(main_file_symbol
) = main_file_symbol
.take() {
140 file
.symbols
.push(main_file_symbol
);
143 for export
in section
144 .get_export_section_reader()
145 .read_error("Couldn't read header of the export section")?
147 let export
= export
.read_error("Couldn't read an export item")?
;
149 let (kind
, section_idx
) = match export
.kind
{
150 wp
::ExternalKind
::Function
=> {
151 if let Some(local_func_id
) =
152 export
.index
.checked_sub(imported_funcs_count
)
154 let local_func_kind
=
155 &mut local_func_kinds
[local_func_id
as usize];
156 if let LocalFunctionKind
::Unknown
= local_func_kind
{
157 *local_func_kind
= LocalFunctionKind
::Exported
{
158 symbol_ids
: Vec
::new(),
161 let symbol_ids
= match local_func_kind
{
162 LocalFunctionKind
::Exported { symbol_ids }
=> symbol_ids
,
165 symbol_ids
.push(file
.symbols
.len() as u32);
167 (SymbolKind
::Text
, SECTION_CODE
)
169 wp
::ExternalKind
::Table
170 | wp
::ExternalKind
::Memory
171 | wp
::ExternalKind
::Global
=> (SymbolKind
::Data
, SECTION_DATA
),
174 file
.symbols
.push(WasmSymbolInternal
{
179 section
: SymbolSection
::Section(SectionIndex(section_idx
)),
180 scope
: SymbolScope
::Dynamic
,
184 wp
::SectionCode
::Start
=> {
185 entry_func_id
= Some(
187 .get_start_section_content()
188 .read_error("Couldn't read contents of the start section")?
,
191 wp
::SectionCode
::Code
=> {
192 if let Some(main_file_symbol
) = main_file_symbol
.take() {
193 file
.symbols
.push(main_file_symbol
);
196 for (i
, (body
, local_func_kind
)) in section
197 .get_code_section_reader()
198 .read_error("Couldn't read header of the code section")?
200 .zip(&mut local_func_kinds
)
203 let body
= body
.read_error("Couldn't read a function body")?
;
204 let range
= body
.range();
206 let address
= range
.start
as u64 - section
.range().start
as u64;
207 let size
= (range
.end
- range
.start
) as u64;
209 if entry_func_id
== Some(i
as u32) {
210 file
.entry
= address
;
213 match local_func_kind
{
214 LocalFunctionKind
::Unknown
=> {
215 *local_func_kind
= LocalFunctionKind
::Local
{
216 symbol_id
: file
.symbols
.len() as u32,
218 file
.symbols
.push(WasmSymbolInternal
{
222 kind
: SymbolKind
::Text
,
223 section
: SymbolSection
::Section(SectionIndex(SECTION_CODE
)),
224 scope
: SymbolScope
::Compilation
,
227 LocalFunctionKind
::Exported { symbol_ids }
=> {
228 for symbol_id
in core
::mem
::replace(symbol_ids
, Vec
::new()) {
229 let export_symbol
= &mut file
.symbols
[symbol_id
as usize];
230 export_symbol
.address
= address
;
231 export_symbol
.size
= size
;
238 wp
::SectionCode
::Custom
{
239 kind
: wp
::CustomSectionKind
::Name
,
243 .get_name_section_reader()
244 .read_error("Couldn't read header of the name section")?
247 match name
.read_error("Couldn't read header of a name subsection")?
{
248 wp
::Name
::Function(name
) => name
,
251 let mut name_map
= name
253 .read_error("Couldn't read header of the function name subsection")?
;
254 for _
in 0..name_map
.get_count() {
255 let naming
= name_map
257 .read_error("Couldn't read a function name")?
;
258 if let Some(local_index
) =
259 naming
.index
.checked_sub(imported_funcs_count
)
261 if let LocalFunctionKind
::Local { symbol_id }
=
262 local_func_kinds
[local_index
as usize]
264 file
.symbols
[symbol_id
as usize].name
= naming
.name
;
270 wp
::SectionCode
::Custom { name, .. }
if name
.starts_with(".debug_") => {
271 file
.has_debug_symbols
= true;
276 let id
= section_code_to_id(section
.code
);
277 file
.id_sections
[id
] = Some(file
.sections
.len());
279 file
.sections
.push(section
);
286 impl<'data
> read
::private
::Sealed
for WasmFile
<'data
> {}
288 impl<'data
, 'file
> Object
<'data
, 'file
> for WasmFile
<'data
>
292 type Segment
= WasmSegment
<'data
, 'file
>;
293 type SegmentIterator
= WasmSegmentIterator
<'data
, 'file
>;
294 type Section
= WasmSection
<'data
, 'file
>;
295 type SectionIterator
= WasmSectionIterator
<'data
, 'file
>;
296 type Comdat
= WasmComdat
<'data
, 'file
>;
297 type ComdatIterator
= WasmComdatIterator
<'data
, 'file
>;
298 type Symbol
= WasmSymbol
<'data
, 'file
>;
299 type SymbolIterator
= WasmSymbolIterator
<'data
, 'file
>;
300 type SymbolTable
= WasmSymbolTable
<'data
, 'file
>;
303 fn architecture(&self) -> Architecture
{
308 fn is_little_endian(&self) -> bool
{
313 fn is_64(&self) -> bool
{
317 fn segments(&'file
self) -> Self::SegmentIterator
{
318 WasmSegmentIterator { file: self }
322 fn entry(&'file
self) -> u64 {
326 fn section_by_name(&'file
self, section_name
: &str) -> Option
<WasmSection
<'data
, 'file
>> {
328 .find(|section
| section
.name() == Ok(section_name
))
331 fn section_by_index(&'file
self, index
: SectionIndex
) -> Result
<WasmSection
<'data
, 'file
>> {
332 // TODO: Missing sections should return an empty section.
333 let id_section
= self
337 .read_error("Invalid Wasm section index")?
;
338 let section
= self.sections
.get(id_section
).unwrap();
339 Ok(WasmSection { section }
)
342 fn sections(&'file
self) -> Self::SectionIterator
{
343 WasmSectionIterator
{
344 sections
: self.sections
.iter(),
348 fn comdats(&'file
self) -> Self::ComdatIterator
{
349 WasmComdatIterator { file: self }
353 fn symbol_by_index(&'file
self, index
: SymbolIndex
) -> Result
<WasmSymbol
<'data
, 'file
>> {
357 .read_error("Invalid Wasm symbol index")?
;
358 Ok(WasmSymbol { index, symbol }
)
361 fn symbols(&'file
self) -> Self::SymbolIterator
{
363 symbols
: self.symbols
.iter().enumerate(),
367 fn symbol_table(&'file
self) -> Option
<WasmSymbolTable
<'data
, 'file
>> {
368 Some(WasmSymbolTable
{
369 symbols
: &self.symbols
,
373 fn dynamic_symbols(&'file
self) -> Self::SymbolIterator
{
375 symbols
: [].iter().enumerate(),
380 fn dynamic_symbol_table(&'file
self) -> Option
<WasmSymbolTable
<'data
, 'file
>> {
384 fn has_debug_symbols(&self) -> bool
{
385 self.has_debug_symbols
389 fn flags(&self) -> FileFlags
{
394 /// An iterator over the segments of a `WasmFile`.
396 pub struct WasmSegmentIterator
<'data
, 'file
> {
397 file
: &'file WasmFile
<'data
>,
400 impl<'data
, 'file
> Iterator
for WasmSegmentIterator
<'data
, 'file
> {
401 type Item
= WasmSegment
<'data
, 'file
>;
404 fn next(&mut self) -> Option
<Self::Item
> {
409 /// A segment of a `WasmFile`.
411 pub struct WasmSegment
<'data
, 'file
> {
412 file
: &'file WasmFile
<'data
>,
415 impl<'data
, 'file
> read
::private
::Sealed
for WasmSegment
<'data
, 'file
> {}
417 impl<'data
, 'file
> ObjectSegment
<'data
> for WasmSegment
<'data
, 'file
> {
419 fn address(&self) -> u64 {
424 fn size(&self) -> u64 {
429 fn align(&self) -> u64 {
434 fn file_range(&self) -> (u64, u64) {
438 fn data(&self) -> Result
<&'data
[u8]> {
442 fn data_range(&self, _address
: u64, _size
: u64) -> Result
<Option
<&'data
[u8]>> {
447 fn name(&self) -> Result
<Option
<&str>> {
452 /// An iterator over the sections of a `WasmFile`.
454 pub struct WasmSectionIterator
<'data
, 'file
> {
455 sections
: slice
::Iter
<'file
, wp
::Section
<'data
>>,
458 impl<'data
, 'file
> Iterator
for WasmSectionIterator
<'data
, 'file
> {
459 type Item
= WasmSection
<'data
, 'file
>;
461 fn next(&mut self) -> Option
<Self::Item
> {
462 let section
= self.sections
.next()?
;
463 Some(WasmSection { section }
)
467 /// A section of a `WasmFile`.
469 pub struct WasmSection
<'data
, 'file
> {
470 section
: &'file wp
::Section
<'data
>,
473 impl<'data
, 'file
> read
::private
::Sealed
for WasmSection
<'data
, 'file
> {}
475 impl<'data
, 'file
> ObjectSection
<'data
> for WasmSection
<'data
, 'file
> {
476 type RelocationIterator
= WasmRelocationIterator
<'data
, 'file
>;
479 fn index(&self) -> SectionIndex
{
480 // Note that we treat all custom sections as index 0.
481 // This is ok because they are never looked up by index.
482 SectionIndex(section_code_to_id(self.section
.code
))
486 fn address(&self) -> u64 {
491 fn size(&self) -> u64 {
492 let range
= self.section
.range();
493 (range
.end
- range
.start
) as u64
497 fn align(&self) -> u64 {
502 fn file_range(&self) -> Option
<(u64, u64)> {
503 let range
= self.section
.range();
504 Some((range
.start
as _
, range
.end
as _
))
508 fn data(&self) -> Result
<&'data
[u8]> {
509 let mut reader
= self.section
.get_binary_reader();
510 // TODO: raise a feature request upstream to be able
511 // to get remaining slice from a BinaryReader directly.
512 Ok(reader
.read_bytes(reader
.bytes_remaining()).unwrap())
515 fn data_range(&self, _address
: u64, _size
: u64) -> Result
<Option
<&'data
[u8]>> {
520 fn compressed_data(&self) -> Result
<CompressedData
<'data
>> {
521 self.data().map(CompressedData
::none
)
525 fn name(&self) -> Result
<&str> {
526 Ok(match self.section
.code
{
527 wp
::SectionCode
::Custom { name, .. }
=> name
,
528 wp
::SectionCode
::Type
=> "<type>",
529 wp
::SectionCode
::Import
=> "<import>",
530 wp
::SectionCode
::Function
=> "<function>",
531 wp
::SectionCode
::Table
=> "<table>",
532 wp
::SectionCode
::Memory
=> "<memory>",
533 wp
::SectionCode
::Global
=> "<global>",
534 wp
::SectionCode
::Export
=> "<export>",
535 wp
::SectionCode
::Start
=> "<start>",
536 wp
::SectionCode
::Element
=> "<element>",
537 wp
::SectionCode
::Code
=> "<code>",
538 wp
::SectionCode
::Data
=> "<data>",
539 wp
::SectionCode
::DataCount
=> "<data_count>",
544 fn segment_name(&self) -> Result
<Option
<&str>> {
549 fn kind(&self) -> SectionKind
{
550 match self.section
.code
{
551 wp
::SectionCode
::Custom { kind, .. }
=> match kind
{
552 wp
::CustomSectionKind
::Reloc
| wp
::CustomSectionKind
::Linking
=> {
555 _
=> SectionKind
::Other
,
557 wp
::SectionCode
::Type
=> SectionKind
::Metadata
,
558 wp
::SectionCode
::Import
=> SectionKind
::Linker
,
559 wp
::SectionCode
::Function
=> SectionKind
::Metadata
,
560 wp
::SectionCode
::Table
=> SectionKind
::UninitializedData
,
561 wp
::SectionCode
::Memory
=> SectionKind
::UninitializedData
,
562 wp
::SectionCode
::Global
=> SectionKind
::Data
,
563 wp
::SectionCode
::Export
=> SectionKind
::Linker
,
564 wp
::SectionCode
::Start
=> SectionKind
::Linker
,
565 wp
::SectionCode
::Element
=> SectionKind
::Data
,
566 wp
::SectionCode
::Code
=> SectionKind
::Text
,
567 wp
::SectionCode
::Data
=> SectionKind
::Data
,
568 wp
::SectionCode
::DataCount
=> SectionKind
::UninitializedData
,
573 fn relocations(&self) -> WasmRelocationIterator
<'data
, 'file
> {
574 WasmRelocationIterator
::default()
578 fn flags(&self) -> SectionFlags
{
583 /// An iterator over the COMDAT section groups of a `WasmFile`.
585 pub struct WasmComdatIterator
<'data
, 'file
> {
586 file
: &'file WasmFile
<'data
>,
589 impl<'data
, 'file
> Iterator
for WasmComdatIterator
<'data
, 'file
> {
590 type Item
= WasmComdat
<'data
, 'file
>;
593 fn next(&mut self) -> Option
<Self::Item
> {
598 /// A COMDAT section group of a `WasmFile`.
600 pub struct WasmComdat
<'data
, 'file
> {
601 file
: &'file WasmFile
<'data
>,
604 impl<'data
, 'file
> read
::private
::Sealed
for WasmComdat
<'data
, 'file
> {}
606 impl<'data
, 'file
> ObjectComdat
<'data
> for WasmComdat
<'data
, 'file
> {
607 type SectionIterator
= WasmComdatSectionIterator
<'data
, 'file
>;
610 fn kind(&self) -> ComdatKind
{
615 fn symbol(&self) -> SymbolIndex
{
620 fn name(&self) -> Result
<&str> {
625 fn sections(&self) -> Self::SectionIterator
{
630 /// An iterator over the sections in a COMDAT section group of a `WasmFile`.
632 pub struct WasmComdatSectionIterator
<'data
, 'file
>
636 file
: &'file WasmFile
<'data
>,
639 impl<'data
, 'file
> Iterator
for WasmComdatSectionIterator
<'data
, 'file
> {
640 type Item
= SectionIndex
;
642 fn next(&mut self) -> Option
<Self::Item
> {
647 /// A symbol table of a `WasmFile`.
649 pub struct WasmSymbolTable
<'data
, 'file
> {
650 symbols
: &'file
[WasmSymbolInternal
<'data
>],
653 impl<'data
, 'file
> read
::private
::Sealed
for WasmSymbolTable
<'data
, 'file
> {}
655 impl<'data
, 'file
> ObjectSymbolTable
<'data
> for WasmSymbolTable
<'data
, 'file
> {
656 type Symbol
= WasmSymbol
<'data
, 'file
>;
657 type SymbolIterator
= WasmSymbolIterator
<'data
, 'file
>;
659 fn symbols(&self) -> Self::SymbolIterator
{
661 symbols
: self.symbols
.iter().enumerate(),
665 fn symbol_by_index(&self, index
: SymbolIndex
) -> Result
<Self::Symbol
> {
669 .read_error("Invalid Wasm symbol index")?
;
670 Ok(WasmSymbol { index, symbol }
)
674 /// An iterator over the symbols of a `WasmFile`.
676 pub struct WasmSymbolIterator
<'data
, 'file
> {
677 symbols
: core
::iter
::Enumerate
<slice
::Iter
<'file
, WasmSymbolInternal
<'data
>>>,
680 impl<'data
, 'file
> Iterator
for WasmSymbolIterator
<'data
, 'file
> {
681 type Item
= WasmSymbol
<'data
, 'file
>;
683 fn next(&mut self) -> Option
<Self::Item
> {
684 let (index
, symbol
) = self.symbols
.next()?
;
686 index
: SymbolIndex(index
),
692 /// A symbol of a `WasmFile`.
693 #[derive(Clone, Copy, Debug)]
694 pub struct WasmSymbol
<'data
, 'file
> {
696 symbol
: &'file WasmSymbolInternal
<'data
>,
699 #[derive(Clone, Debug)]
700 struct WasmSymbolInternal
<'data
> {
705 section
: SymbolSection
,
709 impl<'data
, 'file
> read
::private
::Sealed
for WasmSymbol
<'data
, 'file
> {}
711 impl<'data
, 'file
> ObjectSymbol
<'data
> for WasmSymbol
<'data
, 'file
> {
713 fn index(&self) -> SymbolIndex
{
718 fn name(&self) -> read
::Result
<&'data
str> {
723 fn address(&self) -> u64 {
728 fn size(&self) -> u64 {
733 fn kind(&self) -> SymbolKind
{
738 fn section(&self) -> SymbolSection
{
743 fn is_undefined(&self) -> bool
{
744 self.symbol
.section
== SymbolSection
::Undefined
748 fn is_definition(&self) -> bool
{
749 self.symbol
.kind
== SymbolKind
::Text
&& self.symbol
.section
!= SymbolSection
::Undefined
753 fn is_common(&self) -> bool
{
754 self.symbol
.section
== SymbolSection
::Common
758 fn is_weak(&self) -> bool
{
763 fn scope(&self) -> SymbolScope
{
768 fn is_global(&self) -> bool
{
769 self.symbol
.scope
!= SymbolScope
::Compilation
773 fn is_local(&self) -> bool
{
774 self.symbol
.scope
== SymbolScope
::Compilation
778 fn flags(&self) -> SymbolFlags
<SectionIndex
> {
783 /// An iterator over the relocations in a `WasmSection`.
784 #[derive(Debug, Default)]
785 pub struct WasmRelocationIterator
<'data
, 'file
>(PhantomData
<(&'
data (), &'
file ())>);
787 impl<'data
, 'file
> Iterator
for WasmRelocationIterator
<'data
, 'file
> {
788 type Item
= (u64, Relocation
);
791 fn next(&mut self) -> Option
<Self::Item
> {
796 fn section_code_to_id(code
: wp
::SectionCode
) -> usize {
798 wp
::SectionCode
::Custom { .. }
=> SECTION_CUSTOM
,
799 wp
::SectionCode
::Type
=> SECTION_TYPE
,
800 wp
::SectionCode
::Import
=> SECTION_IMPORT
,
801 wp
::SectionCode
::Function
=> SECTION_FUNCTION
,
802 wp
::SectionCode
::Table
=> SECTION_TABLE
,
803 wp
::SectionCode
::Memory
=> SECTION_MEMORY
,
804 wp
::SectionCode
::Global
=> SECTION_GLOBAL
,
805 wp
::SectionCode
::Export
=> SECTION_EXPORT
,
806 wp
::SectionCode
::Start
=> SECTION_START
,
807 wp
::SectionCode
::Element
=> SECTION_ELEMENT
,
808 wp
::SectionCode
::Code
=> SECTION_CODE
,
809 wp
::SectionCode
::Data
=> SECTION_DATA
,
810 wp
::SectionCode
::DataCount
=> SECTION_DATA_COUNT
,