فهرست منبع

disassembler - use object crate to parse bytecode

bidhan-a 1 ماه پیش
والد
کامیت
15f1d205d9

+ 1 - 0
crates/disassembler/Cargo.toml

@@ -15,6 +15,7 @@ name = "sbpf_disassembler"
 [dependencies]
 anyhow = { workspace = true }
 hex = "0.4.3"
+object = "0.37.3"
 thiserror = "2.0.17"
 serde = { version = "1.0.228", features = ["derive"] }
 serde_json = "1.0.145"

+ 0 - 222
crates/disassembler/src/cursor.rs

@@ -1,222 +0,0 @@
-use std::io::{Cursor, Read, Seek, SeekFrom};
-
-use crate::{
-    elf_header::{
-        E_MACHINE, E_MACHINE_SBPF, E_TYPE, E_VERSION, EI_ABIVERSION, EI_CLASS, EI_DATA, EI_MAGIC,
-        EI_OSABI, EI_PAD, EI_VERSION, ELFHeader,
-    },
-    errors::EZBpfError,
-    instructions::Ix,
-    opcodes::OpCode,
-    program_header::{ProgramFlags, ProgramHeader, ProgramType},
-    section_header::{SectionHeader, SectionHeaderType},
-};
-
-pub trait ELFCursor {
-    fn read_elf_header(&mut self) -> Result<ELFHeader, EZBpfError>;
-    fn read_program_header(&mut self) -> Result<ProgramHeader, EZBpfError>;
-    fn read_section_header(&mut self) -> Result<SectionHeader, EZBpfError>;
-    fn read_ix(&mut self) -> Result<Ix, EZBpfError>;
-    fn read_lddw_imm(&mut self) -> Result<i64, EZBpfError>;
-    fn read_u8(&mut self) -> Result<u8, EZBpfError>;
-    fn read_i16(&mut self) -> Result<i16, EZBpfError>;
-    fn read_u16(&mut self) -> Result<u16, EZBpfError>;
-    fn read_i32(&mut self) -> Result<i32, EZBpfError>;
-    fn read_u32(&mut self) -> Result<u32, EZBpfError>;
-    fn read_u64(&mut self) -> Result<u64, EZBpfError>;
-    fn read_bytes(&mut self, l: usize) -> Result<Vec<u8>, EZBpfError>;
-    fn remainder(&mut self) -> u64;
-}
-
-impl ELFCursor for Cursor<&[u8]> {
-    fn read_elf_header(&mut self) -> Result<ELFHeader, EZBpfError> {
-        let ei_magic = self.read_u32()?.to_le_bytes();
-        let ei_class = self.read_u8()?;
-        let ei_data = self.read_u8()?;
-        let ei_version = self.read_u8()?;
-        let ei_osabi = self.read_u8()?;
-        let ei_abiversion = self.read_u8()?;
-        let mut ei_pad = [0u8; 7];
-        ei_pad.clone_from_slice(&self.read_bytes(7)?);
-        let e_type = self.read_u16()?;
-        let e_machine = self.read_u16()?;
-        let e_version = self.read_u32()?;
-        if ei_magic.ne(&EI_MAGIC)
-            || ei_class.ne(&EI_CLASS)
-            || ei_data.ne(&EI_DATA)
-            || ei_version.ne(&EI_VERSION)
-            || ei_osabi.ne(&EI_OSABI)
-            || ei_abiversion.ne(&EI_ABIVERSION)
-            || ei_pad.ne(&EI_PAD)
-            || e_type.ne(&E_TYPE)
-            || (e_machine.ne(&E_MACHINE) && e_machine.ne(&E_MACHINE_SBPF))
-            || e_version.ne(&E_VERSION)
-        {
-            return Err(EZBpfError::NonStandardElfHeader);
-        }
-
-        let e_entry = self.read_u64()?;
-        let e_phoff = self.read_u64()?;
-        let e_shoff = self.read_u64()?;
-        let e_flags = self.read_u32()?;
-        let e_ehsize = self.read_u16()?;
-        let e_phentsize = self.read_u16()?;
-        let e_phnum = self.read_u16()?;
-        let e_shentsize = self.read_u16()?;
-        let e_shnum = self.read_u16()?;
-        let e_shstrndx = self.read_u16()?;
-        Ok(ELFHeader {
-            ei_magic,
-            ei_class,
-            ei_data,
-            ei_version,
-            ei_osabi,
-            ei_abiversion,
-            ei_pad,
-            e_type,
-            e_machine,
-            e_version,
-            e_entry,
-            e_phoff,
-            e_shoff,
-            e_flags,
-            e_ehsize,
-            e_phentsize,
-            e_phnum,
-            e_shentsize,
-            e_shnum,
-            e_shstrndx,
-        })
-    }
-
-    fn read_program_header(&mut self) -> Result<ProgramHeader, EZBpfError> {
-        let p_type = ProgramType::try_from(self.read_u32()?)?;
-        let p_flags = ProgramFlags::from(self.read_u32()?);
-        let p_offset = self.read_u64()?;
-        let p_vaddr = self.read_u64()?;
-        let p_paddr = self.read_u64()?;
-        let p_filesz = self.read_u64()?;
-        let p_memsz = self.read_u64()?;
-        let p_align = self.read_u64()?;
-        Ok(ProgramHeader {
-            p_type,
-            p_flags,
-            p_offset,
-            p_vaddr,
-            p_paddr,
-            p_filesz,
-            p_memsz,
-            p_align,
-        })
-    }
-
-    fn read_section_header(&mut self) -> Result<SectionHeader, EZBpfError> {
-        let sh_name = self.read_u32()?;
-        let sh_type = SectionHeaderType::try_from(self.read_u32()?)?;
-        let sh_flags = self.read_u64()?;
-        let sh_addr = self.read_u64()?;
-        let sh_offset = self.read_u64()?;
-        let sh_size = self.read_u64()?;
-        let sh_link = self.read_u32()?;
-        let sh_info = self.read_u32()?;
-        let sh_addralign = self.read_u64()?;
-        let sh_entsize = self.read_u64()?;
-        Ok(SectionHeader {
-            sh_name,
-            sh_type,
-            sh_flags,
-            sh_addr,
-            sh_offset,
-            sh_size,
-            sh_link,
-            sh_info,
-            sh_addralign,
-            sh_entsize,
-        })
-    }
-
-    fn read_u8(&mut self) -> Result<u8, EZBpfError> {
-        let mut b = [0u8];
-        self.read_exact(&mut b)
-            .map_err(|_| EZBpfError::CursorError)?;
-        Ok(b[0])
-    }
-
-    fn read_u16(&mut self) -> Result<u16, EZBpfError> {
-        let mut b = [0u8; 2];
-        self.read_exact(&mut b)
-            .map_err(|_| EZBpfError::CursorError)?;
-        Ok(u16::from_le_bytes(b))
-    }
-
-    fn read_i16(&mut self) -> Result<i16, EZBpfError> {
-        let mut b = [0u8; 2];
-        self.read_exact(&mut b)
-            .map_err(|_| EZBpfError::CursorError)?;
-        Ok(i16::from_le_bytes(b))
-    }
-
-    fn read_u32(&mut self) -> Result<u32, EZBpfError> {
-        let mut b = [0u8; 4];
-        self.read_exact(&mut b)
-            .map_err(|_| EZBpfError::CursorError)?;
-        Ok(u32::from_le_bytes(b))
-    }
-
-    fn read_i32(&mut self) -> Result<i32, EZBpfError> {
-        let mut b = [0u8; 4];
-        self.read_exact(&mut b)
-            .map_err(|_| EZBpfError::CursorError)?;
-        Ok(i32::from_le_bytes(b))
-    }
-
-    fn read_u64(&mut self) -> Result<u64, EZBpfError> {
-        let mut b = [0u8; 8];
-        self.read_exact(&mut b)
-            .map_err(|_| EZBpfError::CursorError)?;
-        Ok(u64::from_le_bytes(b))
-    }
-
-    fn read_lddw_imm(&mut self) -> Result<i64, EZBpfError> {
-        let mut b = [0u8; 8];
-        b[0..4].clone_from_slice(&self.read_bytes(4)?);
-        if self.read_u32()? != 0 {
-            return Err(EZBpfError::InvalidImmediate);
-        }
-        b[4..8].clone_from_slice(&self.read_bytes(4)?);
-        Ok(i64::from_le_bytes(b))
-    }
-
-    fn read_ix(&mut self) -> Result<Ix, EZBpfError> {
-        let op = OpCode::try_from(self.read_u8()?)?;
-        let reg = self.read_u8()?;
-        let src = reg >> 4;
-        let dst = reg & 0x0f;
-        let off = self.read_i16()?;
-        let imm = match op {
-            OpCode::Lddw => self.read_lddw_imm()?,
-            _ => self.read_i32()? as i64,
-        };
-        Ok(Ix {
-            op,
-            src,
-            dst,
-            off,
-            imm,
-        })
-    }
-
-    fn read_bytes(&mut self, l: usize) -> Result<Vec<u8>, EZBpfError> {
-        let mut v = vec![0_u8; l];
-        self.read_exact(&mut v)
-            .map_err(|_| EZBpfError::CursorError)?;
-        Ok(v)
-    }
-
-    fn remainder(&mut self) -> u64 {
-        let pos = self.position();
-        let end = self.seek(SeekFrom::End(0)).unwrap();
-        self.seek(SeekFrom::Start(pos)).unwrap();
-        end - pos
-    }
-}

