gsym-rs 0.1.0

Pure-Rust reader, writer, and Linux ELF/DWARF converter for LLVM GSYM
Documentation
use crate::endian::{Cursor, Encoder, Endian};
use crate::error::Error;
use crate::format::leb::{
    read_sleb, read_sleb_bounded, read_uleb, read_uleb_bounded, write_sleb, write_uleb,
};

use super::ENDIANS;

#[test]
fn data_extractor_reads_every_integer_width_and_endian() {
    let source = [1_u8, 2, 3, 4, 5, 6, 7, 8];
    let expected_little = [
        0x01,
        0x0201,
        0x0003_0201,
        0x0403_0201,
        0x0005_0403_0201,
        0x0605_0403_0201,
        0x0007_0605_0403_0201,
        0x0807_0605_0403_0201,
    ];
    let expected_big = [
        0x01,
        0x0102,
        0x0001_0203,
        0x0102_0304,
        0x0001_0203_0405,
        0x0102_0304_0506,
        0x0001_0203_0405_0607,
        0x0102_0304_0506_0708,
    ];

    for width in 1..=8 {
        let mut little = Cursor::new(&source, Endian::Little);
        let mut big = Cursor::new(&source, Endian::Big);
        assert_eq!(
            little.read_uint(width).unwrap(),
            expected_little
                .get(usize::from(width - 1))
                .copied()
                .unwrap()
        );
        assert_eq!(
            big.read_uint(width).unwrap(),
            expected_big.get(usize::from(width - 1)).copied().unwrap()
        );
        assert_eq!(little.position(), usize::from(width));
        assert_eq!(big.position(), usize::from(width));
    }

    assert!(Cursor::at(&source, Endian::Little, source.len() + 1).is_err());
    let mut short = Cursor::at(&source, Endian::Little, 7).unwrap();
    assert!(short.read_u16().is_err());
}

#[test]
fn file_writer_round_trips_fixed_width_leb_alignment_and_fixups() {
    for endian in ENDIANS {
        let mut output = Encoder::new(endian);
        output.write_u8(0x10);
        output.write_u16(0x1122);
        output.write_u32(0x1234_5678);
        output.write_u64(0x3344_5566_7788_99aa);
        output.align_to(16).unwrap();
        let fixup = output.len();
        output.write_u32(0);
        write_sleb(&mut output, i64::MIN);
        write_sleb(&mut output, i64::MAX);
        write_uleb(&mut output, 0);
        write_uleb(&mut output, u64::MAX);
        output.patch_u32(fixup, 0x1234_5678).unwrap();

        let mut input = Cursor::new(output.as_slice(), endian);
        assert_eq!(input.read_u8().unwrap(), 0x10);
        assert_eq!(input.read_u16().unwrap(), 0x1122);
        assert_eq!(input.read_u32().unwrap(), 0x1234_5678);
        assert_eq!(input.read_u64().unwrap(), 0x3344_5566_7788_99aa);
        input.take(16 - input.position() % 16).unwrap();
        assert_eq!(input.read_u32().unwrap(), 0x1234_5678);
        assert_eq!(read_sleb(&mut input).unwrap(), i64::MIN);
        assert_eq!(read_sleb(&mut input).unwrap(), i64::MAX);
        assert_eq!(read_uleb(&mut input).unwrap(), 0);
        assert_eq!(read_uleb(&mut input).unwrap(), u64::MAX);
        assert!(input.is_empty());
    }
}

#[test]
fn unsigned_writer_supports_widths_one_through_eight() {
    let values = [
        0x01,
        0x0102,
        0x0001_0203,
        0x0102_0304,
        0x0001_0203_0405,
        0x0102_0304_0506,
        0x0001_0203_0405_0607,
        0x0102_0304_0506_0708,
    ];
    for endian in ENDIANS {
        let mut output = Encoder::new(endian);
        for (index, value) in values.into_iter().enumerate() {
            output
                .write_uint(value, u8::try_from(index + 1).unwrap())
                .unwrap();
        }
        let mut input = Cursor::new(output.as_slice(), endian);
        for (index, value) in values.into_iter().enumerate() {
            assert_eq!(
                input.read_uint(u8::try_from(index + 1).unwrap()).unwrap(),
                value
            );
        }
        assert!(input.is_empty());
        assert!(Encoder::new(endian).write_uint(0x100, 1).is_err());
    }
}

#[test]
fn bounded_leb_rejects_truncation_overflow_and_bad_widths() {
    for endian in ENDIANS {
        let mut unterminated = Cursor::new(&[0x80; 10], endian);
        assert!(matches!(
            read_uleb(&mut unterminated),
            Err(Error::MalformedUleb { .. })
        ));

        let mut too_large = Cursor::new(&[0x80, 0x02], endian);
        assert!(read_uleb_bounded(&mut too_large, 8).is_err());

        let mut signed_too_large = Cursor::new(&[0x80, 0x01], endian);
        assert!(read_sleb_bounded(&mut signed_too_large, 8).is_err());

        let mut value = Cursor::new(&[0], endian);
        assert!(read_uleb_bounded(&mut value, 0).is_err());
        let mut value = Cursor::new(&[0], endian);
        assert!(read_sleb_bounded(&mut value, 65).is_err());
    }
}