diff --git a/Cargo.toml b/Cargo.toml index f10c12a..3dc3080 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xmas-elf" -version = "0.3.0" +version = "0.4.0" authors = ["Nick Cameron "] description = "Library for parsing and navigating ELF data; zero-allocation, type-safe." license = "Apache-2.0 OR MIT" @@ -10,6 +10,10 @@ keywords = ["elf", "parser", "binary"] [dependencies] zero = "0.1" +[dependencies.byteorder] +version = "0.5" +default-features = false + [[bin]] name = "xmas_elf" doc = false diff --git a/src/header.rs b/src/header.rs index 197d977..8e0afaf 100644 --- a/src/header.rs +++ b/src/header.rs @@ -3,23 +3,50 @@ use core::mem; use {P32, P64, ElfFile}; use zero::{read, Pod}; +use util::{convert_endianess_u16, convert_endianess_u32, convert_endianess_u64}; - -pub fn parse_header<'a>(input: &'a [u8]) -> Header<'a> { +pub fn parse_header(input: &[u8]) -> Header { let size_pt1 = mem::size_of::(); - let header_1: &'a HeaderPt1 = read(&input[..size_pt1]); + let header_1_ref: &HeaderPt1 = read(&input[..size_pt1]); + let header_1 = header_1_ref.clone(); assert!(header_1.magic == MAGIC); let header_2 = match header_1.class { Class::None => Err("Invalid ELF class"), Class::ThirtyTwo => { - let header_2: &'a HeaderPt2_ = + let header_2_ref: &HeaderPt2_ = read(&input[size_pt1..size_pt1 + mem::size_of::>()]); + let mut header_2 = header_2_ref.clone(); + convert_endianess_u16(header_1.data, unsafe { mem::transmute(&mut header_2.type_) }); + convert_endianess_u16(header_1.data, unsafe { mem::transmute(&mut header_2.machine) }); + convert_endianess_u32(header_1.data, &mut header_2.version); + convert_endianess_u16(header_1.data, &mut header_2.header_size); + convert_endianess_u32(header_1.data, &mut header_2.entry_point); + convert_endianess_u32(header_1.data, &mut header_2.ph_offset); + convert_endianess_u32(header_1.data, &mut header_2.sh_offset); + convert_endianess_u16(header_1.data, &mut header_2.ph_entry_size); + convert_endianess_u16(header_1.data, &mut header_2.ph_count); + convert_endianess_u16(header_1.data, &mut header_2.sh_entry_size); + convert_endianess_u16(header_1.data, &mut header_2.sh_count); + convert_endianess_u16(header_1.data, &mut header_2.sh_str_index); Ok(HeaderPt2::Header32(header_2)) } Class::SixtyFour => { - let header_2: &'a HeaderPt2_ = + let header_2_ref: &HeaderPt2_ = read(&input[size_pt1..size_pt1 + mem::size_of::>()]); + let mut header_2 = header_2_ref.clone(); + convert_endianess_u16(header_1.data, unsafe { mem::transmute(&mut header_2.type_) }); + convert_endianess_u16(header_1.data, unsafe { mem::transmute(&mut header_2.machine) }); + convert_endianess_u32(header_1.data, &mut header_2.version); + convert_endianess_u16(header_1.data, &mut header_2.header_size); + convert_endianess_u64(header_1.data, &mut header_2.entry_point); + convert_endianess_u64(header_1.data, &mut header_2.ph_offset); + convert_endianess_u64(header_1.data, &mut header_2.sh_offset); + convert_endianess_u16(header_1.data, &mut header_2.ph_entry_size); + convert_endianess_u16(header_1.data, &mut header_2.ph_count); + convert_endianess_u16(header_1.data, &mut header_2.sh_entry_size); + convert_endianess_u16(header_1.data, &mut header_2.sh_count); + convert_endianess_u16(header_1.data, &mut header_2.sh_str_index); Ok(HeaderPt2::Header64(header_2)) } }; @@ -31,15 +58,15 @@ pub fn parse_header<'a>(input: &'a [u8]) -> Header<'a> { pub const MAGIC: [u8; 4] = [0x7f, 'E' as u8, 'L' as u8, 'F' as u8]; -#[derive(Clone, Copy)] -pub struct Header<'a> { - pub pt1: &'a HeaderPt1, - pub pt2: Result, &'static str>, +#[derive(Clone)] +pub struct Header { + pub pt1: HeaderPt1, + pub pt2: Result, } // TODO add Header::section_count, because if sh_count = 0, then the real count is in the first section. -impl<'a> fmt::Display for Header<'a> { +impl fmt::Display for Header { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(writeln!(f, "ELF header:")); try!(writeln!(f, " magic: {:?}", self.pt1.magic)); @@ -49,12 +76,12 @@ impl<'a> fmt::Display for Header<'a> { try!(writeln!(f, " os abi: {:?}", self.pt1.os_abi)); try!(writeln!(f, " abi version: {:?}", self.pt1.abi_version)); try!(writeln!(f, " padding: {:?}", self.pt1.padding)); - try!(self.pt2.ok().map_or(Ok(()), |pt2| write!(f, "{}", pt2))); + try!(self.pt2.as_ref().ok().map_or(Ok(()), |pt2| write!(f, "{}", pt2))); Ok(()) } } -#[derive(Debug)] +#[derive(Clone, Debug)] #[repr(C)] pub struct HeaderPt1 { pub magic: [u8; 4], @@ -69,24 +96,24 @@ pub struct HeaderPt1 { unsafe impl Pod for HeaderPt1 {} -#[derive(Clone, Copy)] -pub enum HeaderPt2<'a> { - Header32(&'a HeaderPt2_), - Header64(&'a HeaderPt2_), +#[derive(Clone, Debug)] +pub enum HeaderPt2 { + Header32(HeaderPt2_), + Header64(HeaderPt2_), } macro_rules! getter { ($name: ident, $typ: ident) => { pub fn $name(&self) -> $typ { match *self { - HeaderPt2::Header32(h) => h.$name as $typ, - HeaderPt2::Header64(h) => h.$name as $typ, + HeaderPt2::Header32(ref h) => h.$name as $typ, + HeaderPt2::Header64(ref h) => h.$name as $typ, } } } } -impl<'a> HeaderPt2<'a> { +impl HeaderPt2 { pub fn size(&self) -> usize { match *self { HeaderPt2::Header32(_) => mem::size_of::>(), @@ -109,15 +136,16 @@ impl<'a> HeaderPt2<'a> { getter!(sh_str_index, u16); } -impl<'a> fmt::Display for HeaderPt2<'a> { +impl fmt::Display for HeaderPt2 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - HeaderPt2::Header32(h) => write!(f, "{}", h), - HeaderPt2::Header64(h) => write!(f, "{}", h), + HeaderPt2::Header32(ref h) => write!(f, "{}", h), + HeaderPt2::Header64(ref h) => write!(f, "{}", h), } } } +#[derive(Clone, Debug)] pub struct HeaderPt2_

