use colored::Colorize;
use goblin::elf::program_header::{PF_R, PF_W, PF_X};
use goblin::elf::Elf;
use crate::display::{
format_flags, print_field, print_field_with_raw, print_indexed_item, print_title,
};
pub fn display_program_headers(elf: &Elf) {
print_title("Program Headers (Segments)");
if elf.program_headers.is_empty() {
println!(" {}", "No program headers".dimmed());
return;
}
println!(
" {} program headers at offset {:#X}\n",
elf.program_headers.len().to_string().cyan(),
elf.header.e_phoff
);
for (i, ph) in elf.program_headers.iter().enumerate() {
display_program_header(i, ph);
}
}
fn display_program_header(index: usize, ph: &goblin::elf::ProgramHeader) {
let type_str = segment_type_to_string(ph.p_type);
print_indexed_item(index, type_str);
print_field_with_raw("Type", type_str, &format!("0x{:08X}", ph.p_type));
let flags_str = format_segment_flags(ph.p_flags);
print_field_with_raw("Flags", &flags_str, &format!("0x{:X}", ph.p_flags));
print_field("Offset", &format!("{:#018X}", ph.p_offset));
print_field("Virtual Address", &format!("{:#018X}", ph.p_vaddr));
print_field("Physical Address", &format!("{:#018X}", ph.p_paddr));
print_field(
"File Size",
&format!("{:#X} ({} bytes)", ph.p_filesz, ph.p_filesz),
);
print_field(
"Memory Size",
&format!("{:#X} ({} bytes)", ph.p_memsz, ph.p_memsz),
);
print_field("Alignment", &format!("{:#X}", ph.p_align));
println!();
}
fn segment_type_to_string(p_type: u32) -> &'static str {
match p_type {
0 => "PT_NULL (Unused)",
1 => "PT_LOAD (Loadable segment)",
2 => "PT_DYNAMIC (Dynamic linking info)",
3 => "PT_INTERP (Interpreter path)",
4 => "PT_NOTE (Auxiliary info)",
5 => "PT_SHLIB (Reserved)",
6 => "PT_PHDR (Program header table)",
7 => "PT_TLS (Thread-local storage)",
0x6474E550 => "PT_GNU_EH_FRAME (Exception handling)",
0x6474E551 => "PT_GNU_STACK (Stack executability)",
0x6474E552 => "PT_GNU_RELRO (Read-only after reloc)",
0x6474E553 => "PT_GNU_PROPERTY (GNU property)",
0x6FFFFFFA => "PT_SUNWBSS (Sun-specific BSS)",
0x6FFFFFFB => "PT_SUNWSTACK (Sun stack segment)",
pt if (0x60000000..=0x6FFFFFFF).contains(&pt) => "PT_LOOS..PT_HIOS (OS-specific)",
pt if (0x70000000..=0x7FFFFFFF).contains(&pt) => "PT_LOPROC..PT_HIPROC (Processor-specific)",
_ => "Unknown",
}
}
fn format_segment_flags(flags: u32) -> String {
let r = flags & PF_R != 0;
let w = flags & PF_W != 0;
let x = flags & PF_X != 0;
let rwx = format_flags(r, w, x);
let mut parts = vec![rwx];
let extra = flags & !(PF_R | PF_W | PF_X);
if extra != 0 {
parts.push(format!("+0x{:X}", extra));
}
parts.join(" ")
}
pub fn segment_type_short(p_type: u32) -> &'static str {
match p_type {
0 => "NULL",
1 => "LOAD",
2 => "DYNAMIC",
3 => "INTERP",
4 => "NOTE",
5 => "SHLIB",
6 => "PHDR",
7 => "TLS",
0x6474E550 => "GNU_EH_FRAME",
0x6474E551 => "GNU_STACK",
0x6474E552 => "GNU_RELRO",
0x6474E553 => "GNU_PROPERTY",
_ => "UNKNOWN",
}
}