From 916bc1aaddd7016e1287c3ec96855a0cea27dfaa Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Wed, 31 Jan 2018 16:16:44 +1000 Subject: [PATCH 1/2] Add alloc feature This allows building the `endian_fd` feature without `std`, although it does still require the `alloc` crate and a nightly rustc. --- Cargo.toml | 28 +++++----- Makefile | 12 ++++- src/archive/mod.rs | 15 +++--- src/elf/dyn.rs | 20 ++++--- src/elf/header.rs | 23 +++++--- src/elf/mod.rs | 10 +--- src/elf/note.rs | 7 +-- src/elf/program_header.rs | 25 +++++---- src/elf/reloc.rs | 26 +++++---- src/elf/section_header.rs | 28 ++++++---- src/elf/sym.rs | 25 +++++---- src/error.rs | 20 +++++-- src/lib.rs | 111 ++++++++++++++++++++++++-------------- src/mach/exports.rs | 2 + src/mach/fat.rs | 13 ++--- src/mach/header.rs | 2 +- src/mach/imports.rs | 1 + src/mach/load_command.rs | 3 +- src/mach/mod.rs | 5 +- src/mach/segment.rs | 10 ++-- src/pe/export.rs | 1 + src/pe/import.rs | 3 +- src/pe/mod.rs | 2 + src/pe/utils.rs | 1 + src/strtab.rs | 16 +++--- 25 files changed, 253 insertions(+), 156 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dcecf5fae..995dad53e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,25 +18,29 @@ env_logger = "0.4.3" [dependencies] plain = "0.2.3" -log = { version = "0.3.8", optional = true } + +[dependencies.log] +version = "0.3.8" +default-features = false +optional = true [dependencies.scroll] -version = "0.8.0" +version = "0.9.0" default_features = false [features] -default = ["std", "elf32", "elf64", "mach32", "mach64", "pe32", "pe64", "goblin", "endian_fd", "archive", "scroll/std"] -std = ["scroll/derive", "log"] -endian_fd = ["std"] +default = ["std", "elf32", "elf64", "mach32", "mach64", "pe32", "pe64", "archive", "endian_fd"] +std = ["alloc", "scroll/std"] +alloc = ["scroll/derive", "log"] +endian_fd = ["alloc", "elf32", "elf64", "mach32", "mach64", "pe32", "pe64", "archive"] elf32 = [] elf64 = [] -# for now we will require mach and pe to be std + endian_fd -mach32 = ["std", "endian_fd"] -mach64 = ["std", "endian_fd"] -pe32 = ["std", "endian_fd"] -pe64 = ["std", "endian_fd"] -archive = ["endian_fd"] -goblin = [] +# for now we will require mach and pe to be alloc + endian_fd +mach32 = ["alloc", "endian_fd"] +mach64 = ["alloc", "endian_fd"] +pe32 = ["alloc", "endian_fd"] +pe64 = ["alloc", "endian_fd"] +archive = ["alloc"] # [profile.dev] # opt-level = 0 diff --git a/Makefile b/Makefile index b9718be52..805b28550 100644 --- a/Makefile +++ b/Makefile @@ -28,13 +28,21 @@ api: cargo build --no-default-features --features="elf32" cargo build --no-default-features --features="elf32 elf64" cargo build --no-default-features --features="elf32 elf64 std" - cargo build --no-default-features --features="elf32 elf64 endian_fd" + cargo build --no-default-features --features="archive std" + cargo build --no-default-features --features="mach64 mach32 std" + cargo build --no-default-features --features="pe32 pe64 std" + cargo build --no-default-features --features="endian_fd std" + cargo build + +nightly_api: + cargo build --no-default-features --features="alloc" + cargo build --no-default-features --features="elf32 elf64 alloc" cargo build --no-default-features --features="archive" cargo build --no-default-features --features="mach64" cargo build --no-default-features --features="mach32" cargo build --no-default-features --features="mach64 mach32" cargo build --no-default-features --features="pe32" cargo build --no-default-features --features="pe32 pe64" - cargo build + cargo build --no-default-features --features="endian_fd" .PHONY: clean test example doc diff --git a/src/archive/mod.rs b/src/archive/mod.rs index 9a9db5cd8..cfef17365 100644 --- a/src/archive/mod.rs +++ b/src/archive/mod.rs @@ -11,8 +11,9 @@ use scroll::{self, Pread}; use strtab; use error::{Result, Error}; -use std::usize; -use std::collections::HashMap; +use core::usize; +use alloc::btree_map::BTreeMap; +use alloc::vec::Vec; pub const SIZEOF_MAGIC: usize = 8; /// The magic number of a Unix Archive @@ -334,9 +335,9 @@ pub struct Archive<'a> { sysv_name_index: NameIndex<'a>, // the array of members, which are indexed by the members hash and symbol index member_array: Vec>, - members: HashMap<&'a str, usize>, + members: BTreeMap<&'a str, usize>, // symbol -> member - symbol_index: HashMap<&'a str, usize> + symbol_index: BTreeMap<&'a str, usize> } @@ -383,8 +384,8 @@ impl<'a> Archive<'a> { } // preprocess member names - let mut members = HashMap::new(); - let mut member_index_by_offset: HashMap = HashMap::with_capacity(member_array.len()); + let mut members = BTreeMap::new(); + let mut member_index_by_offset: BTreeMap = BTreeMap::new(); for (i, member) in member_array.iter_mut().enumerate() { // copy in any SysV extended names if let Ok(sysv_name) = sysv_name_index.get(member.raw_name()) { @@ -400,7 +401,7 @@ impl<'a> Archive<'a> { } // build the symbol index, translating symbol names into member indexes - let mut symbol_index: HashMap<&str, usize> = HashMap::new(); + let mut symbol_index: BTreeMap<&str, usize> = BTreeMap::new(); for (member_offset, name) in index.symbol_indexes.iter().zip(index.strtab.iter()) { let name = name.clone(); let member_index = member_index_by_offset[member_offset]; diff --git a/src/elf/dyn.rs b/src/elf/dyn.rs index 893754f93..ff6d2936a 100644 --- a/src/elf/dyn.rs +++ b/src/elf/dyn.rs @@ -3,7 +3,7 @@ macro_rules! elf_dyn { ($size:ty) => { #[repr(C)] #[derive(Copy, Clone, PartialEq, Default)] - #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// An entry in the dynamic array pub struct Dyn { /// Dynamic entry type @@ -271,13 +271,14 @@ pub const DF_1_GLOBAUDIT: u64 = 0x01000000; /// Singleton dyn are used. pub const DF_1_SINGLETON: u64 = 0x02000000; -if_std! { +if_alloc! { use core::fmt; use scroll::ctx; use core::result; use container::{Ctx, Container}; use strtab::Strtab; use self::dyn32::{DynamicInfo}; + use alloc::vec::Vec; #[derive(Default, PartialEq, Clone)] pub struct Dyn { @@ -419,19 +420,23 @@ macro_rules! elf_dyn_std_impl { } } - if_std! { + if_alloc! { use core::fmt; use core::slice; + use alloc::vec::Vec; - use std::fs::File; - use std::io::{Read, Seek}; - use std::io::SeekFrom::Start; use elf::program_header::{PT_DYNAMIC}; use strtab::Strtab; - use error::Result; use elf::dyn::Dyn as ElfDyn; + if_std! { + use std::fs::File; + use std::io::{Read, Seek}; + use std::io::SeekFrom::Start; + use error::Result; + } + impl From for Dyn { fn from(dyn: ElfDyn) -> Self { Dyn { @@ -489,6 +494,7 @@ macro_rules! elf_dyn_std_impl { } /// Returns a vector of dynamic entries from the given fd and program headers + #[cfg(feature = "std")] pub fn from_fd(mut fd: &File, phdrs: &[$phdr]) -> Result>> { for phdr in phdrs { if phdr.p_type == PT_DYNAMIC { diff --git a/src/elf/header.rs b/src/elf/header.rs index 152ff992d..f020ff40f 100644 --- a/src/elf/header.rs +++ b/src/elf/header.rs @@ -139,11 +139,12 @@ pub fn et_to_str(et: u16) -> &'static str { } } -if_std! { +if_alloc! { use error::{self}; use scroll::{self, ctx, Endian}; use core::fmt; use container::{Ctx, Container}; + use alloc::string::ToString; #[derive(Copy, Clone, PartialEq)] /// An ELF header @@ -335,21 +336,26 @@ if_std! { }; } } -} // end if_std +} // end if_alloc macro_rules! elf_header_std_impl { ($size:expr, $width:ty) => { - if_std! { + if_alloc! { use elf::header::Header as ElfHeader; - use error::{Result, Error}; + use error::Error; + #[cfg(any(feature = "std", feature = "endian_fd"))] + use error::Result; use scroll::{self, ctx, Pread}; - use std::fs::File; - use std::io::{Read}; use core::result; + if_std! { + use std::fs::File; + use std::io::{Read}; + } + impl From for Header { fn from(eh: ElfHeader) -> Self { Header { @@ -456,8 +462,8 @@ macro_rules! elf_header_std_impl { } impl Header { - /// Load a header from a file. **You must** ensure the seek is at the correct position. + #[cfg(feature = "std")] pub fn from_fd(bytes: &mut File) -> Result
{ let mut elf_header = [0; $size]; bytes.read(&mut elf_header)?; @@ -496,7 +502,7 @@ macro_rules! elf_header_std_impl { Ok(elf_header) } } - } // end if_std + } // end if_alloc }; } @@ -510,6 +516,7 @@ macro_rules! elf_header_test { use elf::header::Header as ElfHeader; use super::*; use container::{Ctx, Container}; + use alloc::vec::Vec; #[test] fn size_of() { assert_eq!(::std::mem::size_of::
(), SIZEOF_EHDR); diff --git a/src/elf/mod.rs b/src/elf/mod.rs index 0d31b1f9f..820e612ee 100644 --- a/src/elf/mod.rs +++ b/src/elf/mod.rs @@ -53,18 +53,12 @@ pub mod reloc; pub mod note; -macro_rules! if_sylvan { - ($($i:item)*) => ($( - #[cfg(all(feature = "std", feature = "elf32", feature = "elf64", feature = "endian_fd"))] - $i - )*) -} - -if_sylvan! { +if_endian_fd! { use scroll::{self, ctx, Pread, Endian}; use strtab::Strtab; use error; use container::{Container, Ctx}; + use alloc::vec::Vec; pub type Header = header::Header; pub type ProgramHeader = program_header::ProgramHeader; diff --git a/src/elf/note.rs b/src/elf/note.rs index 4a7525488..b4d7a7cfb 100644 --- a/src/elf/note.rs +++ b/src/elf/note.rs @@ -32,7 +32,7 @@ pub const NT_GNU_BUILD_ID: u32 = 3; pub const NT_GNU_GOLD_VERSION: u32 = 4; #[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "std", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))] +#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))] #[repr(C)] /// Note section contents. Each entry in the note section begins with a header of a fixed form. pub struct Nhdr32 { @@ -45,7 +45,7 @@ pub struct Nhdr32 { } #[derive(Clone, Copy, Debug)] -#[cfg_attr(feature = "std", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))] +#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))] #[repr(C)] /// Note section contents. Each entry in the note section begins with a header of a fixed form. pub struct Nhdr64 { @@ -57,10 +57,11 @@ pub struct Nhdr64 { pub n_type: u64, } -if_std! { +if_alloc! { use error; use container; use scroll::{ctx, Pread}; + use alloc::vec::Vec; /// An iterator over ELF binary notes in a note section or segment pub struct NoteDataIterator<'a> { diff --git a/src/elf/program_header.rs b/src/elf/program_header.rs index aeec3c579..69a907f4d 100644 --- a/src/elf/program_header.rs +++ b/src/elf/program_header.rs @@ -75,12 +75,13 @@ pub fn pt_to_str(pt: u32) -> &'static str { } } -if_std! { +if_alloc! { use core::fmt; use scroll::ctx; use core::result; use core::ops::Range; use container::{Ctx, Container}; + use alloc::vec::Vec; #[derive(Default, PartialEq, Clone)] /// A unified ProgramHeader - convertable to and from 32-bit and 64-bit variants @@ -224,7 +225,7 @@ if_std! { } } } -} // end if_std +} // end if_alloc macro_rules! elf_program_header_std_impl { ($size:ty) => { @@ -237,20 +238,23 @@ macro_rules! elf_program_header_std_impl { ($size:ty) => { } } - if_std! { + if_alloc! { use elf::program_header::ProgramHeader as ElfProgramHeader; + #[cfg(any(feature = "std", feature = "endian_fd"))] use error::Result; use core::slice; use core::fmt; - use std::fs::File; - use std::io::{Seek, Read}; - use std::io::SeekFrom::Start; - use plain::Plain; + if_std! { + use std::fs::File; + use std::io::{Seek, Read}; + use std::io::SeekFrom::Start; + } + impl From for ElfProgramHeader { fn from(ph: ProgramHeader) -> Self { ElfProgramHeader { @@ -319,6 +323,7 @@ macro_rules! elf_program_header_std_impl { ($size:ty) => { slice::from_raw_parts(phdrp, phnum) } + #[cfg(feature = "std")] pub fn from_fd(fd: &mut File, offset: u64, count: usize) -> Result> { let mut phdrs = vec![ProgramHeader::default(); count]; try!(fd.seek(Start(offset))); @@ -328,7 +333,7 @@ macro_rules! elf_program_header_std_impl { ($size:ty) => { Ok(phdrs) } } - } // end if_std + } // end if_alloc };} @@ -337,7 +342,7 @@ pub mod program_header32 { #[repr(C)] #[derive(Copy, Clone, PartialEq, Default)] - #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// A 64-bit ProgramHeader typically specifies how to map executable and data segments into memory pub struct ProgramHeader { /// Segment type @@ -373,7 +378,7 @@ pub mod program_header64 { #[repr(C)] #[derive(Copy, Clone, PartialEq, Default)] - #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// A 32-bit ProgramHeader typically specifies how to map executable and data segments into memory pub struct ProgramHeader { /// Segment type diff --git a/src/elf/reloc.rs b/src/elf/reloc.rs index 1fe24eddb..41a7e3402 100644 --- a/src/elf/reloc.rs +++ b/src/elf/reloc.rs @@ -51,7 +51,7 @@ macro_rules! elf_reloc { use core::fmt; #[repr(C)] #[derive(Clone, Copy, PartialEq, Default)] - #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// Relocation with an explicit addend pub struct Rela { /// Address @@ -63,7 +63,7 @@ macro_rules! elf_reloc { } #[repr(C)] #[derive(Clone, PartialEq, Default)] - #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// Relocation without an addend pub struct Rel { /// address @@ -104,15 +104,18 @@ macro_rules! elf_reloc { macro_rules! elf_rela_std_impl { ($size:ident, $isize:ty) => { - if_std! { + if_alloc! { use elf::reloc::Reloc; use core::slice; - use error::Result; - use std::fs::File; - use std::io::{Read, Seek}; - use std::io::SeekFrom::Start; + if_std! { + use error::Result; + + use std::fs::File; + use std::io::{Read, Seek}; + use std::io::SeekFrom::Start; + } impl From for Reloc { fn from(rela: Rela) -> Self { @@ -179,6 +182,7 @@ macro_rules! elf_rela_std_impl { ($size:ident, $isize:ty) => { slice::from_raw_parts(ptr, size / SIZEOF_REL) } + #[cfg(feature = "std")] pub fn from_fd(fd: &mut File, offset: usize, size: usize) -> Result> { let count = size / SIZEOF_RELA; let mut relocs = vec![Rela::default(); count]; @@ -188,7 +192,7 @@ macro_rules! elf_rela_std_impl { ($size:ident, $isize:ty) => { } Ok(relocs) } - } // end if_std + } // end if_alloc }; } @@ -250,11 +254,13 @@ pub mod reloc64 { ////////////////////////////// // Generic Reloc ///////////////////////////// -if_std! { +if_alloc! { use core::fmt; use core::result; use scroll::ctx; use container::{Ctx, Container}; + #[cfg(feature = "endian_fd")] + use alloc::vec::Vec; #[derive(Clone, Copy, PartialEq, Default)] /// A unified ELF relocation structure @@ -381,4 +387,4 @@ if_std! { ) } } -} // end if_std +} // end if_alloc diff --git a/src/elf/section_header.rs b/src/elf/section_header.rs index ed5a8e121..2834609a5 100644 --- a/src/elf/section_header.rs +++ b/src/elf/section_header.rs @@ -2,7 +2,7 @@ macro_rules! elf_section_header { ($size:ident) => { #[repr(C)] #[derive(Copy, Clone, Eq, PartialEq, Default)] - #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// Section Headers are typically used by humans and static linkers for additional information or how to relocate the object /// /// **NOTE** section headers are strippable from a binary without any loss of portability/executability; _do not_ rely on them being there! @@ -267,15 +267,19 @@ macro_rules! elf_section_header_std_impl { ($size:ty) => { } } - if_std! { + if_alloc! { use elf::section_header::SectionHeader as ElfSectionHeader; - use error::Result; - - use std::fs::File; - use std::io::{Read, Seek}; - use std::io::SeekFrom::Start; use plain::Plain; + use alloc::vec::Vec; + + if_std! { + use error::Result; + + use std::fs::File; + use std::io::{Read, Seek}; + use std::io::SeekFrom::Start; + } impl From for ElfSectionHeader { fn from(sh: SectionHeader) -> Self { @@ -317,6 +321,7 @@ macro_rules! elf_section_header_std_impl { ($size:ty) => { shdrs } + #[cfg(feature = "std")] pub fn from_fd(fd: &mut File, offset: u64, shnum: usize) -> Result> { let mut shdrs = vec![SectionHeader::default(); shnum]; try!(fd.seek(Start(offset))); @@ -326,7 +331,7 @@ macro_rules! elf_section_header_std_impl { ($size:ty) => { Ok(shdrs) } } - } // end if_std + } // end if_alloc };} @@ -356,7 +361,7 @@ pub mod section_header64 { // Std/analysis/Unified Structs /////////////////////////////// -if_std! { +if_alloc! { use error; use core::fmt; use core::result; @@ -364,6 +369,9 @@ if_std! { use scroll::ctx; use container::{Container, Ctx}; + #[cfg(feature = "endian_fd")] + use alloc::vec::Vec; + #[derive(Default, PartialEq, Clone)] /// A unified SectionHeader - convertable to and from 32-bit and 64-bit variants pub struct SectionHeader { @@ -536,4 +544,4 @@ if_std! { } } } -} // end if_std +} // end if_alloc diff --git a/src/elf/sym.rs b/src/elf/sym.rs index 730480e36..728810fa0 100644 --- a/src/elf/sym.rs +++ b/src/elf/sym.rs @@ -116,16 +116,19 @@ macro_rules! elf_sym_std_impl { } } - if_std! { + if_alloc! { use elf::sym::Sym as ElfSym; - use error::Result; use core::fmt; use core::slice; - use std::fs::File; - use std::io::{Read, Seek}; - use std::io::SeekFrom::Start; + if_std! { + use error::Result; + + use std::fs::File; + use std::io::{Read, Seek}; + use std::io::SeekFrom::Start; + } impl Sym { /// Checks whether this `Sym` has `STB_GLOBAL`/`STB_WEAK` bind and a `st_value` of 0 @@ -185,6 +188,7 @@ macro_rules! elf_sym_std_impl { slice::from_raw_parts(symp, count) } + #[cfg(feature = "std")] pub fn from_fd(fd: &mut File, offset: usize, count: usize) -> Result> { // TODO: AFAIK this shouldn't work, since i pass in a byte size... let mut syms = vec![Sym::default(); count]; @@ -195,7 +199,7 @@ macro_rules! elf_sym_std_impl { syms.dedup(); Ok(syms) } - } // end if_std + } // end if_alloc }; } @@ -204,7 +208,7 @@ pub mod sym32 { #[repr(C)] #[derive(Clone, Copy, PartialEq, Default)] - #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// 32-bit Sym - used for both static and dynamic symbol information in a binary pub struct Sym { /// Symbol name (string tbl index) @@ -235,7 +239,7 @@ pub mod sym64 { #[repr(C)] #[derive(Clone, Copy, PartialEq, Default)] - #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] + #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))] /// 64-bit Sym - used for both static and dynamic symbol information in a binary pub struct Sym { /// Symbol name (string tbl index) @@ -261,13 +265,14 @@ pub mod sym64 { elf_sym_std_impl!(u64); } -if_std! { +if_alloc! { use scroll::{ctx, Pread}; use scroll::ctx::SizeWith; use core::fmt::{self, Debug}; use core::result; use container::{Ctx, Container}; use error::Result; + use alloc::vec::Vec; #[derive(Default, PartialEq, Clone)] /// A unified Sym definition - convertable to and from 32-bit and 64-bit variants @@ -501,4 +506,4 @@ if_std! { self.count - self.index } } -} // end if_std +} // end if_alloc diff --git a/src/error.rs b/src/error.rs index 508cc3322..17b9e2046 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,8 +4,9 @@ use scroll; use core::result; use core::fmt::{self, Display}; -use std::error; -use std::io; +use alloc::string::String; +#[cfg(feature = "std")] +use std::{error, io}; #[derive(Debug)] /// A custom Goblin error @@ -17,18 +18,27 @@ pub enum Error { /// An error emanating from reading and interpreting bytes Scroll(scroll::Error), /// An IO based error + #[cfg(feature = "std")] IO(io::Error), } -impl error::Error for Error { - fn description(&self) -> &str { +impl Error { + pub fn description(&self) -> &str { match *self { + #[cfg(feature = "std")] Error::IO(_) => { "IO error" } Error::Scroll(_) => { "Scroll error" } Error::BadMagic(_) => { "Invalid magic number" } Error::Malformed(_) => { "Entity is malformed in some way" } } } +} + +#[cfg(feature = "std")] +impl error::Error for Error { + fn description(&self) -> &str { + Error::description(self) + } fn cause(&self) -> Option<&error::Error> { match *self { Error::IO(ref io) => { io.cause() } @@ -39,6 +49,7 @@ impl error::Error for Error { } } +#[cfg(feature = "std")] impl From for Error { fn from(err: io::Error) -> Error { Error::IO(err) @@ -54,6 +65,7 @@ impl From for Error { impl Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { + #[cfg(feature = "std")] Error::IO(ref err) => { write!(fmt, "{}", err) }, Error::Scroll(ref err) => { write!(fmt, "{}", err) }, Error::BadMagic(magic) => { write! (fmt, "Invalid magic number: 0x{:x}", magic) }, diff --git a/src/lib.rs b/src/lib.rs index e478ec7ec..f7b65b93d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,26 +79,37 @@ //! via `endian_fd` #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] extern crate plain; -#[cfg_attr(feature = "std", macro_use)] +#[cfg_attr(feature = "alloc", macro_use)] extern crate scroll; -#[cfg_attr(feature = "std", macro_use)] -#[cfg(feature = "std")] extern crate log; +#[cfg(feature = "log")] +#[macro_use] +extern crate log; #[cfg(feature = "std")] extern crate core; -#[cfg(feature = "std")] -pub mod error; +#[cfg(all(feature = "alloc", not(feature = "std")))] +#[macro_use] +extern crate alloc; -pub mod strtab; +#[cfg(feature = "std")] +mod alloc { + pub use std::borrow; + pub use std::boxed; + pub use std::string; + pub use std::vec; + pub use std::collections::btree_map; +} ///////////////////////// // Misc/Helper Modules ///////////////////////// +#[allow(unused)] macro_rules! if_std { ($($i:item)*) => ($( #[cfg(feature = "std")] @@ -106,6 +117,27 @@ macro_rules! if_std { )*) } +#[allow(unused)] +macro_rules! if_alloc { + ($($i:item)*) => ($( + #[cfg(feature = "alloc")] + $i + )*) +} + +#[allow(unused)] +macro_rules! if_endian_fd { + ($($i:item)*) => ($( + #[cfg(feature = "endian_fd")] + $i + )*) +} + +#[cfg(feature = "alloc")] +pub mod error; + +pub mod strtab; + /// Binary container size information and byte-order context pub mod container { use scroll; @@ -190,7 +222,7 @@ pub mod container { } } -if_std! { +if_endian_fd! { #[derive(Debug, Default)] /// Information obtained from a peek `Hint` @@ -211,7 +243,6 @@ if_std! { } /// Peeks at `bytes`, and returns a `Hint` - #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))] pub fn peek_bytes(bytes: &[u8; 16]) -> error::Result { use scroll::{Pread, LE, BE}; use mach::{fat, header}; @@ -252,7 +283,7 @@ if_std! { } /// Peeks at the underlying Read object. Requires the underlying bytes to have at least 16 byte length. Resets the seek to `Start` after reading. - #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))] + #[cfg(feature = "std")] pub fn peek(fd: &mut R) -> error::Result { use std::io::SeekFrom; let mut bytes = [0u8; 16]; @@ -261,38 +292,38 @@ if_std! { fd.seek(SeekFrom::Start(0))?; peek_bytes(&bytes) } -} -#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))] -#[derive(Debug)] -/// A parseable object that goblin understands -pub enum Object<'a> { - /// An ELF32/ELF64! - Elf(elf::Elf<'a>), - /// A PE32/PE32+! - PE(pe::PE<'a>), - /// A 32/64-bit Mach-o binary _OR_ it is a multi-architecture binary container! - Mach(mach::Mach<'a>), - /// A Unix archive - Archive(archive::Archive<'a>), - /// None of the above, with the given magic value - Unknown(u64), -} + #[derive(Debug)] + /// A parseable object that goblin understands + pub enum Object<'a> { + /// An ELF32/ELF64! + Elf(elf::Elf<'a>), + /// A PE32/PE32+! + PE(pe::PE<'a>), + /// A 32/64-bit Mach-o binary _OR_ it is a multi-architecture binary container! + Mach(mach::Mach<'a>), + /// A Unix archive + Archive(archive::Archive<'a>), + /// None of the above, with the given magic value + Unknown(u64), + } -#[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))] -impl<'a> Object<'a> { - /// Tries to parse an `Object` from `bytes` - pub fn parse(bytes: &[u8]) -> error::Result { - use std::io::Cursor; - match peek(&mut Cursor::new(&bytes))? { - Hint::Elf(_) => Ok(Object::Elf(elf::Elf::parse(bytes)?)), - Hint::Mach(_) | Hint::MachFat(_) => Ok(Object::Mach(mach::Mach::parse(bytes)?)), - Hint::Archive => Ok(Object::Archive(archive::Archive::parse(bytes)?)), - Hint::PE => Ok(Object::PE(pe::PE::parse(bytes)?)), - Hint::Unknown(magic) => Ok(Object::Unknown(magic)) + // TODO: this could avoid std using peek_bytes + #[cfg(feature = "std")] + impl<'a> Object<'a> { + /// Tries to parse an `Object` from `bytes` + pub fn parse(bytes: &[u8]) -> error::Result { + use std::io::Cursor; + match peek(&mut Cursor::new(&bytes))? { + Hint::Elf(_) => Ok(Object::Elf(elf::Elf::parse(bytes)?)), + Hint::Mach(_) | Hint::MachFat(_) => Ok(Object::Mach(mach::Mach::parse(bytes)?)), + Hint::Archive => Ok(Object::Archive(archive::Archive::parse(bytes)?)), + Hint::PE => Ok(Object::PE(pe::PE::parse(bytes)?)), + Hint::Unknown(magic) => Ok(Object::Unknown(magic)) + } } } -} +} // end if_endian_fd ///////////////////////// // Binary Modules @@ -334,11 +365,11 @@ pub mod elf64 { } } -#[cfg(all(feature = "mach32", feature = "mach64", feature = "endian_fd"))] +#[cfg(any(feature = "mach32", feature = "mach64"))] pub mod mach; -#[cfg(all(feature = "pe32", feature = "pe64", feature = "endian_fd"))] +#[cfg(any(feature = "pe32", feature = "pe64"))] pub mod pe; -#[cfg(all(feature = "archive", feature = "std"))] +#[cfg(feature = "archive")] pub mod archive; diff --git a/src/mach/exports.rs b/src/mach/exports.rs index 2c83b0db2..131d4a0fe 100644 --- a/src/mach/exports.rs +++ b/src/mach/exports.rs @@ -11,6 +11,8 @@ use scroll::{self, Pread, Uleb128}; use error; use core::fmt::{self, Debug}; use mach::load_command; +use alloc::vec::Vec; +use alloc::string::String; type Flag = u64; diff --git a/src/mach/fat.rs b/src/mach/fat.rs index 10caa6068..3178477e6 100644 --- a/src/mach/fat.rs +++ b/src/mach/fat.rs @@ -2,8 +2,10 @@ use core::fmt; -use std::fs::File; -use std::io::{self, Read}; +if_std! { + use std::fs::File; + use std::io::{self, Read}; +} use scroll::{self, Pread}; use mach::constants::cputype::{CpuType, CpuSubType, CPU_SUBTYPE_MASK, CPU_ARCH_ABI64}; @@ -13,8 +15,7 @@ pub const FAT_MAGIC: u32 = 0xcafebabe; pub const FAT_CIGAM: u32 = 0xbebafeca; #[repr(C)] -#[derive(Clone, Copy, Default)] -#[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] +#[derive(Clone, Copy, Default, Pread, Pwrite, SizeWith)] /// The Mach-o `FatHeader` always has its data bigendian pub struct FatHeader { /// The magic number, `cafebabe` @@ -44,6 +45,7 @@ impl FatHeader { } /// Reads a `FatHeader` from a `File` on disk + #[cfg(feature = "std")] pub fn from_fd(fd: &mut File) -> io::Result { let mut header = [0; SIZEOF_FAT_HEADER]; try!(fd.read(&mut header)); @@ -58,8 +60,7 @@ impl FatHeader { } #[repr(C)] -#[derive(Clone, Copy, Default)] -#[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))] +#[derive(Clone, Copy, Default, Pread, Pwrite, SizeWith)] /// The Mach-o `FatArch` always has its data bigendian pub struct FatArch { /// What kind of CPU this binary is diff --git a/src/mach/header.rs b/src/mach/header.rs index 3c4b41be2..b41677010 100644 --- a/src/mach/header.rs +++ b/src/mach/header.rs @@ -1,6 +1,6 @@ //! A header contains minimal architecture information, the binary kind, the number of load commands, as well as an endianness hint -use std::fmt; +use core::fmt; use scroll::{ctx, Pwrite, Pread}; use scroll::ctx::SizeWith; use plain::{self, Plain}; diff --git a/src/mach/imports.rs b/src/mach/imports.rs index a577d00a2..e0cb8006e 100644 --- a/src/mach/imports.rs +++ b/src/mach/imports.rs @@ -7,6 +7,7 @@ use core::ops::Range; use core::fmt::{self, Debug}; use scroll::{Sleb128, Uleb128, Pread}; +use alloc::vec::Vec; use container; use error; diff --git a/src/mach/load_command.rs b/src/mach/load_command.rs index 02944f652..d92e372f0 100644 --- a/src/mach/load_command.rs +++ b/src/mach/load_command.rs @@ -1,7 +1,7 @@ //! Load commands tell the kernel and dynamic linker anything from how to load this binary into memory, what the entry point is, apple specific information, to which libraries it requires for dynamic linking use error; -use std::fmt::{self, Display}; +use core::fmt::{self, Display}; use scroll::{self, ctx, Endian, Pread}; /////////////////////////////////////// @@ -539,7 +539,6 @@ impl Clone for ThreadCommand { } } -#[cfg(feature = "std")] impl fmt::Debug for ThreadCommand { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("ThreadCommand") diff --git a/src/mach/mod.rs b/src/mach/mod.rs index 7be30b5bb..602fe2fad 100644 --- a/src/mach/mod.rs +++ b/src/mach/mod.rs @@ -1,5 +1,6 @@ //! The Mach-o, mostly zero-copy, binary format parser and raw struct definitions use core::fmt; +use alloc::vec::Vec; use scroll::{self, Pread, BE}; use scroll::ctx::SizeWith; @@ -70,7 +71,6 @@ pub struct MachO<'a> { bind_interpreter: Option>, } -#[cfg(feature = "std")] impl<'a> fmt::Debug for MachO<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("MachO") @@ -239,7 +239,6 @@ impl<'a> MachO<'a> { } } -#[cfg(feature = "std")] /// A Mach-o multi architecture (Fat) binary container pub struct MultiArch<'a> { data: &'a [u8], @@ -311,7 +310,6 @@ impl<'a, 'b> IntoIterator for &'b MultiArch<'a> { } } -#[cfg(feature = "std")] impl<'a> MultiArch<'a> { /// Lazily construct `Self` pub fn new(bytes: &'a [u8]) -> error::Result { @@ -368,7 +366,6 @@ impl<'a> MultiArch<'a> { } } -#[cfg(feature = "std")] impl<'a> fmt::Debug for MultiArch<'a> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("MultiArch") diff --git a/src/mach/segment.rs b/src/mach/segment.rs index a4ebd612f..bf7f9a66e 100644 --- a/src/mach/segment.rs +++ b/src/mach/segment.rs @@ -1,8 +1,10 @@ use scroll::{self, Pread, Pwrite}; use scroll::ctx::{self, SizeWith}; -use std::fmt; -use std::ops::{Deref, DerefMut}; +use core::fmt; +use core::ops::{Deref, DerefMut}; +use alloc::boxed::Box; +use alloc::vec::Vec; use container; use error; @@ -220,7 +222,7 @@ pub struct SectionIterator<'a> { pub type SectionData<'a> = &'a [u8]; -impl<'a> ::std::iter::ExactSizeIterator for SectionIterator<'a> { +impl<'a> ::core::iter::ExactSizeIterator for SectionIterator<'a> { fn len(&self) -> usize { self.count } @@ -484,7 +486,7 @@ impl<'a> DerefMut for Segments<'a> { impl<'a, 'b> IntoIterator for &'b Segments<'a> { type Item = &'b Segment<'a>; - type IntoIter = ::std::slice::Iter<'b, Segment<'a>>; + type IntoIter = ::core::slice::Iter<'b, Segment<'a>>; fn into_iter(self) -> Self::IntoIter { self.segments.iter() } diff --git a/src/pe/export.rs b/src/pe/export.rs index 9a335944f..5736a0838 100644 --- a/src/pe/export.rs +++ b/src/pe/export.rs @@ -1,4 +1,5 @@ use scroll::{self, Pread}; +use alloc::vec::Vec; use error; diff --git a/src/pe/import.rs b/src/pe/import.rs index fbb807a60..2ee8e7557 100644 --- a/src/pe/import.rs +++ b/src/pe/import.rs @@ -1,4 +1,5 @@ -use std::borrow::Cow; +use alloc::borrow::Cow; +use alloc::vec::Vec; use scroll::{self, Pread}; use error; diff --git a/src/pe/mod.rs b/src/pe/mod.rs index e2dfd3a17..afd36ea53 100644 --- a/src/pe/mod.rs +++ b/src/pe/mod.rs @@ -3,6 +3,8 @@ // TODO: panics with unwrap on None for apisetschema.dll, fhuxgraphics.dll and some others +use alloc::vec::Vec; + pub mod header; pub mod optional_header; pub mod characteristic; diff --git a/src/pe/utils.rs b/src/pe/utils.rs index 5f2c4a739..78ebba41a 100644 --- a/src/pe/utils.rs +++ b/src/pe/utils.rs @@ -1,4 +1,5 @@ use scroll::{Pread}; +use alloc::string::ToString; use error; use super::section_table; diff --git a/src/strtab.rs b/src/strtab.rs index 0a6d20493..de19eb383 100644 --- a/src/strtab.rs +++ b/src/strtab.rs @@ -6,8 +6,10 @@ use core::slice; use core::str; use core::fmt; use scroll::{self, ctx, Pread}; -#[cfg(feature = "std")] -use error; +if_alloc! { + use error; + use alloc::vec::Vec; +} /// A common string table format which is indexed by byte offsets (and not /// member index). Constructed using [`parse`](#method.parse) @@ -31,7 +33,7 @@ impl<'a> Strtab<'a> { pub unsafe fn from_raw(ptr: *const u8, size: usize, delim: u8) -> Strtab<'a> { Strtab { delim: ctx::StrCtx::Delimiter(delim), bytes: slice::from_raw_parts(ptr, size) } } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] /// Parses a strtab from `bytes` at `offset` with `len` size as the backing string table, using `delim` as the delimiter pub fn parse(bytes: &'a [u8], offset: usize, len: usize, delim: u8) -> error::Result> { let (end, overflow) = offset.overflowing_add(len); @@ -40,7 +42,7 @@ impl<'a> Strtab<'a> { } Ok(Strtab { bytes: &bytes[offset..end], delim: ctx::StrCtx::Delimiter(delim) }) } - #[cfg(feature = "std")] + #[cfg(feature = "alloc")] /// Converts the string table to a vector, with the original `delim` used to separate the strings pub fn to_vec(self) -> error::Result> { let len = self.bytes.len(); @@ -55,8 +57,8 @@ impl<'a> Strtab<'a> { } /// Safely parses and gets a str reference from the backing bytes starting at byte `offset`. /// If the index is out of bounds, `None` is returned. - /// Requires `feature = "std"` - #[cfg(feature = "std")] + /// Requires `feature = "alloc"` + #[cfg(feature = "alloc")] pub fn get(&self, offset: usize) -> Option> { if offset >= self.bytes.len() { None @@ -93,7 +95,7 @@ impl<'a> Index for Strtab<'a> { /// **NB**: this will panic if the underlying bytes are not valid utf8, or the offset is invalid #[inline(always)] fn index(&self, offset: usize) -> &Self::Output { - // This can't delegate to get() because get() requires #[cfg(features = "std")] + // This can't delegate to get() because get() requires #[cfg(features = "alloc")] // It's also slightly less useful than get() because the lifetime -- specified by the Index // trait -- matches &self, even though we could return &'a instead get_str(offset, self.bytes, self.delim).unwrap() From b86446944477ceac1232913f7d9bd0375865c230 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Fri, 2 Feb 2018 15:36:01 +1000 Subject: [PATCH 2/2] Revert endian_fd dependency changes --- Cargo.toml | 2 +- Makefile | 10 +++++++--- src/elf/mod.rs | 8 +++++++- src/lib.rs | 15 +++++++-------- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 995dad53e..e95cf93f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ default_features = false default = ["std", "elf32", "elf64", "mach32", "mach64", "pe32", "pe64", "archive", "endian_fd"] std = ["alloc", "scroll/std"] alloc = ["scroll/derive", "log"] -endian_fd = ["alloc", "elf32", "elf64", "mach32", "mach64", "pe32", "pe64", "archive"] +endian_fd = ["alloc"] elf32 = [] elf64 = [] # for now we will require mach and pe to be alloc + endian_fd diff --git a/Makefile b/Makefile index 805b28550..a1c7c7efe 100644 --- a/Makefile +++ b/Makefile @@ -25,24 +25,28 @@ example: api: cargo build --no-default-features cargo build --no-default-features --features="std" + cargo build --no-default-features --features="endian_fd std" cargo build --no-default-features --features="elf32" cargo build --no-default-features --features="elf32 elf64" cargo build --no-default-features --features="elf32 elf64 std" + cargo build --no-default-features --features="elf32 elf64 endian_fd std" cargo build --no-default-features --features="archive std" + cargo build --no-default-features --features="mach64 std" + cargo build --no-default-features --features="mach32 std" cargo build --no-default-features --features="mach64 mach32 std" + cargo build --no-default-features --features="pe32 std" cargo build --no-default-features --features="pe32 pe64 std" - cargo build --no-default-features --features="endian_fd std" cargo build nightly_api: cargo build --no-default-features --features="alloc" - cargo build --no-default-features --features="elf32 elf64 alloc" + cargo build --no-default-features --features="endian_fd" + cargo build --no-default-features --features="elf32 elf64 endian_fd" cargo build --no-default-features --features="archive" cargo build --no-default-features --features="mach64" cargo build --no-default-features --features="mach32" cargo build --no-default-features --features="mach64 mach32" cargo build --no-default-features --features="pe32" cargo build --no-default-features --features="pe32 pe64" - cargo build --no-default-features --features="endian_fd" .PHONY: clean test example doc diff --git a/src/elf/mod.rs b/src/elf/mod.rs index 820e612ee..d631b5dd9 100644 --- a/src/elf/mod.rs +++ b/src/elf/mod.rs @@ -52,8 +52,14 @@ pub mod dyn; pub mod reloc; pub mod note; +macro_rules! if_sylvan { + ($($i:item)*) => ($( + #[cfg(all(feature = "elf32", feature = "elf64", feature = "endian_fd"))] + $i + )*) +} -if_endian_fd! { +if_sylvan! { use scroll::{self, ctx, Pread, Endian}; use strtab::Strtab; use error; diff --git a/src/lib.rs b/src/lib.rs index f7b65b93d..31ed64a51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,14 +125,6 @@ macro_rules! if_alloc { )*) } -#[allow(unused)] -macro_rules! if_endian_fd { - ($($i:item)*) => ($( - #[cfg(feature = "endian_fd")] - $i - )*) -} - #[cfg(feature = "alloc")] pub mod error; @@ -222,6 +214,13 @@ pub mod container { } } +macro_rules! if_endian_fd { + ($($i:item)*) => ($( + #[cfg(all(feature = "endian_fd", feature = "elf64", feature = "elf32", feature = "pe64", feature = "pe32", feature = "mach64", feature = "mach32", feature = "archive"))] + $i + )*) +} + if_endian_fd! { #[derive(Debug, Default)]