use goblin::elf::Elf;
use crate::display::{
print_address, print_field, print_field_with_raw, print_section, print_title,
};
pub fn display_header(elf: &Elf) {
print_title("ELF Header");
display_e_ident(elf);
display_core_fields(elf);
display_addresses(elf);
}
fn display_e_ident(elf: &Elf) {
print_section("e_ident");
let magic = format!(
"{:02X} {:02X} {:02X} {:02X}",
elf.header.e_ident[0], elf.header.e_ident[1], elf.header.e_ident[2], elf.header.e_ident[3]
);
print_field_with_raw("Magic", "(ELF)", &magic);
let class = elf.header.e_ident[4];
let class_str = match class {
1 => "32-bit",
2 => "64-bit",
_ => "Unknown",
};
print_field_with_raw("Class (EI_CLASS)", class_str, &format!("{}", class));
let data = elf.header.e_ident[5];
let data_str = match data {
1 => "little endian",
2 => "big endian",
_ => "Unknown",
};
print_field_with_raw("Data (EI_DATA)", data_str, &format!("{}", data));
let version = elf.header.e_ident[6];
let version_str = match version {
1 => "current",
_ => "unknown",
};
print_field_with_raw("Version (EI_VERSION)", version_str, &format!("{}", version));
let osabi = elf.header.e_ident[7];
print_field_with_raw(
"OS/ABI (EI_OSABI)",
osabi_to_string(osabi),
&format!("{}", osabi),
);
let abi_version = elf.header.e_ident[8];
print_field("ABI Version (EI_ABIVERSION)", &format!("{}", abi_version));
}
fn display_core_fields(elf: &Elf) {
print_section("Core");
let e_type = elf.header.e_type;
let type_str = match e_type {
0 => "No file type - ET_NONE",
1 => "Relocatable file - ET_REL",
2 => "Executable file - ET_EXEC",
3 => "Shared object file - ET_DYN",
4 => "Core file - ET_CORE",
_ => "Unknown",
};
print_field_with_raw("Type (e_type)", type_str, &format!("0x{:04X}", e_type));
let e_machine = elf.header.e_machine;
let machine_str = machine_to_string(e_machine);
print_field_with_raw(
"Machine (e_machine)",
machine_str,
&format!("0x{:04X}", e_machine),
);
print_field_with_raw(
"Version (e_version)",
if elf.header.e_version == 1 {
"1 (current)"
} else {
"0"
},
&format!("0x{:08X}", elf.header.e_version),
);
print_field_with_raw(
"Flags (e_flags)",
&format_flags(elf.header.e_flags, e_machine),
&format!("0x{:08X}", elf.header.e_flags),
);
print_field(
"ELF Header Size (e_ehsize)",
&format!("{} bytes", elf.header.e_ehsize),
);
}
fn display_addresses(elf: &Elf) {
print_section("Addresses / Offsets");
print_address("Entry Point (e_entry)", elf.header.e_entry);
print_address("Program Headers Offset (e_phoff)", elf.header.e_phoff);
print_address("Section Headers Offset (e_shoff)", elf.header.e_shoff);
print_field(
"Program Header Size (e_phentsize)",
&format!("{} bytes", elf.header.e_phentsize),
);
print_field(
"Program Header Count (e_phnum)",
&format!("{}", elf.header.e_phnum),
);
print_field(
"Section Header Size (e_shentsize)",
&format!("{} bytes", elf.header.e_shentsize),
);
print_field(
"Section Header Count (e_shnum)",
&format!("{}", elf.header.e_shnum),
);
print_field(
"Section Name String Table Index (e_shstrndx)",
&format!("{}", elf.header.e_shstrndx),
);
}
pub fn osabi_to_string(osabi: u8) -> &'static str {
match osabi {
0 => "System V",
1 => "HP-UX",
2 => "NetBSD",
3 => "Linux",
4 => "GNU Hurd",
6 => "Solaris",
7 => "AIX",
8 => "IRIX",
9 => "FreeBSD",
10 => "Tru64",
11 => "Novell Modesto",
12 => "OpenBSD",
13 => "OpenVMS",
14 => "NonStop Kernel",
15 => "AROS",
16 => "FenixOS",
17 => "Nuxi CloudABI",
18 => "OpenVOS",
97 => "ARM EABI",
255 => "Standalone (embedded)",
_ => "Unknown",
}
}
pub fn machine_to_string(machine: u16) -> &'static str {
match machine {
0 => "No machine",
1 => "AT&T WE 32100",
2 => "SPARC",
3 => "Intel 80386",
4 => "Motorola 68000",
5 => "Motorola 88000",
6 => "Intel MCU",
7 => "Intel 80860",
8 => "MIPS I",
9 => "IBM System/370",
10 => "MIPS RS3000 LE",
15 => "HP PA-RISC",
17 => "Fujitsu VPP500",
18 => "Enhanced SPARC",
19 => "Intel 80960",
20 => "PowerPC",
21 => "PowerPC 64-bit",
22 => "IBM S/390",
23 => "IBM SPU/SPC",
36 => "NEC V800",
37 => "Fujitsu FR20",
38 => "TRW RH-32",
39 => "Motorola RCE",
40 => "ARM (up to ARMv7)",
41 => "DEC Alpha",
42 => "SuperH",
43 => "SPARC V9",
44 => "Siemens TriCore",
45 => "Argonaut RISC Core",
46 => "Hitachi H8/300",
47 => "Hitachi H8/300H",
48 => "Hitachi H8S",
49 => "Hitachi H8/500",
50 => "Intel Itanium",
51 => "Stanford MIPS-X",
52 => "Motorola ColdFire",
53 => "Motorola M68HC12",
54 => "Fujitsu MMA",
55 => "Siemens PCP",
56 => "Sony nCPU",
57 => "Denso NDR1",
58 => "Motorola Star*Core",
59 => "Toyota ME16",
60 => "STMicro ST100",
61 => "TinyJ",
62 => "AMD x86-64",
63 => "Sony DSP",
64 => "DEC PDP-10",
65 => "DEC PDP-11",
66 => "Siemens FX66",
67 => "STMicro ST9+",
68 => "STMicro ST7",
69 => "Motorola MC68HC16",
70 => "Motorola MC68HC11",
71 => "Motorola MC68HC08",
72 => "Motorola MC68HC05",
73 => "Silicon Graphics SVx",
74 => "STMicro ST19",
75 => "Digital VAX",
76 => "Axis CRIS",
77 => "Infineon JAVELIN",
78 => "Element 14 Firepath",
79 => "LSI ZSP",
80 => "MMIX",
81 => "Harvard HUANY",
82 => "SiTera Prism",
83 => "Atmel AVR",
84 => "Fujitsu FR30",
85 => "Mitsubishi D10V",
86 => "Mitsubishi D30V",
87 => "NEC v850",
88 => "Mitsubishi M32R",
89 => "Matsushita MN10300",
90 => "Matsushita MN10200",
91 => "picoJava",
92 => "OpenRISC",
93 => "ARC Tangent-A5",
94 => "Tensilica Xtensa",
95 => "Alphamosaic VideoCore",
96 => "Thompson Multimedia GPP",
97 => "National Semiconductor 32000",
98 => "Tenor Network TPC",
99 => "Trebia SNP 1000",
100 => "STMicro ST200",
164 => "Tilera TILEPro",
183 => "ARM AArch64",
188 => "Tilera TILE-Gx",
243 => "RISC-V",
247 => "Linux BPF",
252 => "C-SKY",
258 => "LoongArch",
_ => "Unknown",
}
}
fn format_flags(flags: u32, machine: u16) -> String {
if flags == 0 {
return String::from("none");
}
match machine {
40 | 183 => format_arm_flags(flags), 62 => format_x86_64_flags(flags), _ => format!("0x{:08X}", flags),
}
}
fn format_arm_flags(flags: u32) -> String {
let mut parts = Vec::new();
let eabi = (flags >> 24) & 0xFF;
if eabi > 0 {
parts.push(format!("EABI{}", eabi));
}
if flags & 0x00000200 != 0 {
parts.push("soft-float".to_string());
}
if flags & 0x00000400 != 0 {
parts.push("hard-float".to_string());
}
if parts.is_empty() {
format!("0x{:08X}", flags)
} else {
parts.join(", ")
}
}
fn format_x86_64_flags(_flags: u32) -> String {
String::from("none")
}