Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- pub const BLOB_MAGIC: [u8; 4] = [b'P', b'V', b'M', b'\0'];
- pub type BlobLen = u64;
- pub const BLOB_LEN_SIZE: usize = core::mem::size_of::<BlobLen>();
- pub const BLOB_LEN_OFFSET: usize = BLOB_MAGIC.len() + 1;
- pub const SECTION_MEMORY_CONFIG: u8 = 1;
- pub const SECTION_RO_DATA: u8 = 2;
- pub const SECTION_RW_DATA: u8 = 3;
- pub const SECTION_IMPORTS: u8 = 4;
- pub const SECTION_EXPORTS: u8 = 5;
- pub const SECTION_CODE_AND_JUMP_TABLE: u8 = 6;
- pub const SECTION_OPT_DEBUG_STRINGS: u8 = 128;
- pub const SECTION_OPT_DEBUG_LINE_PROGRAMS: u8 = 129;
- pub const SECTION_OPT_DEBUG_LINE_PROGRAM_RANGES: u8 = 130;
- pub const SECTION_END_OF_FILE: u8 = 0;
- pub const BLOB_VERSION_V1_64: u8 = 0;
- pub const BLOB_VERSION_V1_32: u8 = 1;
- pub const VERSION_DEBUG_LINE_PROGRAM_V1: u8 = 1;
- impl<'a> Reader<'a, ArcBytes> {
- fn read_slice_as_bytes(&mut self, length: usize) -> Result<ArcBytes, ProgramParseError> {
- let range = self.read_slice_as_range(length)?;
- Ok(self.blob.subslice(range))
- }
- fn read_section_as_bytes(&mut self, out_section: &mut u8, expected_section: u8) -> Result<ArcBytes, ProgramParseError> {
- if *out_section != expected_section {
- return Ok(ArcBytes::default());
- }
- let section_length = self.read_varint()? as usize;
- let range = self.read_slice_as_range(section_length)?;
- *out_section = self.read_byte()?;
- Ok(self.blob.subslice(range))
- }
- }
- impl ProgramParts {
- pub fn from_bytes(blob: ArcBytes) -> Result<Self, ProgramParseError> {
- if !blob.starts_with(&BLOB_MAGIC) {
- return Err(ProgramParseError(ProgramParseErrorKind::Other(
- "blob doesn't start with the expected magic bytes",
- )));
- }
- let mut reader = Reader {
- blob: &blob,
- position: BLOB_MAGIC.len(),
- };
- let blob_version = reader.read_byte()?;
- let is_64_bit = if blob_version == BLOB_VERSION_V1_32 {
- false
- } else if blob_version == BLOB_VERSION_V1_64 {
- true
- } else {
- return Err(ProgramParseError(ProgramParseErrorKind::UnsupportedVersion {
- version: blob_version,
- }));
- };
- let blob_len = BlobLen::from_le_bytes(reader.read_slice(BLOB_LEN_SIZE)?.try_into().unwrap());
- if blob_len != blob.len() as u64 {
- return Err(ProgramParseError(ProgramParseErrorKind::Other(
- "blob size doesn't match the blob length metadata",
- )));
- }
- let mut parts = ProgramParts {
- is_64_bit,
- ..ProgramParts::default()
- };
- let mut section = reader.read_byte()?;
- if section == SECTION_MEMORY_CONFIG {
- let section_length = reader.read_varint()?;
- let position = reader.position;
- parts.ro_data_size = reader.read_varint()?;
- parts.rw_data_size = reader.read_varint()?;
- parts.stack_size = reader.read_varint()?;
- if position + section_length as usize != reader.position {
- return Err(ProgramParseError(ProgramParseErrorKind::Other(
- "the memory config section contains more data than expected",
- )));
- }
- section = reader.read_byte()?;
- }
- parts.ro_data = reader.read_section_as_bytes(&mut section, SECTION_RO_DATA)?;
- parts.rw_data = reader.read_section_as_bytes(&mut section, SECTION_RW_DATA)?;
- if section == SECTION_IMPORTS {
- let section_length = reader.read_varint()? as usize;
- let section_start = reader.position;
- let import_count = reader.read_varint()?;
- if import_count > VM_MAXIMUM_IMPORT_COUNT {
- return Err(ProgramParseError(ProgramParseErrorKind::Other("too many imports")));
- }
- let Some(import_offsets_size) = import_count.checked_mul(4) else {
- return Err(ProgramParseError(ProgramParseErrorKind::Other("the imports section is invalid")));
- };
- parts.import_offsets = reader.read_slice_as_bytes(import_offsets_size as usize)?;
- let Some(import_symbols_size) = section_length.checked_sub(reader.position - section_start) else {
- return Err(ProgramParseError(ProgramParseErrorKind::Other("the imports section is invalid")));
- };
- parts.import_symbols = reader.read_slice_as_bytes(import_symbols_size)?;
- section = reader.read_byte()?;
- }
- parts.exports = reader.read_section_as_bytes(&mut section, SECTION_EXPORTS)?;
- parts.code_and_jump_table = reader.read_section_as_bytes(&mut section, SECTION_CODE_AND_JUMP_TABLE)?;
- parts.debug_strings = reader.read_section_as_bytes(&mut section, SECTION_OPT_DEBUG_STRINGS)?;
- parts.debug_line_programs = reader.read_section_as_bytes(&mut section, SECTION_OPT_DEBUG_LINE_PROGRAMS)?;
- parts.debug_line_program_ranges = reader.read_section_as_bytes(&mut section, SECTION_OPT_DEBUG_LINE_PROGRAM_RANGES)?;
- while (section & 0b10000000) != 0 {
- // We don't know this section, but it's optional, so just skip it.
- #[cfg(feature = "logging")]
- log::debug!("Skipping unsupported optional section: {}", section);
- let section_length = reader.read_varint()?;
- reader.skip(section_length as usize)?;
- section = reader.read_byte()?;
- }
- if section != SECTION_END_OF_FILE {
- return Err(ProgramParseError(ProgramParseErrorKind::UnexpectedSection {
- offset: reader.position - 1,
- section,
- }));
- }
- Ok(parts)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment