-
Notifications
You must be signed in to change notification settings - Fork 163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implemented a solution for #67 #102
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -253,9 +253,10 @@ pub mod reloc64 { | |
// Generic Reloc | ||
///////////////////////////// | ||
if_alloc! { | ||
use scroll::{ctx, Pread}; | ||
use scroll::ctx::SizeWith; | ||
use core::fmt; | ||
use core::result; | ||
use scroll::ctx; | ||
use container::{Ctx, Container}; | ||
#[cfg(feature = "endian_fd")] | ||
use alloc::vec::Vec; | ||
|
@@ -278,18 +279,6 @@ if_alloc! { | |
use scroll::ctx::SizeWith; | ||
Reloc::size_with(&(is_rela, ctx)) | ||
} | ||
#[cfg(feature = "endian_fd")] | ||
pub fn parse(bytes: &[u8], mut offset: usize, filesz: usize, is_rela: bool, ctx: Ctx) -> ::error::Result<Vec<Reloc>> { | ||
use scroll::Pread; | ||
let count = filesz / Reloc::size(is_rela, ctx); | ||
let mut relocs = Vec::with_capacity(count); | ||
let offset = &mut offset; | ||
for _ in 0..count { | ||
let reloc = bytes.gread_with::<Reloc>(offset, (is_rela, ctx))?; | ||
relocs.push(reloc); | ||
} | ||
Ok(relocs) | ||
} | ||
} | ||
|
||
type RelocCtx = (bool, Ctx); | ||
|
@@ -391,4 +380,113 @@ if_alloc! { | |
} | ||
} | ||
} | ||
|
||
#[derive(Default)] | ||
/// An ELF section containing relocations, allowing lazy iteration over symbols. | ||
pub struct RelocSection<'a> { | ||
bytes: &'a [u8], | ||
count: usize, | ||
ctx: RelocCtx, | ||
start: usize, | ||
end: usize, | ||
} | ||
|
||
impl<'a> fmt::Debug for RelocSection<'a> { | ||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { | ||
let len = self.bytes.len(); | ||
fmt.debug_struct("RelocSection") | ||
.field("bytes", &len) | ||
.field("range", &format!("{:#x}..{:#x}", self.start, self.end)) | ||
.field("count", &self.count) | ||
.field("Relocations", &self.to_vec()) | ||
.finish() | ||
} | ||
} | ||
|
||
impl<'a> RelocSection<'a> { | ||
#[cfg(feature = "endian_fd")] | ||
/// Parse a REL or RELA section of size `filesz` from `offset`. | ||
pub fn parse(bytes: &'a [u8], offset: usize, filesz: usize, is_rela: bool, ctx: Ctx) -> ::error::Result<RelocSection<'a>> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doc comment |
||
// TODO: better error message when too large (see symtab implementation) | ||
let bytes = bytes.pread_with(offset, filesz)?; | ||
|
||
Ok(RelocSection { | ||
bytes: bytes, | ||
count: filesz / Reloc::size(is_rela, ctx), | ||
ctx: (is_rela, ctx), | ||
start: offset, | ||
end: offset + filesz, | ||
}) | ||
} | ||
|
||
/// Try to parse a single relocation from the binary, at `index`. | ||
#[inline] | ||
pub fn get(&self, index: usize) -> Option<Reloc> { | ||
if index >= self.count { | ||
None | ||
} else { | ||
Some(self.bytes.pread_with(index * Reloc::size_with(&self.ctx), self.ctx).unwrap()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because constructor checks the size, we're safe to unwrap here and in the iterator, correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, pretty much. The |
||
} | ||
} | ||
|
||
/// The number of relocations in the section. | ||
pub fn len(&self) -> usize { | ||
self.count | ||
} | ||
|
||
/// Iterate over all relocations. | ||
pub fn iter(&self) -> RelocIterator<'a> { | ||
self.into_iter() | ||
} | ||
|
||
/// Parse all relocations into a vector. | ||
pub fn to_vec(&self) -> Vec<Reloc> { | ||
self.iter().collect() | ||
} | ||
} | ||
|
||
impl<'a, 'b> IntoIterator for &'b RelocSection<'a> { | ||
type Item = <RelocIterator<'a> as Iterator>::Item; | ||
type IntoIter = RelocIterator<'a>; | ||
|
||
#[inline] | ||
fn into_iter(self) -> Self::IntoIter { | ||
RelocIterator { | ||
bytes: self.bytes, | ||
offset: 0, | ||
index: 0, | ||
count: self.count, | ||
ctx: self.ctx, | ||
} | ||
} | ||
} | ||
|
||
pub struct RelocIterator<'a> { | ||
bytes: &'a [u8], | ||
offset: usize, | ||
index: usize, | ||
count: usize, | ||
ctx: RelocCtx, | ||
} | ||
|
||
impl<'a> Iterator for RelocIterator<'a> { | ||
type Item = Reloc; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<Self::Item> { | ||
if self.index >= self.count { | ||
None | ||
} else { | ||
self.index += 1; | ||
Some(self.bytes.gread_with(&mut self.offset, self.ctx).unwrap()) | ||
} | ||
} | ||
} | ||
|
||
impl<'a> ExactSizeIterator for RelocIterator<'a> { | ||
#[inline] | ||
fn len(&self) -> usize { | ||
self.count - self.index | ||
} | ||
} | ||
} // end if_alloc |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doc comments please :)