summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs47
-rw-r--r--src/structs.rs426
2 files changed, 351 insertions, 122 deletions
diff --git a/src/main.rs b/src/main.rs
index 3033ece..9be3a25 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,10 +1,14 @@
+// #![allow(incomplete_features)]
+// #![feature(unsized_locals)]
 mod structs;
-use crate::structs::ElfHeader;
+use crate::structs::{ElfHeader, ElfSectionHeader};
+use std::io::Read;
 
 #[repr(C)]
 #[derive(Debug)]
 struct Elf {
     header: &'static ElfHeader,
+    sections: &'static [ElfSectionHeader],
 }
 
 impl Elf {
@@ -12,22 +16,51 @@ impl Elf {
         let header = unsafe { &*(bytes.as_ptr() as *const ElfHeader) };
         assert_eq!(&header.ident.magic, b"\x7fELF");
         
-        Elf {
-            header
+        let sections = unsafe {
+            std::slice::from_raw_parts(
+                bytes.as_ptr().add(header.shoff as usize) as *const ElfSectionHeader,
+                header.shnum as usize,
+            )
+        };
+
+        let strtab = &sections[header.shstrndx as usize];
+        let strtab_section = unsafe { bytes.as_ptr().add(strtab.offset as usize) };
+
+        // let names = unsafe {
+        //     std::slice::from_raw_parts(
+        //         strtab_section as *const u8,
+        //         strtab.size as usize,
+        //     )
+        // };
+        // dbg!(std::str::from_utf8(&names).unwrap());
+        for sec in sections {
+            println!("{:?}", unsafe { std::ffi::CStr::from_ptr(
+                strtab_section.add(sec.name as usize) as *const i8
+            )});
         }
+        // dbg!(sections[5].r#type as u32);
+        Elf { header, sections }
     }
 }
 
 // readelf behavior here
 impl std::fmt::Display for Elf {
     fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
-        formatter.write_str("ELF Header:\n");
+        formatter.write_str("ELF Header:\n")?;
         formatter.write_fmt(format_args!("{}", self.header))
     }
 }
 
 fn main() {
-    let data = include_bytes!("../elf");
-    let elf = Elf::new(&data[..]);
-    println!("{}", elf);
+    let args: Vec<String> = std::env::args().collect();
+
+    let buffer = {
+        let mut f = std::fs::File::open(&args[1]).expect("no file found");
+        let metadata = std::fs::metadata(&args[1]).expect("unable to read metadata");
+        let mut buffer = vec![0; metadata.len() as usize];
+        f.read(&mut buffer).expect("buffer overflow");
+        buffer
+    };
+    let elf = Elf::new(&buffer[..]);
+    // println!("{}", elf);
 }
