r2fas 0.2.1

radare2 core plugin that loads FASM -s symbolic dumps for named labels, source lines, and comments
//! Object-file section names from the optional FAS table.

use crate::error::{FasError, Result};
use crate::fas::bytes;
use crate::fas::header::Header;

/// Size of one section-name table entry.
pub const SECTION_ENTRY_SIZE: usize = 4;

/// One section name, indexed exactly as in the generated ELF/COFF object.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SectionName {
    /// One-based section index used by FAS relocation fields.
    pub index: u32,
    /// Offset of the section name in the strings table.
    pub name_offset: u32,
    /// Original section name.
    pub name: String,
}

/// Parse the optional section-name table.
pub fn parse_sections(header: &Header, data: &[u8]) -> Result<Option<Vec<SectionName>>> {
    let Some(raw) = header.section_names(data)? else {
        return Ok(None);
    };
    if raw.len() % SECTION_ENTRY_SIZE != 0 {
        return Err(FasError::Geometry("section names not a multiple of 4"));
    }
    raw.chunks_exact(SECTION_ENTRY_SIZE)
        .enumerate()
        .map(|(index, entry)| {
            let name_offset = bytes::u32_at(entry, 0)?;
            Ok(SectionName {
                index: u32::try_from(index + 1)
                    .map_err(|_| FasError::Geometry("too many sections"))?,
                name_offset,
                name: header.string_at(data, name_offset)?.to_owned(),
            })
        })
        .collect::<Result<Vec<_>>>()
        .map(Some)
}