use bitflags::bitflags;
use lief_ffi as ffi;
use std::fmt;
use std::marker::PhantomData;
use crate::common::FromFFI;
use crate::{declare_iterator, to_slice};
#[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Type {
PT_NULL,
LOAD,
DYNAMIC,
INTERP,
NOTE,
SHLIB,
PHDR,
TLS,
GNU_EH_FRAME,
GNU_STACK,
GNU_PROPERTY,
GNU_RELRO,
PAX_FLAGS,
ARM_ARCHEXT,
ARM_EXIDX,
ARM_UNWIND,
AARCH64_MEMTAG_MTE,
MIPS_REGINFO,
MIPS_RTPROC,
MIPS_OPTIONS,
MIPS_ABIFLAGS,
RISCV_ATTRIBUTES,
IA_64_EXT,
IA_64_UNWIND,
HP_TLS,
HP_CORE_NONE,
HP_CORE_VERSION,
HP_CORE_KERNEL,
HP_CORE_COMM,
HP_CORE_PROC,
HP_CORE_LOADABLE,
HP_CORE_STACK,
HP_CORE_SHM,
HP_CORE_MMF,
HP_PARALLEL,
HP_FASTBIND,
HP_OPT_ANNOT,
HP_HSL_ANNOT,
HP_STACK,
HP_CORE_UTSNAME,
UNKNOWN(u64),
}
impl From<u64> for Type {
fn from(value: u64) -> Self {
match value {
0x00000000 => Type::PT_NULL,
0x00000001 => Type::LOAD,
0x00000002 => Type::DYNAMIC,
0x00000003 => Type::INTERP,
0x00000004 => Type::NOTE,
0x00000005 => Type::SHLIB,
0x00000006 => Type::PHDR,
0x00000007 => Type::TLS,
0x6474e550 => Type::GNU_EH_FRAME,
0x6474e551 => Type::GNU_STACK,
0x6474e553 => Type::GNU_PROPERTY,
0x6474e552 => Type::GNU_RELRO,
0x65041580 => Type::PAX_FLAGS,
0x270000000 => Type::ARM_ARCHEXT,
0x270000001 => Type::ARM_EXIDX,
0x470000002 => Type::AARCH64_MEMTAG_MTE,
0x670000000 => Type::MIPS_REGINFO,
0x670000001 => Type::MIPS_RTPROC,
0x670000002 => Type::MIPS_OPTIONS,
0x670000003 => Type::MIPS_ABIFLAGS,
0x870000003 => Type::RISCV_ATTRIBUTES,
0xa70000000 => Type::IA_64_EXT,
0xa70000001 => Type::IA_64_UNWIND,
0x20000060000000 => Type::HP_TLS,
0x20000060000001 => Type::HP_CORE_NONE,
0x20000060000002 => Type::HP_CORE_VERSION,
0x20000060000003 => Type::HP_CORE_KERNEL,
0x20000060000004 => Type::HP_CORE_COMM,
0x20000060000005 => Type::HP_CORE_PROC,
0x20000060000006 => Type::HP_CORE_LOADABLE,
0x20000060000007 => Type::HP_CORE_STACK,
0x20000060000008 => Type::HP_CORE_SHM,
0x20000060000009 => Type::HP_CORE_MMF,
0x20000060000010 => Type::HP_PARALLEL,
0x20000060000011 => Type::HP_FASTBIND,
0x20000060000012 => Type::HP_OPT_ANNOT,
0x20000060000013 => Type::HP_HSL_ANNOT,
0x20000060000014 => Type::HP_STACK,
0x20000060000015 => Type::HP_CORE_UTSNAME,
_ => Type::UNKNOWN(value),
}
}
}
impl From<Type> for u64 {
fn from(value: Type) -> u64 {
match value {
Type::PT_NULL => 0x00000000,
Type::LOAD => 0x00000001,
Type::DYNAMIC => 0x00000002,
Type::INTERP => 0x00000003,
Type::NOTE => 0x00000004,
Type::SHLIB => 0x00000005,
Type::PHDR => 0x00000006,
Type::TLS => 0x00000007,
Type::GNU_EH_FRAME => 0x6474e550,
Type::GNU_STACK => 0x6474e551,
Type::GNU_PROPERTY => 0x6474e553,
Type::GNU_RELRO => 0x6474e552,
Type::PAX_FLAGS => 0x65041580,
Type::ARM_ARCHEXT => 0x270000000,
Type::ARM_EXIDX => 0x270000001,
Type::ARM_UNWIND => 0x270000001,
Type::AARCH64_MEMTAG_MTE => 0x470000002,
Type::MIPS_REGINFO => 0x670000000,
Type::MIPS_RTPROC => 0x670000001,
Type::MIPS_OPTIONS => 0x670000002,
Type::MIPS_ABIFLAGS => 0x670000003,
Type::RISCV_ATTRIBUTES => 0x870000003,
Type::IA_64_EXT => 0xa70000000,
Type::IA_64_UNWIND => 0xa70000001,
Type::HP_TLS => 0x20000060000000,
Type::HP_CORE_NONE => 0x20000060000001,
Type::HP_CORE_VERSION => 0x20000060000002,
Type::HP_CORE_KERNEL => 0x20000060000003,
Type::HP_CORE_COMM => 0x20000060000004,
Type::HP_CORE_PROC => 0x20000060000005,
Type::HP_CORE_LOADABLE => 0x20000060000006,
Type::HP_CORE_STACK => 0x20000060000007,
Type::HP_CORE_SHM => 0x20000060000008,
Type::HP_CORE_MMF => 0x20000060000009,
Type::HP_PARALLEL => 0x20000060000010,
Type::HP_FASTBIND => 0x20000060000011,
Type::HP_OPT_ANNOT => 0x20000060000012,
Type::HP_HSL_ANNOT => 0x20000060000013,
Type::HP_STACK => 0x20000060000014,
Type::HP_CORE_UTSNAME => 0x20000060000015,
Type::UNKNOWN(value) => value,
}
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Flags: u32 {
const NONE = 0x0;
const X = 0x1;
const W = 0x2;
const R = 0x4;
}
}
impl Flags {
pub fn from_value(value: u32) -> Self {
Flags::from_bits_truncate(value)
}
pub fn to_value(&self) -> u32 {
self.bits()
}
}
pub struct Segment<'a> {
pub(super) ptr: cxx::UniquePtr<ffi::ELF_Segment>,
_owner: PhantomData<&'a ffi::ELF_Binary>,
}
impl fmt::Debug for Segment<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Segment")
.field("p_type", &self.p_type())
.field("flags", &self.flags())
.field("file_offset", &self.file_offset())
.field("virtual_address", &self.virtual_address())
.field("physical_address", &self.physical_address())
.field("physical_size", &self.physical_size())
.field("virtual_size", &self.virtual_size())
.field("alignment", &self.alignment())
.finish()
}
}
impl FromFFI<ffi::ELF_Segment> for Segment<'_> {
fn from_ffi(ptr: cxx::UniquePtr<ffi::ELF_Segment>) -> Self {
Segment {
ptr,
_owner: PhantomData,
}
}
}
impl Segment<'_> {
pub fn new() -> Segment<'static> {
Segment::from_ffi(lief_ffi::ELF_Segment::create())
}
pub fn content(&self) -> &[u8] {
to_slice!(self.ptr.content());
}
pub fn p_type(&self) -> Type {
Type::from(self.ptr.stype())
}
pub fn flags(&self) -> u32 {
self.ptr.flags()
}
pub fn file_offset(&self) -> u64 {
self.ptr.file_offset()
}
pub fn virtual_address(&self) -> u64 {
self.ptr.virtual_address()
}
pub fn physical_address(&self) -> u64 {
self.ptr.physical_address()
}
pub fn physical_size(&self) -> u64 {
self.ptr.physical_size()
}
pub fn virtual_size(&self) -> u64 {
self.ptr.virtual_size()
}
pub fn alignment(&self) -> u64 {
self.ptr.alignment()
}
pub fn set_type(&mut self, ty: Type) {
self.ptr.pin_mut().set_type(ty.into());
}
pub fn set_flags(&mut self, flags: Flags) {
self.ptr.pin_mut().set_flags(flags.to_value())
}
pub fn set_file_offset(&mut self, offset: u64) {
self.ptr.pin_mut().set_file_offset(offset);
}
pub fn set_virtual_address(&mut self, va: u64) {
self.ptr.pin_mut().set_virtual_address(va);
}
pub fn set_physical_address(&mut self, addr: u64) {
self.ptr.pin_mut().set_physical_address(addr);
}
pub fn set_virtual_size(&mut self, vsize: u64) {
self.ptr.pin_mut().set_virtual_size(vsize);
}
pub fn set_alignment(&mut self, alignment: u64) {
self.ptr.pin_mut().set_alignment(alignment);
}
pub fn set_content(&mut self, content: &[u8]) {
unsafe {
self.ptr
.pin_mut()
.set_content(content.as_ptr(), content.len().try_into().unwrap());
}
}
pub fn clear(&mut self) {
self.ptr.pin_mut().clear()
}
pub fn fill(&mut self, value: u8) {
#[allow(clippy::useless_conversion)]
{
self.ptr.pin_mut().fill((value as i8).try_into().unwrap())
}
}
}
impl fmt::Display for Segment<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.ptr.to_string())
}
}
declare_iterator!(
Segments,
Segment<'a>,
ffi::ELF_Segment,
ffi::ELF_Binary,
ffi::ELF_Binary_it_segments
);