diff --git a/src/structs.rs b/src/structs.rs
index 850a47c..69ec14e 100644
--- a/src/structs.rs
+++ b/src/structs.rs
@@ -1,47 +1,65 @@
+use bitflags::bitflags;
+
 #[repr(C, packed)]
 #[derive(Debug, Copy, Clone)]
 pub struct ElfIdent {
-	/// Magic number - 0x7F, then 'ELF' in ASCII
-	pub magic: [u8; 4],
-	
-	/// 1 = 32 bit, 2 = 64 bit
-	pub class: Class,
+    /// Magic number - 0x7F, then 'ELF' in ASCII
+    pub magic: [u8; 4],
+
+    /// 1 = 32 bit, 2 = 64 bit
+    pub class: Class,
 
-	// 1 = little endian, 2 = big endian
-	pub data: Endian,
+    // 1 = little endian, 2 = big endian
+    pub data: Endian,
 
-	/// ELF header version
-	pub version: u8,
+    /// ELF header version
+    pub version: u8,
 
-	/// OS ABI - usually 0 for System V
-	pub OSABI: OSABI,
+    /// OS ABI - usually 0 for System V
+    pub OSABI: OSABI,
 
-	// This field is used to distinguish among incompatible versions of an ABI.
-	pub ABIVersion: u8,
+    // This field is used to distinguish among incompatible versions of an ABI.
+    pub ABIVersion: u8,
 
-	/// Unused/padding
-	pub _unused: [u8; 7],
+    /// Unused/padding
+    pub _unused: [u8; 7],
 }
 
 impl std::fmt::Display for ElfIdent {
     fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
-        formatter.write_str("  Magic:   ");
-        
-        for b in unsafe {*(std::ptr::addr_of!(self.magic) as *const [u8; 16])} {
-            formatter.pad(&format!("{:02x?} ", b));
+        formatter.write_str("  Magic:   ")?;
+
+        for b in unsafe { *(std::ptr::addr_of!(self.magic) as *const [u8; 16]) } {
+            formatter.pad(&format!("{:02x?} ", b))?;
         }
 
-		formatter.write_str("\n");
-
-        formatter.write_fmt(format_args!("  Class:                             {:?}\n", self.class));
-        formatter.write_fmt(format_args!("  Data:                              {}\n", self.data));
-        formatter.write_fmt(format_args!("  Version:                           {} ({})\n", self.version, match self.version {
-			0 => "invalid",
-			1 => "current",
-			2_u8..=u8::MAX => todo!(), // need to cover all cases
-		}));
-        formatter.write_fmt(format_args!("  OS/ABI:                            {}\n", self.OSABI));
-        formatter.write_fmt(format_args!("  ABI Version:                       {}\n", self.ABIVersion))
+        formatter.write_str("\n")?;
+
+        formatter.write_fmt(format_args!(
+            "  Class:                             {:?}\n",
+            self.class
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Data:                              {}\n",
+            self.data
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Version:                           {} ({})\n",
+            self.version,
+            match self.version {
+                0 => "invalid",
+                1 => "current",
+                2_u8..=u8::MAX => todo!(), // need to cover all cases
+            }
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  OS/ABI:                            {}\n",
+            self.OSABI
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  ABI Version:                       {}\n",
+            self.ABIVersion
+        ))
     }
 }
 