+ 79 - 19
crates/disassembler/src/elf_header.rs

@@ -1,9 +1,10 @@
-use std::io::Cursor;
 use std::str;
 
+use object::Endianness;
+use object::read::elf::ElfFile64;
 use serde::{Deserialize, Serialize, Serializer};
 
-use crate::{cursor::ELFCursor, errors::EZBpfError};
+use crate::errors::EZBpfError;
 
 pub const EI_MAGIC: [u8; 4] = *b"\x7fELF"; // ELF magic
 pub const EI_CLASS: u8 = 0x02; // 64-bit
@@ -51,9 +52,62 @@ pub struct ELFHeader {
 }
 
 impl ELFHeader {
-    pub fn from_bytes(b: &[u8]) -> Result<Self, EZBpfError> {
-        let mut c = Cursor::new(b);
-        c.read_elf_header()
+    pub fn from_elf_file(elf_file: &ElfFile64<Endianness>) -> Result<Self, EZBpfError> {
+        let endian = elf_file.endian();
+        let elf_header = elf_file.elf_header();
+
+        // Extract ELF header fields.
+        let e_ident = elf_header.e_ident;
+        let e_type = elf_header.e_type.get(endian);
+        let e_machine = elf_header.e_machine.get(endian);
+        let e_version = elf_header.e_version.get(endian);
+        let e_entry = elf_header.e_entry.get(endian);
+        let e_phoff = elf_header.e_phoff.get(endian);
+        let e_shoff = elf_header.e_shoff.get(endian);
+        let e_flags = elf_header.e_flags.get(endian);
+        let e_ehsize = elf_header.e_ehsize.get(endian);
+        let e_phentsize = elf_header.e_phentsize.get(endian);
+        let e_phnum = elf_header.e_phnum.get(endian);
+        let e_shentsize = elf_header.e_shentsize.get(endian);
+        let e_shnum = elf_header.e_shnum.get(endian);
+        let e_shstrndx = elf_header.e_shstrndx.get(endian);
+
+        // Validate ELF header fields.
+        if e_ident.magic.ne(&EI_MAGIC)
+            || e_ident.class.ne(&EI_CLASS)
+            || e_ident.data.ne(&EI_DATA)
+            || e_ident.version.ne(&EI_VERSION)
+            || e_ident.os_abi.ne(&EI_OSABI)
+            || e_ident.abi_version.ne(&EI_ABIVERSION)
+            || e_ident.padding.ne(&EI_PAD)
+            || (e_machine.ne(&E_MACHINE) && e_machine.ne(&E_MACHINE_SBPF))
+            || e_version.ne(&E_VERSION)
+        {
+            return Err(EZBpfError::NonStandardElfHeader);
+        }
+
+        Ok(ELFHeader {
+            ei_magic: e_ident.magic,
+            ei_class: e_ident.class,
+            ei_data: e_ident.data,
+            ei_version: e_ident.version,
+            ei_osabi: e_ident.os_abi,
+            ei_abiversion: e_ident.abi_version,
+            ei_pad: e_ident.padding,
+            e_type,
+            e_machine,
+            e_version,
+            e_entry,
+            e_phoff,
+            e_shoff,
+            e_flags,
+            e_ehsize,
+            e_phentsize,
+            e_phnum,
+            e_shentsize,
+            e_shnum,
+            e_shstrndx,
+        })
     }
 
     pub fn to_bytes(&self) -> Vec<u8> {
@@ -87,23 +141,29 @@ impl ELFHeader {
 mod tests {
     use hex_literal::hex;
 
-    use super::ELFHeader;
+    use crate::elf_header::{
+        E_MACHINE, E_MACHINE_SBPF, E_TYPE, E_VERSION, EI_ABIVERSION, EI_CLASS, EI_DATA, EI_MAGIC,
+        EI_OSABI, EI_PAD, EI_VERSION,
+    };
+    use crate::program::Program;
 
     #[test]
-    fn serialize_e2e() {
-        let b = hex!(
-            "7F454C460201010000000000000000000300F7000100000078000000000000004000000000000000900000000000000000000000400038000100400003000200"
-        );
-        let h = ELFHeader::from_bytes(&b).unwrap();
-        assert_eq!(h.to_bytes(), &b)
-    }
+    fn test_elf_header() {
+        let program = Program::from_bytes(&hex!("7F454C460201010000000000000000000300F700010000002001000000000000400000000000000028020000000000000000000040003800030040000600050001000000050000002001000000000000200100000000000020010000000000003000000000000000300000000000000000100000000000000100000004000000C001000000000000C001000000000000C0010000000000003C000000000000003C000000000000000010000000000000020000000600000050010000000000005001000000000000500100000000000070000000000000007000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007912A000000000007911182900000000B7000000010000002D21010000000000B70000000000000095000000000000001E0000000000000004000000000000000600000000000000C0010000000000000B0000000000000018000000000000000500000000000000F0010000000000000A000000000000000C00000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000120001002001000000000000300000000000000000656E747279706F696E7400002E74657874002E64796E737472002E64796E73796D002E64796E616D6963002E73687374727461620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000600000000000000200100000000000020010000000000003000000000000000000000000000000008000000000000000000000000000000170000000600000003000000000000005001000000000000500100000000000070000000000000000400000000000000080000000000000010000000000000000F0000000B0000000200000000000000C001000000000000C001000000000000300000000000000004000000010000000800000000000000180000000000000007000000030000000200000000000000F001000000000000F0010000000000000C00000000000000000000000000000001000000000000000000000000000000200000000300000000000000000000000000000000000000FC010000000000002A00000000000000000000000000000001000000000000000000000000000000")).unwrap();
 
-    #[test]
-    fn serialize_sbpf_machine_e2e() {
-        let b = hex!(
-            "7F454C46020101000000000000000000030007010100000020010000000000004000000000000000680200000000000000000000400038000300400006000500"
+        // Verify ELF header fields match expected constants.
+        assert_eq!(program.elf_header.ei_magic, EI_MAGIC);
+        assert_eq!(program.elf_header.ei_class, EI_CLASS);
+        assert_eq!(program.elf_header.ei_data, EI_DATA);
+        assert_eq!(program.elf_header.ei_version, EI_VERSION);
+        assert_eq!(program.elf_header.ei_osabi, EI_OSABI);
+        assert_eq!(program.elf_header.ei_abiversion, EI_ABIVERSION);
+        assert_eq!(program.elf_header.ei_pad, EI_PAD);
+        assert_eq!(program.elf_header.e_type, E_TYPE);
+        assert!(
+            program.elf_header.e_machine == E_MACHINE
+                || program.elf_header.e_machine == E_MACHINE_SBPF
         );
-        let h = ELFHeader::from_bytes(&b).unwrap();
-        assert_eq!(h.to_bytes(), &b)
+        assert_eq!(program.elf_header.e_version, E_VERSION);
     }
 }

+ 0 - 2
crates/disassembler/src/errors.rs

@@ -2,8 +2,6 @@ use thiserror::Error;
 
 #[derive(Debug, Error)]
 pub enum EZBpfError {
-    #[error("Failed to read from cursor")]
-    CursorError,
     #[error("Non-standard ELF header")]
     NonStandardElfHeader,
     #[error("Invalid Program Type")]

+ 36 - 5
crates/disassembler/src/instructions.rs

@@ -1,8 +1,6 @@
-use std::io::Cursor;
-
 use serde::{Deserialize, Serialize};
 
-use crate::{cursor::ELFCursor, errors::EZBpfError, opcodes::OpCode};
+use crate::{errors::EZBpfError, opcodes::OpCode};
 
 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
 pub struct Ix {
@@ -41,8 +39,41 @@ impl Ix {
 
 impl Ix {
     pub fn from_bytes(b: &[u8]) -> Result<Self, EZBpfError> {
-        let mut c = Cursor::new(b);
-        c.read_ix()
+        if b.len() < 8 {
+            return Err(EZBpfError::InvalidDataLength);
+        }
+
+        let op = OpCode::try_from(b[0])?;
+        let reg = b[1];
+        let src = reg >> 4;
+        let dst = reg & 0x0f;
+        let off = i16::from_le_bytes([b[2], b[3]]);
+
+        let imm = match op {
+            OpCode::Lddw => {
+                if b.len() < 16 {
+                    return Err(EZBpfError::InvalidDataLength);
+                }
+                let mut imm_bytes = [0u8; 8];
+                imm_bytes[0..4].copy_from_slice(&b[4..8]);
+
+                if u32::from_le_bytes([b[8], b[9], b[10], b[11]]) != 0 {
+                    return Err(EZBpfError::InvalidImmediate);
+                }
+
+                imm_bytes[4..8].copy_from_slice(&b[12..16]);
+                i64::from_le_bytes(imm_bytes)
+            }
+            _ => i32::from_le_bytes([b[4], b[5], b[6], b[7]]) as i64,
+        };
+
+        Ok(Ix {
+            op,
+            src,
+            dst,
+            off,
+            imm,
+        })
     }
 
     pub fn to_bytes(&self) -> Vec<u8> {

+ 0 - 1
crates/disassembler/src/lib.rs

@@ -1,4 +1,3 @@
-pub mod cursor;
 pub mod elf_header;
 pub mod errors;
 pub mod instructions;

+ 12 - 39
crates/disassembler/src/program.rs

@@ -1,10 +1,9 @@
-use std::io::Cursor;
-
-use anyhow::Result;
+use object::Endianness;
+use object::read::elf::ElfFile64;
 use serde::{Deserialize, Serialize};
 
 use crate::{
-    cursor::ELFCursor, elf_header::ELFHeader, errors::EZBpfError, program_header::ProgramHeader,
+    elf_header::ELFHeader, errors::EZBpfError, program_header::ProgramHeader,
     section_header::SectionHeader, section_header_entry::SectionHeaderEntry,
 };
 
@@ -18,46 +17,20 @@ pub struct Program {
 
 impl Program {
     pub fn from_bytes(b: &[u8]) -> Result<Self, EZBpfError> {
-        let mut c = Cursor::new(b);
-        let elf_header = c.read_elf_header()?;
-
-        c.set_position(elf_header.e_phoff);
-        let program_headers = (0..elf_header.e_phnum)
-            .map(|_| c.read_program_header())
-            .collect::<Result<Vec<_>, _>>()?;
-        c.set_position(elf_header.e_shoff);
-        let section_headers = (0..elf_header.e_shnum)
-            .map(|_| c.read_section_header())
-            .collect::<Result<Vec<_>, _>>()?;
-
-        let shstrndx = &section_headers[elf_header.e_shstrndx as usize];
-        let shstrndx_value = b
-            [shstrndx.sh_offset as usize..shstrndx.sh_offset as usize + shstrndx.sh_size as usize]
-            .to_vec();
-
-        let mut indices: Vec<u32> = section_headers.iter().map(|h| h.sh_name).collect();
-        indices.push(shstrndx.sh_size as u32);
-        indices.sort_unstable();
+        let elf_file =
+            ElfFile64::<Endianness>::parse(b).map_err(|_| EZBpfError::NonStandardElfHeader)?;
 
-        let section_header_entries = section_headers
-            .iter()
-            .map(|s| {
-                let current_offset = s.sh_name as usize;
-                let next_index = indices.binary_search(&s.sh_name).unwrap() + 1;
-                let next_offset =
-                    *indices.get(next_index).ok_or(EZBpfError::InvalidString)? as usize;
+        // Parse elf header.
+        let elf_header = ELFHeader::from_elf_file(&elf_file)?;
 
-                let label = String::from_utf8(shstrndx_value[current_offset..next_offset].to_vec())
-                    .unwrap_or("default".to_string());
-                let data =
-                    b[s.sh_offset as usize..s.sh_offset as usize + s.sh_size as usize].to_vec();
+        // Parse program headers.
+        let program_headers = ProgramHeader::from_elf_file(&elf_file)?;
 
-                SectionHeaderEntry::new(label, s.sh_offset as usize, data)
-            })
-            .collect::<Result<Vec<_>, _>>()?;
+        // Parse section headers and section header entries.
+        let (section_headers, section_header_entries) = SectionHeader::from_elf_file(&elf_file)?;
 
         Ok(Self {
-            elf_header,
+            elf_header: elf_header,
             program_headers,
             section_headers,
             section_header_entries,

+ 48 - 11
crates/disassembler/src/program_header.rs

@@ -1,8 +1,10 @@
-use std::{fmt::Debug, io::Cursor};
+use std::fmt::Debug;
 
+use object::Endianness;
+use object::read::elf::ElfFile64;
 use serde::{Deserialize, Serialize};
 
-use crate::{cursor::ELFCursor, errors::EZBpfError};
+use crate::errors::EZBpfError;
 
 // Program Segment Flags
 pub const PF_X: u8 = 0x01;
@@ -113,9 +115,34 @@ pub struct ProgramHeader {
 }
 
 impl ProgramHeader {
-    pub fn from_bytes(b: &[u8]) -> Result<Self, EZBpfError> {
-        let mut c = Cursor::new(b);
-        c.read_program_header()
+    pub fn from_elf_file(elf_file: &ElfFile64<Endianness>) -> Result<Vec<Self>, EZBpfError> {
+        let endian = elf_file.endian();
+        let program_headers_data = elf_file.elf_program_headers();
+
+        let mut program_headers = Vec::new();
+        for ph in program_headers_data {
+            let p_type = ProgramType::try_from(ph.p_type.get(endian))?;
+            let p_flags = ProgramFlags::from(ph.p_flags.get(endian));
+            let p_offset = ph.p_offset.get(endian);
+            let p_vaddr = ph.p_vaddr.get(endian);
+            let p_paddr = ph.p_paddr.get(endian);
+            let p_filesz = ph.p_filesz.get(endian);
+            let p_memsz = ph.p_memsz.get(endian);
+            let p_align = ph.p_align.get(endian);
+
+            program_headers.push(ProgramHeader {
+                p_type,
+                p_flags,
+                p_offset,
+                p_vaddr,
+                p_paddr,
+                p_filesz,
+                p_memsz,
+                p_align,
+            });
+        }
+
+        Ok(program_headers)
     }
 
     pub fn to_bytes(&self) -> Vec<u8> {
@@ -135,14 +162,24 @@ impl ProgramHeader {
 mod tests {
     use hex_literal::hex;
 
-    use crate::program_header::ProgramHeader;
+    use crate::program::Program;
 
     #[test]
-    fn serialize_e2e() {
-        let b = hex!(
-            "0100000005000000780000000000000078000000000000007800000000000000080000000000000008000000000000000010000000000000"
+    fn test_program_headers() {
+        let original_bytes = hex!(
+            "7F454C460201010000000000000000000300F700010000002001000000000000400000000000000028020000000000000000000040003800030040000600050001000000050000002001000000000000200100000000000020010000000000003000000000000000300000000000000000100000000000000100000004000000C001000000000000C001000000000000C0010000000000003C000000000000003C000000000000000010000000000000020000000600000050010000000000005001000000000000500100000000000070000000000000007000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007912A000000000007911182900000000B7000000010000002D21010000000000B70000000000000095000000000000001E0000000000000004000000000000000600000000000000C0010000000000000B0000000000000018000000000000000500000000000000F0010000000000000A000000000000000C00000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000120001002001000000000000300000000000000000656E747279706F696E7400002E74657874002E64796E737472002E64796E73796D002E64796E616D6963002E73687374727461620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000600000000000000200100000000000020010000000000003000000000000000000000000000000008000000000000000000000000000000170000000600000003000000000000005001000000000000500100000000000070000000000000000400000000000000080000000000000010000000000000000F0000000B0000000200000000000000C001000000000000C001000000000000300000000000000004000000010000000800000000000000180000000000000007000000030000000200000000000000F001000000000000F0010000000000000C00000000000000000000000000000001000000000000000000000000000000200000000300000000000000000000000000000000000000FC010000000000002A00000000000000000000000000000001000000000000000000000000000000"
         );
-        let h = ProgramHeader::from_bytes(&b).unwrap();
-        assert_eq!(h.to_bytes(), &b)
+        let program = Program::from_bytes(&original_bytes).unwrap();
+
+        // Verify we have the expected number of program headers.
+        assert_eq!(program.program_headers.len(), 3);
+
+        // Verify that serialized program headers match the original ELF data.
+        for (i, program_header) in program.program_headers.iter().enumerate() {
+            let serialized = program_header.to_bytes();
+            let header_offset = 0x40 + (i * 56);
+            let original_header_bytes = &original_bytes[header_offset..header_offset + 56];
+            assert_eq!(serialized, original_header_bytes,);
+        }
     }
 }

+ 86 - 36
crates/disassembler/src/section_header.rs

@@ -1,8 +1,11 @@
-use std::{fmt::Debug, fmt::Display, io::Cursor};
+use std::{fmt::Debug, fmt::Display};
 
+use object::Endianness;
+use object::read::elf::ElfFile64;
 use serde::{Deserialize, Serialize};
 
-use crate::{cursor::ELFCursor, errors::EZBpfError, instructions::Ix};
+use crate::errors::EZBpfError;
+use crate::section_header_entry::SectionHeaderEntry;
 
 #[allow(non_camel_case_types)]
 #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -102,9 +105,70 @@ pub struct SectionHeader {
 }
 
 impl SectionHeader {
-    pub fn from_bytes(b: &[u8]) -> Result<Self, EZBpfError> {
-        let mut c = Cursor::new(b);
-        c.read_section_header()
+    pub fn from_elf_file(
+        elf_file: &ElfFile64<Endianness>,
+    ) -> Result<(Vec<Self>, Vec<SectionHeaderEntry>), EZBpfError> {
+        let endian = elf_file.endian();
+        let section_headers_data: Vec<_> = elf_file.elf_section_table().iter().collect();
+
+        let mut section_headers = Vec::new();
+        for sh in section_headers_data.iter() {
+            let sh_name = sh.sh_name.get(endian);
+            let sh_type = SectionHeaderType::try_from(sh.sh_type.get(endian))?;
+            let sh_flags = sh.sh_flags.get(endian);
+            let sh_addr = sh.sh_addr.get(endian);
+            let sh_offset = sh.sh_offset.get(endian);
+            let sh_size = sh.sh_size.get(endian);
+            let sh_link = sh.sh_link.get(endian);
+            let sh_info = sh.sh_info.get(endian);
+            let sh_addralign = sh.sh_addralign.get(endian);
+            let sh_entsize = sh.sh_entsize.get(endian);
+
+            section_headers.push(SectionHeader {
+                sh_name,
+                sh_type,
+                sh_flags,
+                sh_addr,
+                sh_offset,
+                sh_size,
+                sh_link,
+                sh_info,
+                sh_addralign,
+                sh_entsize,
+            });
+        }
+
+        let elf_header = elf_file.elf_header();
+        let e_shstrndx = elf_header.e_shstrndx.get(endian);
+        let shstrndx = &section_headers[e_shstrndx as usize];
+        let shstrndx_value = elf_file.data()
+            [shstrndx.sh_offset as usize..shstrndx.sh_offset as usize + shstrndx.sh_size as usize]
+            .to_vec();
+
+        let mut indices: Vec<u32> = section_headers.iter().map(|h| h.sh_name).collect();
+        indices.push(shstrndx.sh_size as u32);
+        indices.sort_unstable();
+
+        let section_header_entries = section_headers
+            .iter()
+            .map(|s| {
+                let current_offset = s.sh_name as usize;
+                let next_index = indices.binary_search(&s.sh_name).unwrap() + 1;
+                let next_offset =
+                    *indices.get(next_index).ok_or(EZBpfError::InvalidString)? as usize;
+
+                let label = String::from_utf8(shstrndx_value[current_offset..next_offset].to_vec())
+                    .unwrap_or("default".to_string());
+
+                let data = elf_file.data()
+                    [s.sh_offset as usize..s.sh_offset as usize + s.sh_size as usize]
+                    .to_vec();
+
+                SectionHeaderEntry::new(label, s.sh_offset as usize, data)
+            })
+            .collect::<Result<Vec<_>, _>>()?;
+
+        Ok((section_headers, section_header_entries))
     }
 
     pub fn to_bytes(&self) -> Vec<u8> {
@@ -122,41 +186,27 @@ impl SectionHeader {
     }
 }
 
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct SectionHeaderEntry {
-    pub label: String,
-    pub offset: usize,
-    pub data: Vec<u8>,
-}
-
-impl SectionHeaderEntry {
-    pub fn to_ixs(&self) -> Result<Vec<Ix>, EZBpfError> {
-        if self.data.len() % 8 != 0 {
-            return Err(EZBpfError::InvalidDataLength);
-        }
-        let mut ixs: Vec<Ix> = vec![];
-        if self.data.len() >= 8 {
-            let mut c = Cursor::new(self.data.as_slice());
-            while let Ok(ix) = c.read_ix() {
-                ixs.push(ix)
-            }
-        }
-        Ok(ixs)
-    }
-}
-
 #[cfg(test)]
-mod test {
+mod tests {
     use hex_literal::hex;
 
-    use crate::section_header::SectionHeader;
+    use crate::program::Program;
 
     #[test]
-    fn serialize_e2e() {
-        let b = hex!(
-            "07000000030000000000000000000000000000000000000080000000000000000A00000000000000000000000000000001000000000000000000000000000000"
-        );
-        let h = SectionHeader::from_bytes(&b).unwrap();
-        assert_eq!(h.to_bytes(), &b)
+    fn test_section_headers() {
+        let program = Program::from_bytes(&hex!("7F454C460201010000000000000000000300F700010000002001000000000000400000000000000028020000000000000000000040003800030040000600050001000000050000002001000000000000200100000000000020010000000000003000000000000000300000000000000000100000000000000100000004000000C001000000000000C001000000000000C0010000000000003C000000000000003C000000000000000010000000000000020000000600000050010000000000005001000000000000500100000000000070000000000000007000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007912A000000000007911182900000000B7000000010000002D21010000000000B70000000000000095000000000000001E0000000000000004000000000000000600000000000000C0010000000000000B0000000000000018000000000000000500000000000000F0010000000000000A000000000000000C00000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000120001002001000000000000300000000000000000656E747279706F696E7400002E74657874002E64796E737472002E64796E73796D002E64796E616D6963002E73687374727461620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000600000000000000200100000000000020010000000000003000000000000000000000000000000008000000000000000000000000000000170000000600000003000000000000005001000000000000500100000000000070000000000000000400000000000000080000000000000010000000000000000F0000000B0000000200000000000000C001000000000000C001000000000000300000000000000004000000010000000800000000000000180000000000000007000000030000000200000000000000F001000000000000F0010000000000000C00000000000000000000000000000001000000000000000000000000000000200000000300000000000000000000000000000000000000FC010000000000002A00000000000000000000000000000001000000000000000000000000000000")).unwrap();
+
+        // Verify we have the expected number of section headers.
+        assert_eq!(program.section_headers.len(), 6);
+        assert_eq!(program.section_header_entries.len(), 6);
+
+        // Verify section header entries have proper data.
+        for entry in &program.section_header_entries {
+            assert!(!entry.label.is_empty());
+            if entry.label == ".text\0" {
+                assert!(!entry.data.is_empty());
+                assert!(!entry.ixs.is_empty());
+            }
+        }
     }
 }

+ 19 - 7
crates/disassembler/src/section_header_entry.rs

@@ -1,8 +1,8 @@
-use std::{fmt::Debug, io::Cursor};
+use std::fmt::Debug;
 
 use serde::{Deserialize, Serialize};
 
-use crate::{cursor::ELFCursor, errors::EZBpfError, instructions::Ix};
+use crate::{errors::EZBpfError, instructions::Ix};
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct SectionHeaderEntry {
@@ -25,7 +25,7 @@ impl SectionHeaderEntry {
             utf8: String::new(),
         };
 
-        if &h.label == ".text\0" {
+        if h.label.contains(".text\0") {
             h.ixs = h.to_ixs()?;
         }
 
@@ -44,12 +44,24 @@ impl SectionHeaderEntry {
             return Err(EZBpfError::InvalidDataLength);
         }
         let mut ixs: Vec<Ix> = vec![];
-        if self.data.len() >= 8 {
-            let mut c = Cursor::new(self.data.as_slice());
-            while let Ok(ix) = c.read_ix() {
-                ixs.push(ix);
+        let mut pos = 0;
+
+        while pos < self.data.len() {
+            let remaining = &self.data[pos..];
+            if remaining.len() < 8 {
+                break;
+            }
+
+            let ix = Ix::from_bytes(remaining)?;
+            if ix.op == crate::opcodes::OpCode::Lddw {
+                pos += 16;
+            } else {
+                pos += 8;
             }
+
+            ixs.push(ix);
         }
+
         Ok(ixs)
     }