Update for newer Rust.

This commit is contained in:
Richard Diamond 2015-06-29 05:38:59 -05:00
parent 6a7dd76bbc
commit e5e60e6199
5 changed files with 120 additions and 70 deletions

View File

@ -16,4 +16,5 @@ name = "rust-readelf"
[lib]
name = "elf"
[dependencies]
byteorder = "*"

View File

@ -1,9 +1,8 @@
#![feature(old_path)]
#![feature(collections)]
extern crate elf;
use std::old_path::Path;
use std::path::Path;
fn main() {
let path = Path::new("stress");
@ -18,7 +17,7 @@ fn main() {
println!("{}", file);
println!("Getting the .text section");
let text = file.get_section(String::from_str(".text"));
let text = file.get_section(".text");
match text {
Some(s) => println!("shdr: {}", s),
None => println!("Failed to look up .text section!"),

View File

@ -1,5 +1,9 @@
#![feature(old_io)]
#![feature(old_path)]
use std::fs;
use std::io;
use std::path::Path;
extern crate byteorder;
pub mod types;
@ -12,6 +16,31 @@ pub struct File {
pub sections: Vec<Section>,
}
pub trait ReadExact {
fn read_exact(&mut self, len: usize) -> io::Result<Vec<u8>>;
}
impl<T> ReadExact for T
where T: io::Read
{
fn read_exact(&mut self, len: usize) -> io::Result<Vec<u8>> {
use std::io::{Error, ErrorKind};
let mut buf = Vec::with_capacity(len);
loop {
if buf.len() >= len { break; }
let current_len = buf.len();
let read = try!(self.read(&mut buf[current_len..]));
if read == 0 {
return Err(Error::new(ErrorKind::Other,
"EOF"));
}
}
return Ok(buf);
}
}
impl std::fmt::Debug for File {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?} {:?} {:?}", self.ehdr, self.phdrs, self.sections)
@ -35,35 +64,48 @@ impl std::fmt::Display for File {
#[derive(Debug)]
pub enum ParseError {
IoError,
IoError(io::Error),
InvalidMagic,
InvalidFormat,
InvalidFormat(Option<std::string::FromUtf8Error>),
NotImplemented,
}
impl std::error::FromError<std::old_io::IoError> for ParseError {
fn from_error(_: std::old_io::IoError) -> Self {
ParseError::IoError
impl std::convert::From<std::io::Error> for ParseError {
fn from(e: std::io::Error) -> Self {
ParseError::IoError(e)
}
}
impl std::error::FromError<std::string::FromUtf8Error> for ParseError {
fn from_error(_: std::string::FromUtf8Error) -> Self {
ParseError::InvalidFormat
impl std::convert::From<std::string::FromUtf8Error> for ParseError {
fn from(e: std::string::FromUtf8Error) -> Self {
ParseError::InvalidFormat(Some(e))
}
}
impl std::convert::From<byteorder::Error> for ParseError {
fn from(e: byteorder::Error) -> Self {
match e {
byteorder::Error::UnexpectedEOF => {
ParseError::InvalidFormat(None)
},
byteorder::Error::Io(e) => {
From::from(e)
},
}
}
}
impl File {
pub fn open(path: &std::old_path::Path) -> Result<File, ParseError> {
pub fn open<T: AsRef<Path>>(path: T) -> Result<File, ParseError> {
use std::io::{Read, Seek};
// Open the file for reading
let mut io_file = try!(std::old_io::File::open(path));
let mut io_file = try!(fs::File::open(path));
// Read the platform-independent ident bytes
let mut ident = [0u8; types::EI_NIDENT];
let nread = try!(io_file.read(&mut ident));
let nread = try!(io_file.read(ident.as_mut()));
if nread != types::EI_NIDENT {
return Err(ParseError::InvalidFormat);
return Err(ParseError::InvalidFormat(None));
}
// Verify the magic number
@ -105,7 +147,7 @@ impl File {
let shstrndx = try!(read_u16!(elf_f, io_file));
// Parse the program headers
try!(io_file.seek(phoff as i64, std::old_io::SeekStyle::SeekSet));
try!(io_file.seek(io::SeekFrom::Start(phoff)));
for _ in 0..phnum {
let mut progtype: types::ProgType;
let mut offset: u64;
@ -149,7 +191,7 @@ impl File {
// Parse the section headers
let mut name_idxs: Vec<u32> = Vec::new();
try!(io_file.seek(shoff as i64, std::old_io::SeekStyle::SeekSet));
try!(io_file.seek(io::SeekFrom::Start(phoff)));
for _ in 0..shnum {
let name: String = String::new();
let mut shtype: types::SectionType;
@ -202,30 +244,37 @@ impl File {
}
// Read the section data
for s_i in 0..shnum {
let off = elf_f.sections[s_i as usize].shdr.offset;
let size = elf_f.sections[s_i as usize].shdr.size;
try!(io_file.seek(off as i64, std::old_io::SeekStyle::SeekSet));
elf_f.sections[s_i as usize].data = try!(io_file.read_exact(size as usize));
let mut s_i: usize = 0;
loop {
if s_i == shnum as usize { break; }
let off = elf_f.sections[s_i].shdr.offset;
let size = elf_f.sections[s_i].shdr.size;
try!(io_file.seek(io::SeekFrom::Start(off)));
elf_f.sections[s_i].data = try!(io_file.read_exact(size as usize));
s_i += 1;
}
// Parse the section names from the string header string table
for s_i in 0..shnum {
elf_f.sections[s_i as usize].shdr.name = try!(utils::get_string(
&elf_f.sections[shstrndx as usize].data,
name_idxs[s_i as usize] as usize));
s_i = 0;
loop {
if s_i == shnum as usize { break; }
elf_f.sections[s_i].shdr.name = try!(utils::get_string(
&elf_f.sections[shstrndx as usize].data,
name_idxs[s_i] as usize));
s_i += 1;
}
Ok(elf_f)
}
pub fn get_section(&self, name: String) -> Option<&Section> {
for s_i in 0..self.sections.len() {
if self.sections[s_i].shdr.name == name {
return Some(&self.sections[s_i])
}
}
None
pub fn get_section<T: AsRef<str>>(&self, name: T) -> Option<&Section> {
self.sections
.iter()
.find(|section| section.shdr.name == name.as_ref() )
}
pub fn new() -> File {
@ -248,4 +297,3 @@ impl std::fmt::Display for Section {
write!(f, "{}", self.shdr)
}
}

View File

@ -23,7 +23,7 @@ pub const EI_OSABI: usize = 7;
pub const EI_ABIVERSION: usize = 8;
/// Represents the ELF file class (32-bit vs 64-bit)
#[derive(Copy, PartialEq)]
#[derive(Copy, Clone, PartialEq)]
pub struct Class(pub u8);
/// Invalid ELF file class
pub const ELFCLASSNONE : Class = Class(0);
@ -51,7 +51,7 @@ impl fmt::Display for Class {
}
/// Represents the ELF file data format (little-endian vs big-endian)
#[derive(Copy, PartialEq)]
#[derive(Copy, Clone, PartialEq)]
pub struct Data(pub u8);
/// Invalid ELF data format
pub const ELFDATANONE : Data = Data(0);
@ -81,7 +81,7 @@ impl fmt::Display for Data {
/// Represents the ELF file version
///
/// This field represents the values both found in the e_ident byte array and the e_version field.
#[derive(Copy)]
#[derive(Copy, Clone)]
pub struct Version(pub u32);
/// Invalid version
pub const EV_NONE : Version = Version(0);
@ -106,7 +106,7 @@ impl fmt::Display for Version {
}
/// Represents the ELF file OS ABI
#[derive(Copy)]
#[derive(Copy, Clone)]
pub struct OSABI(pub u8);
/// Defaults to Unix System V
pub const ELFOSABI_NONE : OSABI = OSABI(0);
@ -160,7 +160,7 @@ impl fmt::Display for OSABI {
}
/// Represents the ELF file type (object, executable, shared lib, core)
#[derive(Copy)]
#[derive(Copy, Clone)]
pub struct Type(pub u16);
/// No file type
pub const ET_NONE : Type = Type(0);
@ -194,7 +194,7 @@ impl fmt::Display for Type {
}
/// Represents the ELF file machine architecture
#[derive(Copy)]
#[derive(Copy, Clone)]
pub struct Machine(pub u16);
pub const EM_NONE : Machine = Machine(0);
pub const EM_M32 : Machine = Machine(1);
@ -374,7 +374,7 @@ impl fmt::Display for Machine {
/// file contents and informs how to interpret said contents. This includes
/// the width of certain fields (32-bit vs 64-bit), the data endianness, the
/// file type, and more.
#[derive(Copy, Debug)]
#[derive(Copy, Clone, Debug)]
pub struct FileHeader {
/// 32-bit vs 64-bit
pub class: Class,
@ -410,7 +410,7 @@ impl fmt::Display for FileHeader {
}
/// Represents ELF Program Header flags
#[derive(Copy, PartialEq)]
#[derive(Copy, Clone, PartialEq)]
pub struct ProgFlag(pub u32);
pub const PF_NONE : ProgFlag = ProgFlag(0);
/// Executable program segment
@ -447,7 +447,7 @@ impl fmt::Display for ProgFlag {
}
/// Represents ELF Program Header type
#[derive(Copy, PartialEq)]
#[derive(Copy, Clone, PartialEq)]
pub struct ProgType(pub u32);
/// Program header table entry unused
pub const PT_NULL : ProgType = ProgType(0);
@ -502,7 +502,7 @@ impl fmt::Display for ProgType {
///
/// The program header table is an array of program header structures describing
/// the various segments for program execution.
#[derive(Copy, Debug)]
#[derive(Copy, Clone, Debug)]
pub struct ProgramHeader {
/// Program segment type
pub progtype: ProgType,
@ -531,7 +531,7 @@ impl fmt::Display for ProgramHeader {
}
/// Represens ELF Section type
#[derive(Copy, PartialEq)]
#[derive(Copy, Clone, PartialEq)]
pub struct SectionType(pub u32);
/// Inactive section with undefined values
pub const SHT_NULL : SectionType = SectionType(0);
@ -624,7 +624,7 @@ impl fmt::Display for SectionType {
///
/// Wrapper type for SectionFlag
///
#[derive(Copy, PartialEq)]
#[derive(Copy, Clone, PartialEq)]
pub struct SectionFlag(pub u64);
/// Empty flags
pub const SHF_NONE : SectionFlag = SectionFlag(0);
@ -694,7 +694,7 @@ impl fmt::Display for SectionHeader {
}
}
#[derive(Copy)]
#[derive(Copy, Clone)]
pub struct SymbolType(pub u8);
/// Unspecified symbol type
pub const STT_NOTYPE : SymbolType = SymbolType(0);
@ -730,7 +730,7 @@ impl fmt::Display for SymbolType {
}
}
#[derive(Copy)]
#[derive(Copy, Clone)]
pub struct SymbolBind(pub u8);
/// Local symbol
pub const STB_LOCAL : SymbolBind = SymbolBind(0);
@ -754,7 +754,7 @@ impl fmt::Display for SymbolBind {
}
}
#[derive(Copy)]
#[derive(Copy, Clone)]
pub struct SymbolVis(pub u8);
/// Default symbol visibility
pub const STV_DEFAULT : SymbolVis = SymbolVis(0);
@ -802,4 +802,3 @@ impl Symbol {
SymbolVis(self.other & 0x3)
}
}

View File

@ -1,50 +1,54 @@
#[macro_export]
macro_rules! read_u8 {
($elf:ident, $io:ident) => (
($elf:ident, $io:ident) => ({
use byteorder::{LittleEndian, BigEndian, ReadBytesExt};
match $elf.ehdr.data {
types::ELFDATA2LSB => { $io.read_le_u8() }
types::ELFDATA2MSB => { $io.read_be_u8() }
types::ELFDATA2LSB => { $io.read_u8::<LittleEndian>() }
types::ELFDATA2MSB => { $io.read_u8::<BigEndian>() }
types::ELFDATANONE => { panic!("Unable to resolve file endianness"); }
_ => { panic!("Unable to resolve file endianness"); }
}
);
});
}
#[macro_export]
macro_rules! read_u16 {
($elf:ident, $io:ident) => (
($elf:ident, $io:ident) => ({
use byteorder::{LittleEndian, BigEndian, ReadBytesExt};
match $elf.ehdr.data {
types::ELFDATA2LSB => { $io.read_le_u16() }
types::ELFDATA2MSB => { $io.read_be_u16() }
types::ELFDATA2LSB => { $io.read_u16::<LittleEndian>() }
types::ELFDATA2MSB => { $io.read_u16::<BigEndian>() }
types::ELFDATANONE => { panic!("Unable to resolve file endianness"); }
_ => { panic!("Unable to resolve file endianness"); }
}
);
});
}
#[macro_export]
macro_rules! read_u32 {
($elf:ident, $io:ident) => (
($elf:ident, $io:ident) => ({
use byteorder::{LittleEndian, BigEndian, ReadBytesExt};
match $elf.ehdr.data {
types::ELFDATA2LSB => { $io.read_le_u32() }
types::ELFDATA2MSB => { $io.read_be_u32() }
types::ELFDATA2LSB => { $io.read_u32::<LittleEndian>() }
types::ELFDATA2MSB => { $io.read_u32::<BigEndian>() }
types::ELFDATANONE => { panic!("Unable to resolve file endianness"); }
_ => { panic!("Unable to resolve file endianness"); }
}
);
});
}
#[macro_export]
macro_rules! read_u64 {
($elf:ident, $io:ident) => (
($elf:ident, $io:ident) => ({
use byteorder::{LittleEndian, BigEndian, ReadBytesExt};
match $elf.ehdr.data {
types::ELFDATA2LSB => { $io.read_le_u64() }
types::ELFDATA2MSB => { $io.read_be_u64() }
types::ELFDATA2LSB => { $io.read_u64::<LittleEndian>() }
types::ELFDATA2MSB => { $io.read_u64::<BigEndian>() }
types::ELFDATANONE => { panic!("Unable to resolve file endianness"); }
_ => { panic!("Unable to resolve file endianness"); }
}
);
});
}
use std;
@ -62,4 +66,3 @@ pub fn get_string(data: &Vec<u8>, start: usize) -> Result<String, std::string::F
}
Ok(rtn)
}