@@ -51,153 +69,331 @@ impl std::fmt::Display for ElfIdent {
 #[repr(C)]
 #[derive(Debug)]
 pub struct ElfHeader {
-	pub ident: ElfIdent,
+    pub ident: ElfIdent,
+
+    /// 1 = relocatable, 2 = executable, 3 = shared, 4 = core
+    pub r#type: Type,
+
+    /// Instruction set - see table below
+    pub machine: Machine,
 
-	/// 1 = relocatable, 2 = executable, 3 = shared, 4 = core
-	pub r#type: Type,
-	
-	/// Instruction set - see table below
-	pub machine: Machine,
+    /// ELF Version
+    pub version: u32,
 
-	/// ELF Version
-	pub version: u32,
+    /// Program entry position (virtual)
+    pub entry: u64,
 
-	/// Program entry position (virtual)
-	pub entry: u64,
+    /// Program header table position (bytes into file)
+    pub phoff: u64,
 
-	/// Program header table position (bytes into file)
-	pub phoff: u64,
+    /// Section header table position (bytes into file)
+    pub shoff: u64,
 
-	/// Section header table position (bytes into file)
-	pub shoff: u64,
+    /// This member holds processor-specific flags associated with the file
+    /// Currently, no flags have been defined.
+    pub flags: u32,
 
-	/// This member holds processor-specific flags associated with the file
-	/// Currently, no flags have been defined.
-	pub flags: u32,
+    /// Header size
+    pub ehsize: u16,
 
-	/// Header size
-	pub ehsize: u16,
+    /// Size of an entry in the program header table
+    pub phentsize: u16,
 
-	/// Size of an entry in the program header table
-	pub phentsize: u16,
+    /// Number of entries in the program header table
+    pub phnum: u16,
 
-	/// Number of entries in the program header table
-	pub phnum: u16,
+    /// Size of an entry in the section header table
+    pub shentsize: u16,
 
-	/// Size of an entry in the section header table
-	pub shentsize: u16,
+    /// Number of entries in the section header table
+    pub shnum: u16,
 
-	/// Number of entries in the section header table
-	pub shnum: u16,
-	
-	/// Index in section header table with the section names
-	pub shstrndx: u16,
+    /// Index in section header table with the section names
+    pub shstrndx: u16,
 }
 
 impl std::fmt::Display for ElfHeader {
     fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
-		// yes, this is really what they do in readelf.c
-        formatter.write_fmt(format_args!("{}", self.ident));
-        formatter.write_fmt(format_args!("  Type:                              {}\n", self.r#type));
-        formatter.write_fmt(format_args!("  Machine:                           {}\n", self.machine));
-        formatter.write_fmt(format_args!("  Version:                           {:#02x?}\n", self.version));
-        formatter.write_fmt(format_args!("  Entry point address:               {:#x?}\n", self.entry));
-        formatter.write_fmt(format_args!("  Start of program headers:          {} (bytes into file)\n", self.phoff));
-        formatter.write_fmt(format_args!("  Start of section headers:          {} (bytes into file)\n", self.shoff));
-        formatter.write_fmt(format_args!("  Flags:                             {:#x?}\n", self.flags));
-        formatter.write_fmt(format_args!("  Size of this header:               {} (bytes)\n", self.ehsize));
-        formatter.write_fmt(format_args!("  Size of program headers:           {} (bytes)\n", self.phentsize));
-        formatter.write_fmt(format_args!("  Number of program headers:         {}\n", self.phnum));
-        formatter.write_fmt(format_args!("  Size of section headers:           {} (bytes)\n", self.shentsize));
-        formatter.write_fmt(format_args!("  Number of section headers:         {}\n", self.shnum));
-        formatter.write_fmt(format_args!("  Section header string table index: {}\n", self.shstrndx))
+        // yes, this is really what they do in readelf.c
+        formatter.write_fmt(format_args!("{}", self.ident))?;
+        formatter.write_fmt(format_args!(
+            "  Type:                              {}\n",
+            self.r#type
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Machine:                           {}\n",
+            self.machine
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Version:                           {:#02x?}\n",
+            self.version
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Entry point address:               {:#x?}\n",
+            self.entry
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Start of program headers:          {} (bytes into file)\n",
+            self.phoff
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Start of section headers:          {} (bytes into file)\n",
+            self.shoff
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Flags:                             {:#x?}\n",
+            self.flags
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Size of this header:               {} (bytes)\n",
+            self.ehsize
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Size of program headers:           {} (bytes)\n",
+            self.phentsize
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Number of program headers:         {}\n",
+            self.phnum
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Size of section headers:           {} (bytes)\n",
+            self.shentsize
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Number of section headers:         {}\n",
+            self.shnum
+        ))?;
+        formatter.write_fmt(format_args!(
+            "  Section header string table index: {}\n",
+            self.shstrndx
+        ))
     }
 }
 
 #[derive(Debug, Copy, Clone)]
 #[repr(u16)]
 pub enum Type {
-	None = 0,
-	Rel = 1,
-	Exec = 2,
-	Dyn = 3,
-	Core = 4,
+    None = 0,
+    Rel = 1,
+    Exec = 2,
+    Dyn = 3,
+    Core = 4,
 }
 
 impl std::fmt::Display for Type {
     fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
         match self {
-			Type::None => formatter.write_str("NONE (None)"),
-			Type::Rel => formatter.write_str("REL (Relocatable file)"),
-			Type::Exec => formatter.write_str("EXEC (Executable file)"),
-			Type::Dyn => formatter.write_str("DYN (Shared object file)"),
-			Type::Core => formatter.write_str("CORE (Core file)"),
-		}
+            Type::None => formatter.write_str("NONE (None)"),
+            Type::Rel => formatter.write_str("REL (Relocatable file)"),
+            Type::Exec => formatter.write_str("EXEC (Executable file)"),
+            Type::Dyn => formatter.write_str("DYN (Shared object file)"),
+            Type::Core => formatter.write_str("CORE (Core file)"),
+        }
     }
 }
 
 #[derive(Debug, Copy, Clone)]
 #[repr(u16)]
 pub enum Machine {
-	// there are many many many more, im just gonna do x86
-	// https://github.com/bminor/binutils-gdb/blob/master/binutils/readelf.c#L2746
-	None = 1,
-	X86_64 = 62,
+    // there are many many many more, im just gonna do x86
+    // https://github.com/bminor/binutils-gdb/blob/master/binutils/readelf.c#L2746
+    None = 1,
+    X86_64 = 62,
 }
 
 impl std::fmt::Display for Machine {
     fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
         match self {
-			Machine::None => formatter.write_str("None"),
-			Machine::X86_64 => formatter.write_str("Advanced Micro Devices X86-64"),
-		}
+            Machine::None => formatter.write_str("None"),
+            Machine::X86_64 => formatter.write_str("Advanced Micro Devices X86-64"),
+        }
     }
 }
 
-
 #[derive(Debug, Copy, Clone)]
 #[repr(u8)]
 pub enum Class {
-	ELF32 = 1,
-	ELF64 = 2,
+    ELF32 = 1,
+    ELF64 = 2,
 }
 
 #[derive(Debug, Copy, Clone)]
 #[repr(u8)]
 pub enum OSABI {
-	None = 0x00,
-	SystemV = 0x01,
-	// HPUX = 0x02,
-	// Solaris = 0x03,
-	// IRIX = 0x04,
-	// FreeBSD = 0x05,
-	// TRU64 = 0x06,
-	// ARM = 0x07,
-	Standalone = 0x08,
+    None = 0x00,
+    SystemV = 0x01,
+    // HPUX = 0x02,
+    // Solaris = 0x03,
+    // IRIX = 0x04,
+    // FreeBSD = 0x05,
+    // TRU64 = 0x06,
+    // ARM = 0x07,
+    Standalone = 0x08,
 }
 
 impl std::fmt::Display for OSABI {
     fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
         match self {
-			OSABI::None => formatter.write_str("UNIX - System V"),
-			OSABI::SystemV => formatter.write_str("UNIX - System V"),
-			OSABI::Standalone => formatter.write_str("Standalone"),
-		}
+            OSABI::None => formatter.write_str("UNIX - System V"),
+            OSABI::SystemV => formatter.write_str("UNIX - System V"),
+            OSABI::Standalone => formatter.write_str("Standalone"),
+        }
     }
 }
 
 #[derive(Debug, Copy, Clone)]
 #[repr(u8)]
 pub enum Endian {
-	Little = 1,
-	Big = 2,
+    Little = 1,
+    Big = 2,
 }
 
 impl std::fmt::Display for Endian {
     fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
         match self {
-			Endian::Little => formatter.write_str("2's complement, little endian"),
-			Endian::Big => formatter.write_str("1's complement, big endian"),
-		}
+            Endian::Little => formatter.write_str("2's complement, little endian"),
+            Endian::Big => formatter.write_str("1's complement, big endian"),
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+#[repr(C)]
+pub struct ElfSectionHeader {
+    /*  This member specifies the name of the section.  Its value
+    is an index into the section header string table section,
+    giving the location of a null-terminated string. */
+    pub name: u32,
+    /*  This member categorizes the section's contents and
+    semantics. */
+    pub r#type: ElfSectionType,
+
+    /*  Sections support one-bit flags that describe miscellaneous
+    attributes.  If a flag bit is set in sh_flags, the
+    attribute is "on" for the section.  Otherwise, the
+    attribute is "off" or does not apply.  Undefined
+    attributes are set to zero. */
+    pub flags: ElfSectionFlags,
+
+    /*  If this section appears in the memory image of a process,
+    this member holds the address at which the section's first
+    byte should reside.  Otherwise, the member contains zero. */
+    pub addr: u64,
+
+    /*  This member's value holds the byte offset from the
+    beginning of the file to the first byte in the section.
+    One section type, SHT_NOBITS, occupies no space in the
+    file, and its sh_offset member locates the conceptual
+    placement in the file. */
+    pub offset: u64,
+
+    /* 	This member holds the section's size in bytes.  Unless the
+    section type is SHT_NOBITS, the section occupies sh_size
+    bytes in the file.  A section of type SHT_NOBITS may have
+    a nonzero size, but it occupies no space in the file. */
+    pub size: u64,
+
+    /* 	This member holds a section header table index link, whose
+    interpretation depends on the section type. */
+    pub link: u32,
+
+    /* 	This member holds extra information, whose interpretation
+    depends on the section type. */
+    pub info: u32,
+
+    /* 	Some sections have address alignment constraints.  If a
+    section holds a doubleword, the system must ensure
+    doubleword alignment for the entire section.  That is, the
+    value of sh_addr must be congruent to zero, modulo the
+    value of sh_addralign.  Only zero and positive integral
+    powers of two are allowed.  The value 0 or 1 means that
+    the section has no alignment constraints. */
+    pub addralign: u64,
+
+    /*	Some sections hold a table of fixed-sized entries, such as
+    a symbol table.  For such a section, this member gives the
+    size in bytes for each entry.  This member contains zero
+    if the section does not hold a table of fixed-size
+    entries. */
+    pub entsize: u64,
+}
+
+#[derive(Debug, Copy, Clone)]
+#[repr(u32)]
+pub enum ElfSectionType {
+    /*  This value marks the section header as inactive.
+    It does not have an associated section.  Other
+    members of the section header have undefined
+    values. */
+    Null = 0,
+
+    /*  This section holds information defined by the
+    program, whose format and meaning are determined
+    solely by the program. */
+    ProgBits = 1,
+
+    /*  This section holds a symbol table.  Typically,
+    SHT_SYMTAB provides symbols for link editing,
+    though it may also be used for dynamic linking.  As
+    a complete symbol table, it may contain many
+    symbols unnecessary for dynamic linking.  An object
+    file can also contain a SHT_DYNSYM section. */
+    SymTab = 2,
+
+    /*  This section holds a string table.  An object file
+    may have multiple string table sections. */
+    StrTab = 3,
+
+    /*  This section holds relocation entries with explicit
+    addends, such as type Elf32_Rela for the 32-bit
+    class of object files.  An object may have multiple
+    relocation sections. */
+    Rela = 4,
+
+    /*  This section holds a symbol hash table.  An object
+    participating in dynamic linking must contain a
+    symbol hash table.  An object file may have only
+    one hash table. */
+    Hash = 5,
+
+    /*  This section holds information for dynamic linking.
+    An object file may have only one dynamic section. */
+    Dynamic = 6,
+
+    /* This section holds notes (ElfN_Nhdr). */
+    Note = 7,
+
+    /*  A section of this type occupies no space in the
+    file but otherwise resembles SHT_PROGBITS.
+    Although this section contains no bytes, the
+    sh_offset member contains the conceptual file
+    offset. */
+    NoBits = 8,
+
+    /*  This section holds relocation offsets without
+    explicit addends, such as type Elf32_Rel for the
+    32-bit class of object files.  An object file may
+    have multiple relocation sections. */
+    Rel = 9,
+
+    /*  This section is reserved but has unspecified
+    semantics. */
+    ShLib = 10,
+
+    /*  This section holds a minimal set of dynamic linking
+    symbols.  An object file can also contain a
+    SHT_SYMTAB section. */
+    DynSym = 11,
+
+    GnuHash = 0x6FFFFFF6,
+}
+
+bitflags! {
+	#[derive(Debug, Copy, Clone)]
+	pub struct ElfSectionFlags: u64 {
+        const WRITE = 0x1;
+        const ALLOC = 0x2;
+        const EXEC = 0x4;
     }
-}
\ No newline at end of file
+}