This commit is contained in:
nora 2023-02-12 12:46:41 +01:00
parent 98eaa92612
commit 84f4ab4297
4 changed files with 207 additions and 17 deletions

View file

@ -2,8 +2,8 @@ use std::{fmt::Display, fs::File};
use anyhow::Context; use anyhow::Context;
use elven_parser::{ use elven_parser::{
consts::{ShType, RX86_64}, consts::{DynamicTag, ShType, RX86_64},
defs::Elf, defs::{Addr, Elf},
ElfParseError, ElfParseError,
}; };
use memmap2::Mmap; use memmap2::Mmap;
@ -40,6 +40,12 @@ struct RelaTable {
addend: u64, addend: u64,
} }
#[derive(Tabled)]
struct DynTable {
tag: DynamicTag,
value: Addr,
}
fn print_file(path: &str) -> anyhow::Result<()> { fn print_file(path: &str) -> anyhow::Result<()> {
println!("{path}"); println!("{path}");
@ -59,7 +65,7 @@ fn print_file(path: &str) -> anyhow::Result<()> {
HeaderTable("osabi", &ident.osabi), HeaderTable("osabi", &ident.osabi),
HeaderTable("type", &header.r#type), HeaderTable("type", &header.r#type),
HeaderTable("machine", &header.machine), HeaderTable("machine", &header.machine),
HeaderTable("entrypoint (hex)", &header.entry), HeaderTable("entrypoint", &header.entry),
]; ];
let mut table = Table::new(header_tab); let mut table = Table::new(header_tab);
@ -90,8 +96,10 @@ fn print_file(path: &str) -> anyhow::Result<()> {
.relas()? .relas()?
.map(|(sh, rela)| { .map(|(sh, rela)| {
let section = elf.sh_string(sh.name)?.to_string(); let section = elf.sh_string(sh.name)?.to_string();
let sym = elf.symbol(rela.info.sym())?; let sym = elf.symbol(rela.info.sym())?;
let symbol = elf.string(sym.name)?.to_string(); let symbol = elf.string(sym.name)?.to_string();
let offset = rela.offset.0; let offset = rela.offset.0;
let r#type = elven_parser::consts::RX86_64(rela.info.r#type()); let r#type = elven_parser::consts::RX86_64(rela.info.r#type());
let addend = rela.addend; let addend = rela.addend;
@ -108,6 +116,16 @@ fn print_file(path: &str) -> anyhow::Result<()> {
print_table(Table::new(relas)); print_table(Table::new(relas));
if let Ok(dyns) = elf.dyn_entries() {
println!("\nDynamic entries");
let dyns = dyns.iter().map(|dy| DynTable {
tag: dy.tag,
value: Addr(dy.val),
});
print_table(Table::new(dyns));
}
println!(); println!();
Ok(()) Ok(())

View file

@ -129,8 +129,12 @@ pub const ET_EXEC: u16 = 2;
pub const ET_DYN: u16 = 3; pub const ET_DYN: u16 = 3;
pub const ET_CORE: u16 = 4; pub const ET_CORE: u16 = 4;
pub const EM_NONE: u16 = 0; /* No machine */ const_group_with_fmt! {
pub const EM_X86_64: u16 = 62; /* AMD x86-64 architecture */ pub struct Machine(u16): "Machine"
pub const EM_NONE = 0; /* No machine */
pub const EM_X86_64 = 62; /* AMD x86-64 architecture */
}
pub const EV_NONE: u32 = 0; pub const EV_NONE: u32 = 0;
@ -297,6 +301,105 @@ const_group_with_fmt! {
pub const R_X86_64_NUM = 43; pub const R_X86_64_NUM = 43;
} }
// ------------------
// Dynamic
// ------------------
const_group_with_fmt! {
pub struct DynamicTag(u64): "DT"
pub const DT_NULL = 0; /* Marks end of dynamic section */
pub const DT_NEEDED = 1; /* Name of needed library */
pub const DT_PLTRELSZ = 2; /* Size in bytes of PLT relocs */
pub const DT_PLTGOT = 3; /* Processor defined value */
pub const DT_HASH = 4; /* Address of symbol hash table */
pub const DT_STRTAB = 5; /* Address of string table */
pub const DT_SYMTAB = 6; /* Address of symbol table */
pub const DT_RELA = 7; /* Address of Rela relocs */
pub const DT_RELASZ = 8; /* Total size of Rela relocs */
pub const DT_RELAENT = 9; /* Size of one Rela reloc */
pub const DT_STRSZ = 10; /* Size of string table */
pub const DT_SYMENT = 11; /* Size of one symbol table entry */
pub const DT_INIT = 12; /* Address of init function */
pub const DT_FINI = 13; /* Address of termination function */
pub const DT_SONAME = 14; /* Name of shared object */
pub const DT_RPATH = 15; /* Library search path (deprecated) */
pub const DT_SYMBOLIC = 16; /* Start symbol search here */
pub const DT_REL = 17; /* Address of Rel relocs */
pub const DT_RELSZ = 18; /* Total size of Rel relocs */
pub const DT_RELENT = 19; /* Size of one Rel reloc */
pub const DT_PLTREL = 20; /* Type of reloc in PLT */
pub const DT_DEBUG = 21; /* For debugging; unspecified */
pub const DT_TEXTREL = 22; /* Reloc might modify .text */
pub const DT_JMPREL = 23; /* Address of PLT relocs */
pub const DT_BIND_NOW = 24; /* Process relocations of object */
pub const DT_INIT_ARRAY = 25; /* Array with addresses of init fct */
pub const DT_FINI_ARRAY = 26; /* Array with addresses of fini fct */
pub const DT_INIT_ARRAYSZ = 27; /* Size in bytes of DT_INIT_ARRAY */
pub const DT_FINI_ARRAYSZ = 28; /* Size in bytes of DT_FINI_ARRAY */
pub const DT_RUNPATH = 29; /* Library search path */
pub const DT_FLAGS = 30; /* Flags for the object being loaded */
pub const DT_PREINIT_ARRAY = 32; /* Array with addresses of preinit fct*/
pub const DT_PREINIT_ARRAYSZ = 33; /* size in bytes of DT_PREINIT_ARRAY */
pub const DT_SYMTAB_SHNDX = 34; /* Address of SYMTAB_SHNDX section */
pub const DT_NUM = 35; /* Number used */
pub const DT_PROCNUM = 0x37; /* Most used by any processor */
/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's
approach. */
pub const DT_GNU_PRELINKED = 0x6ffffdf5; /* Prelinking timestamp */
pub const DT_GNU_CONFLICTSZ = 0x6ffffdf6; /* Size of conflict section */
pub const DT_GNU_LIBLISTSZ = 0x6ffffdf7; /* Size of library list */
pub const DT_CHECKSUM = 0x6ffffdf8;
pub const DT_PLTPADSZ = 0x6ffffdf9;
pub const DT_MOVEENT = 0x6ffffdfa;
pub const DT_MOVESZ = 0x6ffffdfb;
pub const DT_FEATURE_1 = 0x6ffffdfc; /* Feature selection (DTF_*). */
pub const DT_POSFLAG_1 = 0x6ffffdfd; /* Flags for DT_* entries, effecting the: u following DT_* entry. */
pub const DT_SYMINSZ = 0x6ffffdfe; /* Size of syminfo table (in bytes) */
pub const DT_SYMINENT = 0x6ffffdff; /* Entry size of syminfo */
/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
If any adjustment is made to the ELF object after it has been
built these entries will need to be adjusted. */
pub const DT_GNU_HASH = 0x6ffffef5; /* GNU-style hash table. */
pub const DT_TLSDESC_PLT = 0x6ffffef6;
pub const DT_TLSDESC_GOT = 0x6ffffef7;
pub const DT_GNU_CONFLICT = 0x6ffffef8; /* Start of conflict section */
pub const DT_GNU_LIBLIST = 0x6ffffef9; /* Library list */
pub const DT_CONFIG = 0x6ffffefa; /* Configuration information. */
pub const DT_DEPAUDIT = 0x6ffffefb; /* Dependency auditing. */
pub const DT_AUDIT = 0x6ffffefc; /* Object auditing. */
pub const DT_PLTPAD = 0x6ffffefd; /* PLT padding. */
pub const DT_MOVETAB = 0x6ffffefe; /* Move table. */
pub const DT_SYMINFO = 0x6ffffeff; /* Syminfo table. */
/* The versioning entry types. The next are defined as part of the
GNU extension. */
pub const DT_VERSYM = 0x6ffffff0;
pub const DT_RELACOUNT = 0x6ffffff9;
pub const DT_RELCOUNT = 0x6ffffffa;
/* These were chosen by Sun. */
pub const DT_FLAGS_1 = 0x6ffffffb; /* State flags, see DF_1_* below. */
pub const DT_VERDEF = 0x6ffffffc; /* Address of version definition table */
pub const DT_VERDEFNUM = 0x6ffffffd; /* Number of version definitions */
pub const DT_VERNEED = 0x6ffffffe; /* Address of table with needed versions */
pub const DT_VERNEEDNUM = 0x6fffffff; /* Number of needed versions */
}
pub const DT_ENCODING: u64 = 32; /* Start of encoded range */
pub const DT_LOOS: u64 = 0x6000000d; /* Start of OS-specific */
pub const DT_HIOS: u64 = 0x6ffff000; /* End of OS-specific */
pub const DT_LOPROC: u64 = 0x70000000; /* Start of processor-specific */
pub const DT_HIPROC: u64 = 0x7fffffff; /* End of processor-specific */
pub const DT_ADDRRNGLO: u64 = 0x6ffffe00;
pub const DT_ADDRRNGHI: u64 = 0x6ffffeff;
pub const DT_VALRNGLO: u64 = 0x6ffffd00;
pub const DT_VALRNGHI: u64 = 0x6ffffdff;
impl SectionIdx { impl SectionIdx {
pub fn usize(self) -> usize { pub fn usize(self) -> usize {
self.0 as usize self.0 as usize

View file

@ -3,13 +3,16 @@
//! See https://man7.org/linux/man-pages/man5/elf.5.html //! See https://man7.org/linux/man-pages/man5/elf.5.html
use crate::{ use crate::{
consts as c, consts::{self as c, DynamicTag, ShType},
idx::{define_idx, ElfIndexExt, ToIdxUsize}, idx::{define_idx, ElfIndexExt, ToIdxUsize},
ElfParseError, Result, ElfParseError, Result,
}; };
use bstr::BStr; use bstr::BStr;
use std::{fmt::{Debug, Display}, mem, string}; use std::{
fmt::{Debug, Display},
mem, string,
};
use bytemuck::{Pod, PodCastError, Zeroable}; use bytemuck::{Pod, PodCastError, Zeroable};
@ -20,13 +23,13 @@ pub struct Addr(pub u64);
impl Debug for Addr { impl Debug for Addr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:x}", self.0) write!(f, "0x{:x}", self.0)
} }
} }
impl Display for Addr { impl Display for Addr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:x}", self.0) write!(f, "0x{:x}", self.0)
} }
} }
@ -63,7 +66,7 @@ pub struct Elf<'a> {
pub struct ElfHeader { pub struct ElfHeader {
pub ident: ElfIdent, pub ident: ElfIdent,
pub r#type: u16, pub r#type: u16,
pub machine: u16, pub machine: c::Machine,
pub version: u32, pub version: u32,
pub entry: Addr, pub entry: Addr,
pub phoff: Offset, pub phoff: Offset,
@ -185,6 +188,13 @@ impl Debug for RelInfo {
} }
} }
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
#[repr(C)]
pub struct Dyn {
pub tag: c::DynamicTag,
pub val: u64,
}
impl<'a> Elf<'a> { impl<'a> Elf<'a> {
pub fn new(data: &'a [u8]) -> Result<Self> { pub fn new(data: &'a [u8]) -> Result<Self> {
let magic = data[..c::SELFMAG].try_into().unwrap(); let magic = data[..c::SELFMAG].try_into().unwrap();
@ -263,6 +273,13 @@ impl<'a> Elf<'a> {
)) ))
} }
pub fn section_header_by_type(&self, ty: u32) -> Result<&Shdr> {
self.section_headers()?
.iter()
.find(|sh| sh.r#type == ty)
.ok_or(ElfParseError::SectionTypeNotFound(ShType(ty)))
}
pub fn section_content(&self, sh: &Shdr) -> Result<&[u8]> { pub fn section_content(&self, sh: &Shdr) -> Result<&[u8]> {
if sh.r#type.0 == c::SHT_NOBITS { if sh.r#type.0 == c::SHT_NOBITS {
return Ok(&[]); return Ok(&[]);
@ -320,6 +337,23 @@ impl<'a> Elf<'a> {
Ok(BStr::new(&indexed[..end])) Ok(BStr::new(&indexed[..end]))
} }
pub fn dyn_string(&self, idx: StringIdx) -> Result<&BStr> {
let tab_addr = self.dyn_entry_by_tag(c::DT_STRTAB)?;
let tab_sz = self.dyn_entry_by_tag(c::DT_STRSZ)?;
let str_table = self
.data
.get_elf(tab_addr.val.., "dyn string table")?
.get_elf(..tab_sz.val, "dyn string table size")?;
let indexed = str_table.get_elf(idx.., "string offset")?;
let end = indexed
.iter()
.position(|&c| c == b'\0')
.ok_or(ElfParseError::NoStringNulTerm(idx.to_idx_usize()))?;
Ok(BStr::new(&indexed[..end]))
}
pub fn relas(&self) -> Result<impl Iterator<Item = (&Shdr, &Rela)>> { pub fn relas(&self) -> Result<impl Iterator<Item = (&Shdr, &Rela)>> {
Ok(self Ok(self
.section_headers()? .section_headers()?
@ -336,11 +370,7 @@ impl<'a> Elf<'a> {
} }
pub fn symbols(&self) -> Result<&[Sym]> { pub fn symbols(&self) -> Result<&[Sym]> {
let sh = self let sh = self.section_header_by_type(c::SHT_SYMTAB)?;
.section_headers()?
.iter()
.find(|sh| sh.r#type == c::SHT_SYMTAB)
.ok_or(ElfParseError::SymtabNotFound)?;
let data = self.section_content(sh)?; let data = self.section_content(sh)?;
@ -350,6 +380,41 @@ impl<'a> Elf<'a> {
pub fn symbol(&self, idx: SymIdx) -> Result<&Sym> { pub fn symbol(&self, idx: SymIdx) -> Result<&Sym> {
self.symbols()?.get_elf(idx, "symbol index") self.symbols()?.get_elf(idx, "symbol index")
} }
pub fn dyn_symbols(&self) -> Result<&[Sym]> {
let addr = self.dyn_entry_by_tag(c::DT_SYMTAB)?;
let size = self.dyn_entry_by_tag(c::DT_SYMENT)?;
dbg!(addr, size);
let data = self.dyn_content(addr.val, size.val)?;
load_slice(data, data.len() / mem::size_of::<Sym>())
}
pub fn dyn_symbol(&self, idx: SymIdx) -> Result<&Sym> {
dbg!(self.dyn_symbols()?).get_elf(idx, "symbol index")
}
pub fn dyn_entries(&self) -> Result<&[Dyn]> {
let sh = self.section_header_by_name(b".dynamic")?;
let data = self.section_content(sh)?;
load_slice(data, data.len() / mem::size_of::<Dyn>())
}
pub fn dyn_entry_by_tag(&self, tag: u64) -> Result<&Dyn> {
self.dyn_entries()?
.iter()
.find(|dy| dy.tag == tag)
.ok_or(ElfParseError::DynEntryNotFound(DynamicTag(tag)))
}
pub fn dyn_content(&self, addr: u64, size: u64) -> Result<&[u8]> {
self.data
.get_elf(addr.., "dyn content offset")?
.get_elf(..size, "section size")
}
} }
fn load_ref<T: Pod>(data: &[u8]) -> Result<&T> { fn load_ref<T: Pod>(data: &[u8]) -> Result<&T> {

View file

@ -1,3 +1,5 @@
use consts::{DynamicTag, ShType};
pub mod consts; pub mod consts;
pub mod defs; pub mod defs;
mod idx; mod idx;
@ -20,10 +22,12 @@ pub enum ElfParseError {
IndexOutOfBounds(&'static str, usize), IndexOutOfBounds(&'static str, usize),
#[error("String in string table does not end with a nul terminator: String offset: {0}")] #[error("String in string table does not end with a nul terminator: String offset: {0}")]
NoStringNulTerm(usize), NoStringNulTerm(usize),
#[error("The SHT_SYMTAB section was not found")] #[error("The {0} section was not found")]
SymtabNotFound, SectionTypeNotFound(ShType),
#[error("The section with the name {0:?} was not found")] #[error("The section with the name {0:?} was not found")]
SectionNotFound(std::result::Result<String, Vec<u8>>), SectionNotFound(std::result::Result<String, Vec<u8>>),
#[error("Dynamic entry not found: {0}")]
DynEntryNotFound(DynamicTag),
} }
pub type Result<T> = std::result::Result<T, ElfParseError>; pub type Result<T> = std::result::Result<T, ElfParseError>;