{ pub type_: Type_, pub machine: Machine, @@ -156,7 +184,7 @@ impl fmt::Display for HeaderPt2_

{ } -#[derive(Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(u8)] pub enum Class { None = 0, @@ -174,7 +202,7 @@ impl Class { } } -#[derive(Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(u8)] pub enum Data { None = 0, @@ -192,7 +220,7 @@ impl Data { } } -#[derive(Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(u8)] pub enum Version { None = 0, @@ -209,7 +237,7 @@ impl Version { } } -#[derive(Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(u8)] pub enum OsAbi { // or None @@ -225,7 +253,7 @@ pub enum OsAbi { OpenVMS = 0x0D, // FIXME there are many, many more of these } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct Type_(pub u16); impl Type_ { @@ -247,7 +275,7 @@ impl fmt::Debug for Type_ { } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum Type { None, Relocatable, @@ -258,7 +286,7 @@ pub enum Type { } #[allow(non_camel_case_types)] -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(u16)] pub enum Machine { None = 0, @@ -278,7 +306,11 @@ pub enum Machine { pub fn sanity_check(file: &ElfFile) -> Result<(), &'static str> { check!(mem::size_of::() == 16); check!(file.header.pt1.magic == MAGIC, "bad magic number"); - let pt2 = try!(file.header.pt2); + let pt2 = match file.header.pt2 { + Ok(ref h) => h, + Err(err) => return Err(err) + }; + check!(mem::size_of::() + pt2.size() == pt2.header_size() as usize, "header_size does not match size of header"); match (&file.header.pt1.class, &file.header.pt2) { diff --git a/src/lib.rs b/src/lib.rs index b2861af..1969788 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,9 @@ macro_rules! check { } extern crate zero; +extern crate byteorder; +mod util; pub mod header; pub mod sections; pub mod program; @@ -28,13 +30,14 @@ use sections::{SectionHeader, SectionIter}; use program::{ProgramHeader, ProgramIter}; use zero::read_str; use symbol_table::Entry; +use util::ResultExt; pub type P32 = u32; pub type P64 = u64; pub struct ElfFile<'a> { pub input: &'a [u8], - pub header: Header<'a>, + pub header: Header, } impl<'a> ElfFile<'a> { @@ -46,8 +49,8 @@ impl<'a> ElfFile<'a> { } } - pub fn section_header(&self, index: u16) -> Result, &'static str> { - sections::parse_section_header(self.input, self.header, index) + pub fn section_header(&self, index: u16) -> Result { + sections::parse_section_header(self.input, &self.header, index) } pub fn section_iter<'b>(&'b self) -> SectionIter<'b, 'a> { @@ -57,8 +60,8 @@ impl<'a> ElfFile<'a> { } } - pub fn program_header(&self, index: u16) -> Result, &'static str> { - program::parse_program_header(self.input, self.header, index) + pub fn program_header(&self, index: u16) -> Result { + program::parse_program_header(self.input, &self.header, index) } pub fn program_iter<'b>(&'b self) -> ProgramIter<'b, 'a> { @@ -69,7 +72,12 @@ impl<'a> ElfFile<'a> { } pub fn get_string(&self, index: u32) -> Result<&'a str, &'static str> { - self.get_str_table().map(|str_table| read_str(&str_table[(index as usize)..])) + let section = try!(self.find_section_by_name(".strtab").ok_or(".strtab section not found")); + Ok(read_str(§ion.raw_data(self)[(index as usize)..])) + } + + pub fn get_section_name_string(&self, index: u32) -> Result<&'a str, &'static str> { + self.get_section_name_str_table().map(|str_table| read_str(&str_table[(index as usize)..])) } pub fn get_dyn_string(&self, index: u32) -> Result<&'a str, &'static str> { @@ -79,7 +87,7 @@ impl<'a> ElfFile<'a> { // This is really, stupidly slow. Not sure how to fix that, perhaps keeping // a HashTable mapping names to section header indices? - pub fn find_section_by_name(&self, name: &str) -> Option> { + pub fn find_section_by_name(&self, name: &str) -> Option { for sect in self.section_iter() { if let Ok(sect_name) = sect.get_name(&self) { if sect_name == name { @@ -91,9 +99,9 @@ impl<'a> ElfFile<'a> { None } - fn get_str_table(&self) -> Result<&'a [u8], &'static str> { + fn get_section_name_str_table(&self) -> Result<&'a [u8], &'static str> { // TODO cache this? - let header = self.section_header(try!(self.header.pt2).sh_str_index()); + let header = self.section_header(try!(self.header.pt2.ok_as_ref()).sh_str_index()); header.map(|h| &self.input[(h.offset() as usize)..]) } } diff --git a/src/program.rs b/src/program.rs index e3199b5..d0986e6 100644 --- a/src/program.rs +++ b/src/program.rs @@ -3,28 +3,47 @@ use zero::{read, read_array, Pod}; use header::{Class, Header}; use dynamic::Dynamic; use sections::NoteHeader; +use util::{ResultExt, convert_endianess_u32, convert_endianess_u64}; use core::mem; use core::fmt; pub fn parse_program_header<'a>(input: &'a [u8], - header: Header<'a>, + header: &Header, index: u16) - -> Result, &'static str> { - let pt2 = try!(header.pt2); + -> Result { + let pt2 = try!(header.pt2.ok_as_ref()); assert!(index < pt2.ph_count() && pt2.ph_offset() > 0 && pt2.ph_entry_size() > 0); let start = pt2.ph_offset() as usize + index as usize * pt2.ph_entry_size() as usize; let end = start + pt2.ph_entry_size() as usize; match header.pt1.class { Class::ThirtyTwo => { - let header: &'a ProgramHeader32 = read(&input[start..end]); - Ok(ProgramHeader::Ph32(header)) + let pheader_ref: &'a ProgramHeader32 = read(&input[start..end]); + let mut pheader = pheader_ref.clone(); + convert_endianess_u32(header.pt1.data, &mut pheader.type_.0); + convert_endianess_u32(header.pt1.data, &mut pheader.flags); + convert_endianess_u32(header.pt1.data, &mut pheader.offset); + convert_endianess_u32(header.pt1.data, &mut pheader.virtual_addr); + convert_endianess_u32(header.pt1.data, &mut pheader.physical_addr); + convert_endianess_u32(header.pt1.data, &mut pheader.file_size); + convert_endianess_u32(header.pt1.data, &mut pheader.mem_size); + convert_endianess_u32(header.pt1.data, &mut pheader.align); + Ok(ProgramHeader::Ph32(pheader)) } Class::SixtyFour => { - let header: &'a ProgramHeader64 = read(&input[start..end]); - Ok(ProgramHeader::Ph64(header)) + let pheader_ref: &'a ProgramHeader64 = read(&input[start..end]); + let mut pheader = pheader_ref.clone(); + convert_endianess_u32(header.pt1.data, &mut pheader.type_.0); + convert_endianess_u32(header.pt1.data, &mut pheader.flags); + convert_endianess_u64(header.pt1.data, &mut pheader.offset); + convert_endianess_u64(header.pt1.data, &mut pheader.virtual_addr); + convert_endianess_u64(header.pt1.data, &mut pheader.physical_addr); + convert_endianess_u64(header.pt1.data, &mut pheader.file_size); + convert_endianess_u64(header.pt1.data, &mut pheader.mem_size); + convert_endianess_u64(header.pt1.data, &mut pheader.align); + Ok(ProgramHeader::Ph64(pheader)) } Class::None => unreachable!(), } @@ -36,10 +55,10 @@ pub struct ProgramIter<'b, 'a: 'b> { } impl<'b, 'a> Iterator for ProgramIter<'b, 'a> { - type Item = ProgramHeader<'a>; + type Item = ProgramHeader; fn next(&mut self) -> Option { - let count = self.file.header.pt2.map(|pt2| pt2.ph_count()).unwrap_or(0); + let count = self.file.header.pt2.as_ref().map(|pt2| pt2.ph_count()).unwrap_or(0); if self.next_index >= count { return None; } @@ -50,10 +69,10 @@ impl<'b, 'a> Iterator for ProgramIter<'b, 'a> { } } -#[derive(Copy, Clone, Debug)] -pub enum ProgramHeader<'a> { - Ph32(&'a ProgramHeader32), - Ph64(&'a ProgramHeader64), +#[derive(Clone, Debug)] +pub enum ProgramHeader { + Ph32(ProgramHeader32), + Ph64(ProgramHeader64), } #[derive(Clone, Debug)] @@ -90,25 +109,25 @@ macro_rules! getter { ($name: ident, $typ: ident) => { pub fn $name(&self) -> $typ { match *self { - ProgramHeader::Ph32(h) => h.$name as $typ, - ProgramHeader::Ph64(h) => h.$name as $typ, + ProgramHeader::Ph32(ref h) => h.$name as $typ, + ProgramHeader::Ph64(ref h) => h.$name as $typ, } } } } -impl<'a> ProgramHeader<'a> { +impl<'a> ProgramHeader { pub fn get_type(&self) -> Result { match *self { - ProgramHeader::Ph32(ph) => ph.get_type(), - ProgramHeader::Ph64(ph) => ph.get_type(), + ProgramHeader::Ph32(ref ph) => ph.get_type(), + ProgramHeader::Ph64(ref ph) => ph.get_type(), } } pub fn get_data(&self, elf_file: &ElfFile<'a>) -> Result, &'static str> { match *self { - ProgramHeader::Ph32(ph) => ph.get_data(elf_file), - ProgramHeader::Ph64(ph) => ph.get_data(elf_file), + ProgramHeader::Ph32(ref ph) => ph.get_data(elf_file), + ProgramHeader::Ph64(ref ph) => ph.get_data(elf_file), } } @@ -121,11 +140,11 @@ impl<'a> ProgramHeader<'a> { getter!(flags, u32); } -impl<'a> fmt::Display for ProgramHeader<'a> { +impl fmt::Display for ProgramHeader { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - ProgramHeader::Ph32(ph) => ph.fmt(f), - ProgramHeader::Ph64(ph) => ph.fmt(f), + ProgramHeader::Ph32(ref ph) => ph.fmt(f), + ProgramHeader::Ph64(ref ph) => ph.fmt(f), } } } @@ -254,11 +273,12 @@ pub const FLAG_R: u32 = 0x4; pub const FLAG_MASKOS: u32 = 0x0ff00000; pub const FLAG_MASKPROC: u32 = 0xf0000000; -pub fn sanity_check<'a>(ph: ProgramHeader<'a>, elf_file: &ElfFile<'a>) -> Result<(), &'static str> { - let header = elf_file.header; +pub fn sanity_check<'a>(ph: ProgramHeader, elf_file: &ElfFile<'a>) -> Result<(), &'static str> { + let header = &elf_file.header; + let pt2 = try!(header.pt2.ok_as_ref()); match ph { - ProgramHeader::Ph32(ph) => { - check!(mem::size_of_val(ph) == try!(header.pt2).ph_entry_size() as usize, + ProgramHeader::Ph32(ref ph) => { + check!(mem::size_of_val(ph) == pt2.ph_entry_size() as usize, "program header size mismatch"); check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), "entry point out of range"); @@ -268,8 +288,8 @@ pub fn sanity_check<'a>(ph: ProgramHeader<'a>, elf_file: &ElfFile<'a>) -> Result "Invalid combination of virtual_addr, offset, and align"); } } - ProgramHeader::Ph64(ph) => { - check!(mem::size_of_val(ph) == try!(header.pt2).ph_entry_size() as usize, + ProgramHeader::Ph64(ref ph) => { + check!(mem::size_of_val(ph) == pt2.ph_entry_size() as usize, "program header size mismatch"); check!(((ph.offset + ph.file_size) as usize) < elf_file.input.len(), "entry point out of range"); diff --git a/src/sections.rs b/src/sections.rs index ecc4049..67d1c49 100644 --- a/src/sections.rs +++ b/src/sections.rs @@ -8,27 +8,50 @@ use zero::{read, read_array, read_str, read_strs_to_null, StrReaderIterator, Pod use symbol_table; use dynamic::Dynamic; use hash::HashTable; +use util::{ResultExt, convert_endianess_u32, convert_endianess_u64}; -pub fn parse_section_header<'a>(input: &'a [u8], - header: Header<'a>, +pub fn parse_section_header(input: &[u8], + header: &Header, index: u16) - -> Result, &'static str> { + -> Result { // Trying to get index 0 (SHN_UNDEF) is also probably an error, but it is a legitimate section. assert!(index < SHN_LORESERVE, "Attempt to get section for a reserved index"); - header.pt2.map(|pt2| { + header.pt2.ok_as_ref().map(|pt2| { let start = (index as u64 * pt2.sh_entry_size() as u64 + pt2.sh_offset() as u64) as usize; let end = start + pt2.sh_entry_size() as usize; match header.pt1.class { Class::ThirtyTwo => { - let header: &'a SectionHeader_ = read(&input[start..end]); - SectionHeader::Sh32(header) + let sheader_ref: &SectionHeader_ = read(&input[start..end]); + let mut sheader = sheader_ref.clone(); + convert_endianess_u32(header.pt1.data, &mut sheader.name); + convert_endianess_u32(header.pt1.data, &mut sheader.type_.0); + convert_endianess_u32(header.pt1.data, &mut sheader.flags); + convert_endianess_u32(header.pt1.data, &mut sheader.address); + convert_endianess_u32(header.pt1.data, &mut sheader.offset); + convert_endianess_u32(header.pt1.data, &mut sheader.size); + convert_endianess_u32(header.pt1.data, &mut sheader.link); + convert_endianess_u32(header.pt1.data, &mut sheader.info); + convert_endianess_u32(header.pt1.data, &mut sheader.align); + convert_endianess_u32(header.pt1.data, &mut sheader.entry_size); + SectionHeader::Sh32(sheader) } Class::SixtyFour => { - let header: &'a SectionHeader_ = read(&input[start..end]); - SectionHeader::Sh64(header) + let sheader_ref: &SectionHeader_ = read(&input[start..end]); + let mut sheader = sheader_ref.clone(); + convert_endianess_u32(header.pt1.data, &mut sheader.name); + convert_endianess_u32(header.pt1.data, &mut sheader.type_.0); + convert_endianess_u64(header.pt1.data, &mut sheader.flags); + convert_endianess_u64(header.pt1.data, &mut sheader.address); + convert_endianess_u64(header.pt1.data, &mut sheader.offset); + convert_endianess_u64(header.pt1.data, &mut sheader.size); + convert_endianess_u32(header.pt1.data, &mut sheader.link); + convert_endianess_u32(header.pt1.data, &mut sheader.info); + convert_endianess_u64(header.pt1.data, &mut sheader.align); + convert_endianess_u64(header.pt1.data, &mut sheader.entry_size); + SectionHeader::Sh64(sheader) } Class::None => unreachable!(), } @@ -41,10 +64,10 @@ pub struct SectionIter<'b, 'a: 'b> { } impl<'b, 'a> Iterator for SectionIter<'b, 'a> { - type Item = SectionHeader<'a>; + type Item = SectionHeader; fn next(&mut self) -> Option { - let count = self.file.header.pt2.map(|pt2| pt2.sh_count()).unwrap_or(0); + let count = self.file.header.pt2.as_ref().map(|pt2| pt2.sh_count()).unwrap_or(0); if self.next_index >= count { return None; } @@ -67,29 +90,29 @@ pub const SHN_COMMON: u16 = 0xfff2; pub const SHN_XINDEX: u16 = 0xffff; pub const SHN_HIRESERVE: u16 = 0xffff; -#[derive(Clone, Copy)] -pub enum SectionHeader<'a> { - Sh32(&'a SectionHeader_), - Sh64(&'a SectionHeader_), +#[derive(Clone, Debug)] +pub enum SectionHeader { + Sh32(SectionHeader_), + Sh64(SectionHeader_), } macro_rules! getter { ($name: ident, $typ: ident) => { pub fn $name(&self) -> $typ { match *self { - SectionHeader::Sh32(h) => h.$name as $typ, - SectionHeader::Sh64(h) => h.$name as $typ, + SectionHeader::Sh32(ref h) => h.$name as $typ, + SectionHeader::Sh64(ref h) => h.$name as $typ, } } } } -impl<'a> SectionHeader<'a> { +impl SectionHeader { // Note that this function is O(n) in the length of the name. - pub fn get_name(&self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str> { + pub fn get_name<'a>(&self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str> { self.get_type().and_then(|typ| match typ { ShType::Null => Err("Attempt to get name of null section"), - _ => elf_file.get_string(self.name()), + _ => elf_file.get_section_name_string(self.name()), }) } @@ -97,7 +120,7 @@ impl<'a> SectionHeader<'a> { self.type_().as_sh_type() } - pub fn get_data(&self, elf_file: &ElfFile<'a>) -> Result, &'static str> { + pub fn get_data<'a>(&self, elf_file: &ElfFile<'a>) -> Result, &'static str> { macro_rules! array_data { ($data32: ident, $data64: ident) => {{ let data = self.raw_data(elf_file); @@ -158,7 +181,7 @@ impl<'a> SectionHeader<'a> { }) } - pub fn raw_data(&self, elf_file: &ElfFile<'a>) -> &'a [u8] { + pub fn raw_data<'a>(&self, elf_file: &ElfFile<'a>) -> &'a [u8] { assert!(self.get_type().unwrap() != ShType::Null); &elf_file.input[self.offset() as usize..(self.offset() + self.size()) as usize] } @@ -170,7 +193,7 @@ impl<'a> SectionHeader<'a> { getter!(type_, ShType_); } -impl<'a> fmt::Display for SectionHeader<'a> { +impl fmt::Display for SectionHeader { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { macro_rules! sh_display { ($sh: ident) => {{ @@ -189,13 +212,13 @@ impl<'a> fmt::Display for SectionHeader<'a> { } match *self { - SectionHeader::Sh32(sh) => sh_display!(sh), - SectionHeader::Sh64(sh) => sh_display!(sh), + SectionHeader::Sh32(ref sh) => sh_display!(sh), + SectionHeader::Sh64(ref sh) => sh_display!(sh), } } } -#[derive(Debug)] +#[derive(Clone, Debug)] #[repr(C)] pub struct SectionHeader_

{ name: u32, @@ -499,7 +522,7 @@ impl NoteHeader { } } -pub fn sanity_check<'a>(header: SectionHeader<'a>, file: &ElfFile<'a>) -> Result<(), &'static str> { +pub fn sanity_check<'a>(header: SectionHeader, file: &ElfFile<'a>) -> Result<(), &'static str> { if try!(header.get_type()) == ShType::Null { return Ok(()); } diff --git a/src/symbol_table.rs b/src/symbol_table.rs index 233063f..42e9abd 100644 --- a/src/symbol_table.rs +++ b/src/symbol_table.rs @@ -1,9 +1,9 @@ use ElfFile; use sections; +use util::{convert_endianess_u16, convert_endianess_u32, convert_endianess_u64}; use zero::Pod; -use core::fmt; use core::mem; #[derive(Debug)] @@ -54,12 +54,12 @@ unsafe impl Pod for DynEntry32 {} unsafe impl Pod for DynEntry64 {} pub trait Entry { - fn name(&self) -> u32; + fn name<'a>(&self, elf_file: &ElfFile<'a>) -> u32; fn info(&self) -> u8; fn other(&self) -> Visibility_; - fn shndx(&self) -> u16; - fn value(&self) -> u64; - fn size(&self) -> u64; + fn shndx<'a>(&self, elf_file: &ElfFile<'a>) -> u16; + fn value<'a>(&self, elf_file: &ElfFile<'a>) -> u64; + fn size<'a>(&self, elf_file: &ElfFile<'a>) -> u64; fn get_name<'a>(&'a self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str>; @@ -78,8 +78,8 @@ pub trait Entry { fn get_section_header<'a>(&'a self, elf_file: &ElfFile<'a>, self_index: usize) - -> Result, &'static str> { - match self.shndx() { + -> Result { + match self.shndx(elf_file) { sections::SHN_XINDEX => { // TODO factor out distinguished section names into sections consts let header = elf_file.find_section_by_name(".symtab_shndx"); @@ -87,9 +87,13 @@ pub trait Entry { assert!(try!(header.get_type()) == sections::ShType::SymTabShIndex); if let sections::SectionData::SymTabShIndex(data) = try!(header.get_data(elf_file)) { + + let mut index_value = data[self_index]; + convert_endianess_u32(elf_file.header.pt1.data, &mut index_value); + // TODO cope with u32 section indices (count is in sh_size of header 0, etc.) // Note that it is completely bogus to crop to u16 here. - let index = data[self_index] as u16; + let index = index_value as u16; assert!(index != sections::SHN_UNDEF); elf_file.section_header(index) } else { @@ -107,40 +111,47 @@ pub trait Entry { } } -impl fmt::Display for Entry { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - try!(writeln!(f, "Symbol table entry:")); - try!(writeln!(f, " name: {:?}", self.name())); - try!(writeln!(f, " binding: {:?}", self.get_binding())); - try!(writeln!(f, " type: {:?}", self.get_type())); - try!(writeln!(f, " other: {:?}", self.get_other())); - try!(writeln!(f, " shndx: {:?}", self.shndx())); - try!(writeln!(f, " value: {:?}", self.value())); - try!(writeln!(f, " size: {:?}", self.size())); - Ok(()) - } -} - macro_rules! impl_entry { - ($name: ident with ElfFile::$strfunc: ident) => { + ($name: ident with ElfFile::$strfunc: ident and $convert_endianess_pointer: expr) => { impl Entry for $name { fn get_name<'a>(&'a self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str> { - elf_file.$strfunc(self.name()) + elf_file.$strfunc(self.name(elf_file)) + } + + fn name<'a>(&self, elf_file: &ElfFile<'a>) -> u32 { + let mut out = self.0.name; + convert_endianess_u32(elf_file.header.pt1.data, &mut out); + out } - fn name(&self) -> u32 { self.0.name } fn info(&self) -> u8 { self.0.info } fn other(&self) -> Visibility_ { self.0.other } - fn shndx(&self) -> u16 { self.0.shndx } - fn value(&self) -> u64 { self.0.value as u64 } - fn size(&self) -> u64 { self.0.size as u64 } + + fn shndx<'a>(&self, elf_file: &ElfFile<'a>) -> u16 { + let mut out = self.0.shndx; + convert_endianess_u16(elf_file.header.pt1.data, &mut out); + out + } + + fn value<'a>(&self, elf_file: &ElfFile<'a>) -> u64 { + let mut out = self.0.value; + $convert_endianess_pointer(elf_file.header.pt1.data, &mut out); + out as u64 + } + + fn size<'a>(&self, elf_file: &ElfFile<'a>) -> u64 { + let mut out = self.0.size; + $convert_endianess_pointer(elf_file.header.pt1.data, &mut out); + out as u64 + } + } } } -impl_entry!(Entry32 with ElfFile::get_string); -impl_entry!(Entry64 with ElfFile::get_string); -impl_entry!(DynEntry32 with ElfFile::get_dyn_string); -impl_entry!(DynEntry64 with ElfFile::get_dyn_string); +impl_entry!(Entry32 with ElfFile::get_string and convert_endianess_u32); +impl_entry!(Entry64 with ElfFile::get_string and convert_endianess_u64); +impl_entry!(DynEntry32 with ElfFile::get_dyn_string and convert_endianess_u32); +impl_entry!(DynEntry64 with ElfFile::get_dyn_string and convert_endianess_u64); #[derive(Copy, Clone, Debug)] pub struct Visibility_(u8); diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..bc77d3c --- /dev/null +++ b/src/util.rs @@ -0,0 +1,62 @@ +use core::mem; +use core::slice; + +use header::Data; +use byteorder; +use byteorder::ByteOrder; + +fn to_byte_slice(reference: &T) -> &[u8] { + unsafe { + slice::from_raw_parts(reference as *const T as *const u8, mem::size_of::()) + } +} + +pub fn convert_endianess_u16(byte_ordering: Data, value: &mut u16) { + match byte_ordering { + Data::None => {}, + Data::LittleEndian => { + *value = byteorder::LittleEndian::read_u16(to_byte_slice(value)); + }, + Data::BigEndian => { + *value = byteorder::BigEndian::read_u16(to_byte_slice(value)); + } + } +} + + +pub fn convert_endianess_u32(byte_ordering: Data, value: &mut u32) { + match byte_ordering { + Data::None => {}, + Data::LittleEndian => { + *value = byteorder::LittleEndian::read_u32(to_byte_slice(value)); + }, + Data::BigEndian => { + *value = byteorder::BigEndian::read_u32(to_byte_slice(value)); + } + } +} + +pub fn convert_endianess_u64(byte_ordering: Data, value: &mut u64) { + match byte_ordering { + Data::None => {}, + Data::LittleEndian => { + *value = byteorder::LittleEndian::read_u64(to_byte_slice(value)); + }, + Data::BigEndian => { + *value = byteorder::BigEndian::read_u64(to_byte_slice(value)); + } + } +} + +pub trait ResultExt { + fn ok_as_ref(&self) -> Result<&T, E>; +} + +impl ResultExt for Result { + fn ok_as_ref(&self) -> Result<&T, E> { + match *self { + Ok(ref value) => Ok(value), + Err(ref error) => Err(error.clone()) + } + } +}