804 lines
28 KiB
Rust
804 lines
28 KiB
Rust
use std::fmt;
|
|
|
|
/// Length of ELF file header platform-independent identification fields
|
|
pub const EI_NIDENT: usize = 16;
|
|
/// ELF magic number byte 1
|
|
pub const ELFMAG0: u8 = 0x7f;
|
|
/// ELF magic number byte 2
|
|
pub const ELFMAG1: u8 = 0x45;
|
|
/// ELF magic number byte 3
|
|
pub const ELFMAG2: u8 = 0x4c;
|
|
/// ELF magic number byte 4
|
|
pub const ELFMAG3: u8 = 0x46;
|
|
/// Location of ELF class field in ELF file header ident array
|
|
pub const EI_CLASS: usize = 4;
|
|
/// Location of data format field in ELF file header ident array
|
|
pub const EI_DATA: usize = 5;
|
|
/// Location of ELF version field in ELF file header ident array
|
|
pub const EI_VERSION: usize = 6;
|
|
/// Location of OS ABI field in ELF file header ident array
|
|
pub const EI_OSABI: usize = 7;
|
|
/// Location of ABI version field in ELF file header ident array
|
|
pub const EI_ABIVERSION: usize = 8;
|
|
|
|
/// Represents the ELF file class (32-bit vs 64-bit)
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct Class(pub u8);
|
|
/// Invalid ELF file class
|
|
pub const ELFCLASSNONE : Class = Class(0);
|
|
/// 32-bit ELF file
|
|
pub const ELFCLASS32 : Class = Class(1);
|
|
/// 64-bit ELF file
|
|
pub const ELFCLASS64 : Class = Class(2);
|
|
|
|
impl fmt::Debug for Class {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Class {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
ELFCLASSNONE => "Invalid",
|
|
ELFCLASS32 => "32-bit",
|
|
ELFCLASS64 => "64-bit",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
/// Represents the ELF file data format (little-endian vs big-endian)
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct Data(pub u8);
|
|
/// Invalid ELF data format
|
|
pub const ELFDATANONE : Data = Data(0);
|
|
/// little-endian ELF file
|
|
pub const ELFDATA2LSB : Data = Data(1);
|
|
/// big-endian ELF file
|
|
pub const ELFDATA2MSB : Data = Data(2);
|
|
|
|
impl fmt::Debug for Data {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Data {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
ELFDATANONE => "Invalid",
|
|
ELFDATA2LSB => "2's complement, little endian",
|
|
ELFDATA2MSB => "2's complement, big endian",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
/// 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, Clone, PartialEq, Eq)]
|
|
pub struct Version(pub u32);
|
|
/// Invalid version
|
|
pub const EV_NONE : Version = Version(0);
|
|
/// Current version
|
|
pub const EV_CURRENT : Version = Version(1);
|
|
|
|
impl fmt::Debug for Version {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Version {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
EV_NONE => "Invalid",
|
|
EV_CURRENT => "1 (Current)",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
/// Represents the ELF file OS ABI
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct OSABI(pub u8);
|
|
/// Defaults to Unix System V
|
|
pub const ELFOSABI_NONE : OSABI = OSABI(0);
|
|
/// Unix System V
|
|
pub const ELFOSABI_SYSV : OSABI = OSABI(0);
|
|
/// HP-UX
|
|
pub const ELFOSABI_HPUX : OSABI = OSABI(1);
|
|
/// NetBSD
|
|
pub const ELFOSABI_NETBSD : OSABI = OSABI(2);
|
|
/// Linux with GNU extensions
|
|
pub const ELFOSABI_LINUX : OSABI = OSABI(3);
|
|
/// Solaris
|
|
pub const ELFOSABI_SOLARIS : OSABI = OSABI(6);
|
|
/// AIX
|
|
pub const ELFOSABI_AIX : OSABI = OSABI(7);
|
|
/// SGI Irix
|
|
pub const ELFOSABI_IRIX : OSABI = OSABI(8);
|
|
/// FreeBSD
|
|
pub const ELFOSABI_FREEBSD : OSABI = OSABI(9);
|
|
/// Compaq TRU64 UNIX
|
|
pub const ELFOSABI_TRU64 : OSABI = OSABI(10);
|
|
/// Novell Modesto
|
|
pub const ELFOSABI_MODESTO : OSABI = OSABI(11);
|
|
/// OpenBSD
|
|
pub const ELFOSABI_OPENBSD : OSABI = OSABI(12);
|
|
|
|
impl fmt::Debug for OSABI {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for OSABI {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
ELFOSABI_SYSV => "UNIX System V",
|
|
ELFOSABI_HPUX => "HP-UX",
|
|
ELFOSABI_NETBSD => "NetBSD",
|
|
ELFOSABI_LINUX => "Linux with GNU extensions",
|
|
ELFOSABI_SOLARIS => "Solaris",
|
|
ELFOSABI_AIX => "AIX",
|
|
ELFOSABI_IRIX => "SGI Irix",
|
|
ELFOSABI_FREEBSD => "FreeBSD",
|
|
ELFOSABI_TRU64 => "Compaq TRU64 UNIX",
|
|
ELFOSABI_MODESTO => "Novell Modesto",
|
|
ELFOSABI_OPENBSD => "OpenBSD",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
/// Represents the ELF file type (object, executable, shared lib, core)
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct Type(pub u16);
|
|
/// No file type
|
|
pub const ET_NONE : Type = Type(0);
|
|
/// Relocatable object file
|
|
pub const ET_REL : Type = Type(1);
|
|
/// Executable file
|
|
pub const ET_EXEC : Type = Type(2);
|
|
/// Shared library
|
|
pub const ET_DYN : Type = Type(3);
|
|
/// Core file
|
|
pub const ET_CORE : Type = Type(4);
|
|
|
|
impl fmt::Debug for Type {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Type {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
ET_NONE => "No file type",
|
|
ET_REL => "Relocatable file",
|
|
ET_EXEC => "Executable file",
|
|
ET_DYN => "Shared object file",
|
|
ET_CORE => "Core file",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
/// Represents the ELF file machine architecture
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct Machine(pub u16);
|
|
pub const EM_NONE : Machine = Machine(0);
|
|
pub const EM_M32 : Machine = Machine(1);
|
|
pub const EM_SPARC : Machine = Machine(2);
|
|
pub const EM_386 : Machine = Machine(3);
|
|
pub const EM_68K : Machine = Machine(4);
|
|
pub const EM_88K : Machine = Machine(5);
|
|
pub const EM_860 : Machine = Machine(7);
|
|
pub const EM_MIPS : Machine = Machine(8);
|
|
pub const EM_S370 : Machine = Machine(9);
|
|
pub const EM_MIPS_RS3_LE : Machine = Machine(10);
|
|
pub const EM_PARISC : Machine = Machine(15);
|
|
pub const EM_VPP500 : Machine = Machine(17);
|
|
pub const EM_SPARC32PLUS : Machine = Machine(18);
|
|
pub const EM_960 : Machine = Machine(19);
|
|
pub const EM_PPC : Machine = Machine(20);
|
|
pub const EM_PPC64 : Machine = Machine(21);
|
|
pub const EM_S390 : Machine = Machine(22);
|
|
pub const EM_V800 : Machine = Machine(36);
|
|
pub const EM_FR20 : Machine = Machine(37);
|
|
pub const EM_RH32 : Machine = Machine(38);
|
|
pub const EM_RCE : Machine = Machine(39);
|
|
pub const EM_ARM : Machine = Machine(40);
|
|
pub const EM_FAKE_ALPHA : Machine = Machine(41);
|
|
pub const EM_SH : Machine = Machine(42);
|
|
pub const EM_SPARCV9 : Machine = Machine(43);
|
|
pub const EM_TRICORE : Machine = Machine(44);
|
|
pub const EM_ARC : Machine = Machine(45);
|
|
pub const EM_H8_300 : Machine = Machine(46);
|
|
pub const EM_H8_300H : Machine = Machine(47);
|
|
pub const EM_H8S : Machine = Machine(48);
|
|
pub const EM_H8_500 : Machine = Machine(49);
|
|
pub const EM_IA_64 : Machine = Machine(50);
|
|
pub const EM_MIPS_X : Machine = Machine(51);
|
|
pub const EM_COLDFIRE : Machine = Machine(52);
|
|
pub const EM_68HC12 : Machine = Machine(53);
|
|
pub const EM_MMA : Machine = Machine(54);
|
|
pub const EM_PCP : Machine = Machine(55);
|
|
pub const EM_NCPU : Machine = Machine(56);
|
|
pub const EM_NDR1 : Machine = Machine(57);
|
|
pub const EM_STARCORE : Machine = Machine(58);
|
|
pub const EM_ME16 : Machine = Machine(59);
|
|
pub const EM_ST100 : Machine = Machine(60);
|
|
pub const EM_TINYJ : Machine = Machine(61);
|
|
pub const EM_X86_64 : Machine = Machine(62);
|
|
pub const EM_PDSP : Machine = Machine(63);
|
|
pub const EM_FX66 : Machine = Machine(66);
|
|
pub const EM_ST9PLUS : Machine = Machine(67);
|
|
pub const EM_ST7 : Machine = Machine(68);
|
|
pub const EM_68HC16 : Machine = Machine(69);
|
|
pub const EM_68HC11 : Machine = Machine(70);
|
|
pub const EM_68HC08 : Machine = Machine(71);
|
|
pub const EM_68HC05 : Machine = Machine(72);
|
|
pub const EM_SVX : Machine = Machine(73);
|
|
pub const EM_ST19 : Machine = Machine(74);
|
|
pub const EM_VAX : Machine = Machine(75);
|
|
pub const EM_CRIS : Machine = Machine(76);
|
|
pub const EM_JAVELIN : Machine = Machine(77);
|
|
pub const EM_FIREPATH : Machine = Machine(78);
|
|
pub const EM_ZSP : Machine = Machine(79);
|
|
pub const EM_MMIX : Machine = Machine(80);
|
|
pub const EM_HUANY : Machine = Machine(81);
|
|
pub const EM_PRISM : Machine = Machine(82);
|
|
pub const EM_AVR : Machine = Machine(83);
|
|
pub const EM_FR30 : Machine = Machine(84);
|
|
pub const EM_D10V : Machine = Machine(85);
|
|
pub const EM_D30V : Machine = Machine(86);
|
|
pub const EM_V850 : Machine = Machine(87);
|
|
pub const EM_M32R : Machine = Machine(88);
|
|
pub const EM_MN10300 : Machine = Machine(89);
|
|
pub const EM_MN10200 : Machine = Machine(90);
|
|
pub const EM_PJ : Machine = Machine(91);
|
|
pub const EM_OPENRISC : Machine = Machine(92);
|
|
pub const EM_ARC_A5 : Machine = Machine(93);
|
|
pub const EM_XTENSA : Machine = Machine(94);
|
|
pub const EM_AARCH64 : Machine = Machine(183);
|
|
pub const EM_TILEPRO : Machine = Machine(188);
|
|
pub const EM_MICROBLAZE : Machine = Machine(189);
|
|
pub const EM_TILEGX : Machine = Machine(191);
|
|
|
|
impl fmt::Debug for Machine {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Machine {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
EM_NONE => "No machine",
|
|
EM_M32 => "AT&T WE 32100",
|
|
EM_SPARC => "SUN SPARC",
|
|
EM_386 => "Intel 80386",
|
|
EM_68K => "Motorola m68k family",
|
|
EM_88K => "Motorola m88k family",
|
|
EM_860 => "Intel 80860",
|
|
EM_MIPS => "MIPS R3000 big-endian",
|
|
EM_S370 => "IBM System/370",
|
|
EM_MIPS_RS3_LE => "MIPS R3000 little-endian",
|
|
EM_PARISC => "HPPA",
|
|
EM_VPP500 => "Fujitsu VPP500",
|
|
EM_SPARC32PLUS => "Sun's 'v8plus'",
|
|
EM_960 => "Intel 80960",
|
|
EM_PPC => "PowerPC",
|
|
EM_PPC64 => "PowerPC 64-bit",
|
|
EM_S390 => "IBM S390",
|
|
EM_V800 => "NEC V800 series",
|
|
EM_FR20 => "Fujitsu FR20",
|
|
EM_RH32 => "TRW RH-32",
|
|
EM_RCE => "Motorola RCE",
|
|
EM_ARM => "ARM",
|
|
EM_FAKE_ALPHA => "Digital Alpha",
|
|
EM_SH => "Hitachi SH",
|
|
EM_SPARCV9 => "SPARC v9 64-bit",
|
|
EM_TRICORE => "Siemens Tricore",
|
|
EM_ARC => "Argonaut RISC Core",
|
|
EM_H8_300 => "Hitachi H8/300",
|
|
EM_H8_300H => "Hitachi H8/300H",
|
|
EM_H8S => "Hitachi H8S",
|
|
EM_H8_500 => "Hitachi H8/500",
|
|
EM_IA_64 => "Intel Merced",
|
|
EM_MIPS_X => "Stanford MIPS-X",
|
|
EM_COLDFIRE => "Motorola Coldfire",
|
|
EM_68HC12 => "Motorola M68HC12",
|
|
EM_MMA => "Fujitsu MMA Multimedia Accelerato",
|
|
EM_PCP => "Siemens PCP",
|
|
EM_NCPU => "Sony nCPU embeeded RISC",
|
|
EM_NDR1 => "Denso NDR1 microprocessor",
|
|
EM_STARCORE => "Motorola Start*Core processor",
|
|
EM_ME16 => "Toyota ME16 processor",
|
|
EM_ST100 => "STMicroelectronic ST100 processor",
|
|
EM_TINYJ => "Advanced Logic Corp. Tinyj emb.fa",
|
|
EM_X86_64 => "AMD x86-64 architecture",
|
|
EM_PDSP => "Sony DSP Processor",
|
|
EM_FX66 => "Siemens FX66 microcontroller",
|
|
EM_ST9PLUS => "STMicroelectronics ST9+ 8/16 mc",
|
|
EM_ST7 => "STmicroelectronics ST7 8 bit mc",
|
|
EM_68HC16 => "Motorola MC68HC16 microcontroller",
|
|
EM_68HC11 => "Motorola MC68HC11 microcontroller",
|
|
EM_68HC08 => "Motorola MC68HC08 microcontroller",
|
|
EM_68HC05 => "Motorola MC68HC05 microcontroller",
|
|
EM_SVX => "Silicon Graphics SVx",
|
|
EM_ST19 => "STMicroelectronics ST19 8 bit mc",
|
|
EM_VAX => "Digital VAX",
|
|
EM_CRIS => "Axis Communications 32-bit embedded processor",
|
|
EM_JAVELIN => "Infineon Technologies 32-bit embedded processor",
|
|
EM_FIREPATH => "Element 14 64-bit DSP Processor",
|
|
EM_ZSP => "LSI Logic 16-bit DSP Processor",
|
|
EM_MMIX => "Donald Knuth's educational 64-bit processor",
|
|
EM_HUANY => "Harvard University machine-independent object files",
|
|
EM_PRISM => "SiTera Prism",
|
|
EM_AVR => "Atmel AVR 8-bit microcontroller",
|
|
EM_FR30 => "Fujitsu FR30",
|
|
EM_D10V => "Mitsubishi D10V",
|
|
EM_D30V => "Mitsubishi D30V",
|
|
EM_V850 => "NEC v850",
|
|
EM_M32R => "Mitsubishi M32R",
|
|
EM_MN10300 => "Matsushita MN10300",
|
|
EM_MN10200 => "Matsushita MN10200",
|
|
EM_PJ => "picoJava",
|
|
EM_OPENRISC => "OpenRISC 32-bit embedded processor",
|
|
EM_ARC_A5 => "ARC Cores Tangent-A5",
|
|
EM_XTENSA => "Tensilica Xtensa Architecture",
|
|
EM_AARCH64 => "ARM AARCH64",
|
|
EM_TILEPRO => "Tilera TILEPro",
|
|
EM_MICROBLAZE => "Xilinx MicroBlaze",
|
|
EM_TILEGX => "Tilera TILE-Gx",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
/// Encapsulates the contents of the ELF File Header
|
|
///
|
|
/// The ELF File Header starts off every ELF file and both identifies the
|
|
/// 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, Clone, Debug, PartialEq, Eq)]
|
|
pub struct FileHeader {
|
|
/// 32-bit vs 64-bit
|
|
pub class: Class,
|
|
/// little vs big endian
|
|
pub data: Data,
|
|
/// elf version
|
|
pub version: Version,
|
|
/// OS ABI
|
|
pub osabi: OSABI,
|
|
/// Version of the OS ABI
|
|
pub abiversion: u8,
|
|
/// ELF file type
|
|
pub elftype: Type,
|
|
/// Target machine architecture
|
|
pub machine: Machine,
|
|
/// Virtual address of program entry point
|
|
pub entry: u64,
|
|
}
|
|
|
|
impl FileHeader {
|
|
pub fn new() -> FileHeader {
|
|
FileHeader { class : ELFCLASSNONE, data : ELFDATANONE, version : EV_NONE,
|
|
elftype : ET_NONE, machine : EM_NONE, osabi : ELFOSABI_NONE,
|
|
abiversion : 0, entry : 0 }
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for FileHeader {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "File Header for {} {} Elf {} for {} {}", self.class, self.data,
|
|
self.elftype, self.osabi, self.machine)
|
|
}
|
|
}
|
|
|
|
/// Represents ELF Program Header flags
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct ProgFlag(pub u32);
|
|
pub const PF_NONE : ProgFlag = ProgFlag(0);
|
|
/// Executable program segment
|
|
pub const PF_X : ProgFlag = ProgFlag(1);
|
|
/// Writable program segment
|
|
pub const PF_W : ProgFlag = ProgFlag(2);
|
|
/// Readable program segment
|
|
pub const PF_R : ProgFlag = ProgFlag(4);
|
|
|
|
impl fmt::Debug for ProgFlag {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for ProgFlag {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
if (self.0 & PF_R.0) != 0 {
|
|
try!(write!(f, "R"));
|
|
} else {
|
|
try!(write!(f, " "));
|
|
}
|
|
if (self.0 & PF_W.0) != 0 {
|
|
try!(write!(f, "W"));
|
|
} else {
|
|
try!(write!(f, " "));
|
|
}
|
|
if (self.0 & PF_X.0) != 0 {
|
|
write!(f, "E")
|
|
} else {
|
|
write!(f, " ")
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Represents ELF Program Header type
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct ProgType(pub u32);
|
|
/// Program header table entry unused
|
|
pub const PT_NULL : ProgType = ProgType(0);
|
|
/// Loadable program segment
|
|
pub const PT_LOAD : ProgType = ProgType(1);
|
|
/// Dynamic linking information
|
|
pub const PT_DYNAMIC : ProgType = ProgType(2);
|
|
/// Program interpreter
|
|
pub const PT_INTERP : ProgType = ProgType(3);
|
|
/// Auxiliary information
|
|
pub const PT_NOTE : ProgType = ProgType(4);
|
|
/// Unused
|
|
pub const PT_SHLIB : ProgType = ProgType(5);
|
|
/// The program header table
|
|
pub const PT_PHDR : ProgType = ProgType(6);
|
|
/// Thread-local storage segment
|
|
pub const PT_TLS : ProgType = ProgType(7);
|
|
/// GCC .eh_frame_hdr segment
|
|
pub const PT_GNU_EH_FRAME : ProgType = ProgType(0x6474e550);
|
|
/// Indicates stack executability
|
|
pub const PT_GNU_STACK : ProgType = ProgType(0x6474e551);
|
|
/// Read-only after relocation
|
|
pub const PT_GNU_RELRO : ProgType = ProgType(0x6474e552);
|
|
|
|
impl fmt::Debug for ProgType {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for ProgType {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
PT_NULL => "NULL",
|
|
PT_LOAD => "LOAD",
|
|
PT_DYNAMIC => "DYNAMIC",
|
|
PT_INTERP => "INTERP",
|
|
PT_NOTE => "NOTE",
|
|
PT_SHLIB => "SHLIB",
|
|
PT_PHDR => "PHDR",
|
|
PT_TLS => "TLS",
|
|
PT_GNU_EH_FRAME => "GNU_EH_FRAME",
|
|
PT_GNU_STACK => "GNU_STACK",
|
|
PT_GNU_RELRO => "GNU_RELRO",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
/// Encapsulates the contents of an ELF Program Header
|
|
///
|
|
/// The program header table is an array of program header structures describing
|
|
/// the various segments for program execution.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
pub struct ProgramHeader {
|
|
/// Program segment type
|
|
pub progtype: ProgType,
|
|
/// Offset into the ELF file where this segment begins
|
|
pub offset: u64,
|
|
/// Virtual adress where this segment should be loaded
|
|
pub vaddr: u64,
|
|
/// Physical address where this segment should be loaded
|
|
pub paddr: u64,
|
|
/// Size of this segment in the file
|
|
pub filesz: u64,
|
|
/// Size of this segment in memory
|
|
pub memsz: u64,
|
|
/// Flags for this segment
|
|
pub flags: ProgFlag,
|
|
/// file and memory alignment
|
|
pub align: u64,
|
|
}
|
|
|
|
impl fmt::Display for ProgramHeader {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "Program Header: Type: {} Offset: {:#010x} VirtAddr: {:#010x} PhysAddr: {:#010x} FileSize: {:#06x} MemSize: {:#06x} Flags: {} Align: {:#x}",
|
|
self.progtype, self.offset, self.vaddr, self.paddr, self.filesz,
|
|
self.memsz, self.flags, self.align)
|
|
}
|
|
}
|
|
|
|
/// Represens ELF Section type
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct SectionType(pub u32);
|
|
/// Inactive section with undefined values
|
|
pub const SHT_NULL : SectionType = SectionType(0);
|
|
/// Information defined by the program, includes executable code and data
|
|
pub const SHT_PROGBITS : SectionType = SectionType(1);
|
|
/// Section data contains a symbol table
|
|
pub const SHT_SYMTAB : SectionType = SectionType(2);
|
|
/// Section data contains a string table
|
|
pub const SHT_STRTAB : SectionType = SectionType(3);
|
|
/// Section data contains relocation entries with explicit addends
|
|
pub const SHT_RELA : SectionType = SectionType(4);
|
|
/// Section data contains a symbol hash table. Must be present for dynamic linking
|
|
pub const SHT_HASH : SectionType = SectionType(5);
|
|
/// Section data contains information for dynamic linking
|
|
pub const SHT_DYNAMIC : SectionType = SectionType(6);
|
|
/// Section data contains information that marks the file in some way
|
|
pub const SHT_NOTE : SectionType = SectionType(7);
|
|
/// Section data occupies no space in the file but otherwise resembles SHT_PROGBITS
|
|
pub const SHT_NOBITS : SectionType = SectionType(8);
|
|
/// Section data contains relocation entries without explicit addends
|
|
pub const SHT_REL : SectionType = SectionType(9);
|
|
/// Section is reserved but has unspecified semantics
|
|
pub const SHT_SHLIB : SectionType = SectionType(10);
|
|
/// Section data contains a minimal set of dynamic linking symbols
|
|
pub const SHT_DYNSYM : SectionType = SectionType(11);
|
|
/// Section data contains an array of constructors
|
|
pub const SHT_INIT_ARRAY : SectionType = SectionType(14);
|
|
/// Section data contains an array of destructors
|
|
pub const SHT_FINI_ARRAY : SectionType = SectionType(15);
|
|
/// Section data contains an array of pre-constructors
|
|
pub const SHT_PREINIT_ARRAY : SectionType = SectionType(16);
|
|
/// Section group
|
|
pub const SHT_GROUP : SectionType = SectionType(17);
|
|
/// Extended symbol table section index
|
|
pub const SHT_SYMTAB_SHNDX : SectionType = SectionType(18);
|
|
/// Number of reserved SHT_* values
|
|
pub const SHT_NUM : SectionType = SectionType(19);
|
|
/// Object attributes
|
|
pub const SHT_GNU_ATTRIBUTES : SectionType = SectionType(0x6ffffff5);
|
|
/// GNU-style hash section
|
|
pub const SHT_GNU_HASH : SectionType = SectionType(0x6ffffff6);
|
|
/// Pre-link library list
|
|
pub const SHT_GNU_LIBLIST : SectionType = SectionType(0x6ffffff7);
|
|
/// Version definition section
|
|
pub const SHT_GNU_VERDEF : SectionType = SectionType(0x6ffffffd);
|
|
/// Version needs section
|
|
pub const SHT_GNU_VERNEED : SectionType = SectionType(0x6ffffffe);
|
|
/// Version symbol table
|
|
pub const SHT_GNU_VERSYM : SectionType = SectionType(0x6fffffff);
|
|
|
|
impl fmt::Debug for SectionType {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for SectionType {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
SHT_NULL => "SHT_NULL",
|
|
SHT_PROGBITS => "SHT_PROGBITS",
|
|
SHT_SYMTAB => "SHT_SYMTAB",
|
|
SHT_STRTAB => "SHT_STRTAB",
|
|
SHT_RELA => "SHT_RELA",
|
|
SHT_HASH => "SHT_HASH",
|
|
SHT_DYNAMIC => "SHT_DYNAMIC",
|
|
SHT_NOTE => "SHT_NOTE",
|
|
SHT_NOBITS => "SHT_NOBITS",
|
|
SHT_REL => "SHT_REL",
|
|
SHT_SHLIB => "SHT_SHLIB",
|
|
SHT_DYNSYM => "SHT_DYNSYM",
|
|
SHT_INIT_ARRAY => "SHT_INIT_ARRAY",
|
|
SHT_FINI_ARRAY => "SHT_FINI_ARRAY",
|
|
SHT_PREINIT_ARRAY => "SHT_PREINIT_ARRAY",
|
|
SHT_GROUP => "SHT_GROUP",
|
|
SHT_SYMTAB_SHNDX => "SHT_SYMTAB_SHNDX",
|
|
SHT_NUM => "SHT_NUM",
|
|
SHT_GNU_ATTRIBUTES => "SHT_GNU_ATTRIBUTES",
|
|
SHT_GNU_HASH => "SHT_GNU_HASH",
|
|
SHT_GNU_LIBLIST => "SHT_GNU_LIBLIST",
|
|
SHT_GNU_VERDEF => "SHT_GNU_VERDEF",
|
|
SHT_GNU_VERNEED => "SHT_GNU_VERNEED",
|
|
SHT_GNU_VERSYM => "SHT_GNU_VERSYM",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
///
|
|
/// Wrapper type for SectionFlag
|
|
///
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct SectionFlag(pub u64);
|
|
/// Empty flags
|
|
pub const SHF_NONE : SectionFlag = SectionFlag(0);
|
|
/// Writable
|
|
pub const SHF_WRITE : SectionFlag = SectionFlag(1);
|
|
/// Occupies memory during execution
|
|
pub const SHF_ALLOC : SectionFlag = SectionFlag(2);
|
|
/// Executable
|
|
pub const SHF_EXECINSTR : SectionFlag = SectionFlag(4);
|
|
/// Might be merged
|
|
pub const SHF_MERGE : SectionFlag = SectionFlag(16);
|
|
/// Contains nul-terminated strings
|
|
pub const SHF_STRINGS : SectionFlag = SectionFlag(32);
|
|
/// `sh_info' contains SHT index
|
|
pub const SHF_INFO_LINK : SectionFlag = SectionFlag(64);
|
|
/// Preserve order after combining
|
|
pub const SHF_LINK_ORDER : SectionFlag = SectionFlag(128);
|
|
/// Non-standard OS specific handling required
|
|
pub const SHF_OS_NONCONFORMING : SectionFlag = SectionFlag(256);
|
|
/// Section is member of a group
|
|
pub const SHF_GROUP : SectionFlag = SectionFlag(512);
|
|
/// Section hold thread-local data
|
|
pub const SHF_TLS : SectionFlag = SectionFlag(1024);
|
|
|
|
impl fmt::Debug for SectionFlag {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for SectionFlag {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "{:#x}", self.0)
|
|
}
|
|
}
|
|
|
|
/// Encapsulates the contents of an ELF Section Header
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub struct SectionHeader {
|
|
/// Section Name
|
|
pub name: String,
|
|
/// Section Type
|
|
pub shtype: SectionType,
|
|
/// Section Flags
|
|
pub flags: SectionFlag,
|
|
/// in-memory address where this section is loaded
|
|
pub addr: u64,
|
|
/// Byte-offset into the file where this section starts
|
|
pub offset: u64,
|
|
/// Section size in bytes
|
|
pub size: u64,
|
|
/// Defined by section type
|
|
pub link: u32,
|
|
/// Defined by section type
|
|
pub info: u32,
|
|
/// address alignment
|
|
pub addralign: u64,
|
|
/// size of an entry if section data is an array of entries
|
|
pub entsize: u64,
|
|
}
|
|
|
|
impl fmt::Display for SectionHeader {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "Section Header: Name: {} Type: {} Flags: {} Addr: {:#010x} Offset: {:#06x} Size: {:#06x} Link: {} Info: {:#x} AddrAlign: {} EntSize: {}",
|
|
self.name, self.shtype, self.flags, self.addr, self.offset,
|
|
self.size, self.link, self.info, self.addralign, self.entsize)
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct SymbolType(pub u8);
|
|
/// Unspecified symbol type
|
|
pub const STT_NOTYPE : SymbolType = SymbolType(0);
|
|
/// Data object symbol
|
|
pub const STT_OBJECT : SymbolType = SymbolType(1);
|
|
/// Code object symbol
|
|
pub const STT_FUNC : SymbolType = SymbolType(2);
|
|
/// Section symbol
|
|
pub const STT_SECTION : SymbolType = SymbolType(3);
|
|
/// File name symbol
|
|
pub const STT_FILE : SymbolType = SymbolType(4);
|
|
/// Common data object symbol
|
|
pub const STT_COMMON : SymbolType = SymbolType(5);
|
|
/// Thread-local data object symbol
|
|
pub const STT_TLS : SymbolType = SymbolType(6);
|
|
/// Indirect code object symbol
|
|
pub const STT_GNU_IFUNC : SymbolType = SymbolType(10);
|
|
|
|
impl fmt::Display for SymbolType {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
STT_NOTYPE => "unspecified",
|
|
STT_OBJECT => "data object",
|
|
STT_FUNC => "code object",
|
|
STT_SECTION => "section",
|
|
STT_FILE => "file name",
|
|
STT_COMMON => "common data object",
|
|
STT_TLS => "thread-local data object",
|
|
STT_GNU_IFUNC => "indirect code object",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct SymbolBind(pub u8);
|
|
/// Local symbol
|
|
pub const STB_LOCAL : SymbolBind = SymbolBind(0);
|
|
/// Global symbol
|
|
pub const STB_GLOBAL : SymbolBind = SymbolBind(1);
|
|
/// Weak symbol
|
|
pub const STB_WEAK : SymbolBind = SymbolBind(2);
|
|
/// Unique symbol
|
|
pub const STB_GNU_UNIQUE : SymbolBind = SymbolBind(10);
|
|
|
|
impl fmt::Display for SymbolBind {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
STB_LOCAL => "local",
|
|
STB_GLOBAL => "global",
|
|
STB_WEAK => "weak",
|
|
STB_GNU_UNIQUE => "unique",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
|
pub struct SymbolVis(pub u8);
|
|
/// Default symbol visibility
|
|
pub const STV_DEFAULT : SymbolVis = SymbolVis(0);
|
|
/// Processor-specific hidden visibility
|
|
pub const STV_INTERNAL : SymbolVis = SymbolVis(1);
|
|
/// Hidden visibility
|
|
pub const STV_HIDDEN : SymbolVis = SymbolVis(2);
|
|
/// Protected visibility
|
|
pub const STV_PROTECTED : SymbolVis = SymbolVis(3);
|
|
|
|
impl fmt::Display for SymbolVis {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
let str = match *self {
|
|
STV_DEFAULT => "default",
|
|
STV_INTERNAL => "internal",
|
|
STV_HIDDEN => "hidden",
|
|
STV_PROTECTED => "protected",
|
|
_ => "Unknown",
|
|
};
|
|
write!(f, "{}", str)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq)]
|
|
pub struct Symbol {
|
|
/// Symbol name
|
|
pub name: String,
|
|
/// Symbol value
|
|
pub value: u64,
|
|
/// Symbol size
|
|
pub size: u64,
|
|
/// Section index
|
|
pub shndx: u16,
|
|
/// Symbol type
|
|
pub symtype: SymbolType,
|
|
/// Symbol binding
|
|
pub bind: SymbolBind,
|
|
/// Symbol visibility
|
|
pub vis: SymbolVis,
|
|
}
|
|
|
|
impl fmt::Display for Symbol {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "Symbol: Value: {:#010x} Size: {:#06x} Type: {} Bind: {} Vis: {} Section: {} Name: {}",
|
|
self.value, self.size, self.symtype, self.bind, self.vis, self.shndx, self.name)
|
|
}
|
|
}
|