Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 156 additions & 10 deletions src/rust-readelf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ struct Args {
notes: bool,
}

fn table() -> Table {
let mut table = Table::new();
table.load_preset(comfy_table::presets::UTF8_NO_BORDERS);
table
}

// _____ _ _ _ _ _
// | ___(_) | ___| | | | ___ __ _ __| | ___ _ __
// | |_ | | |/ _ \ |_| |/ _ \/ _` |/ _` |/ _ \ '__|
Expand Down Expand Up @@ -95,12 +101,14 @@ fn print_file_header(ehdr: &elf::file::FileHeader<AnyEndian>) {
//

fn print_program_headers(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
let mut table = Table::new();
let mut table = table();
table.set_header([
"p_type", "p_offset", "p_vaddr", "p_paddr", "p_filesz", "p_memsz", "p_align", "p_flags",
"Idx", "p_type", "p_offset", "p_vaddr", "p_paddr", "p_filesz", "p_memsz", "p_align",
"p_flags",
]);
for phdr in elf_file.segments() {
for (i, phdr) in elf_file.segments().iter().enumerate() {
let cells: Vec<Cell> = vec![
i.into(),
elf::to_str::p_type_to_string(phdr.p_type).into(),
format!("{:#x}", phdr.p_offset).into(),
format!("{:#x}", phdr.p_vaddr).into(),
Expand All @@ -112,7 +120,126 @@ fn print_program_headers(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
];
table.add_row(cells);
}
println!("Program Headers (Segments):");
println!();
println!("{table}");
println!();
}

fn print_segment_mapping(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
use elf::abi::{PT_TLS, SHF_TLS, SHT_NOBITS, SHT_NULL};

let mut table = table();
table.set_header(["Segment", "Sections"]);

let segments = elf_file.segments().to_vec();
for (i, seg) in segments.iter().enumerate() {
let (sections, sec_strtab) = elf_file
.section_headers_with_strtab()
.expect("Could not get section headers");
let sec_strtab = sec_strtab.expect("Could not get section header strtab");

let mut section_names: Vec<String> = vec![];
for sec in sections {
if sec.sh_type == SHT_NULL {
continue;
}
if ((sec.sh_flags as u32 & SHF_TLS) != 0)
&& sec.sh_type == SHT_NOBITS
&& seg.p_type == PT_TLS
{
// .tbss
continue;
}

if elf_section_in_segment(sec, seg) {
let name = if sec.sh_name == 0 {
"<null>"
} else {
sec_strtab.get(sec.sh_name.try_into().unwrap()).unwrap()
};
section_names.push(name.to_string());
}
}

let cells: Vec<Cell> = vec![i.into(), section_names.join("\n").into()];
table.add_row(cells);
}
println!(" Section to segment mapping:");
println!();
println!("{table}");
println!();
}

fn elf_section_in_segment(
sec: &elf::section::SectionHeader,
seg: &elf::segment::ProgramHeader,
) -> bool {
// References:
// * binutils: ELF_SECTION_IN_SEGMENT_STRICT
// * pyelftools: Segment.section_in_segment()
use elf::abi::{
PT_DYNAMIC, PT_GNU_EH_FRAME, PT_GNU_RELRO, PT_GNU_STACK, PT_LOAD, PT_PHDR, PT_TLS,
SHF_ALLOC, SHF_TLS, SHT_NOBITS,
};

// Only PT_LOAD, PT_GNU_RELRO and PT_TLS segments can contain SHF_TLS sections.
if (sec.sh_flags as u32 & SHF_TLS) != 0 {
match seg.p_type {
PT_TLS | PT_GNU_RELRO | PT_LOAD => (),
_ => return false,
}
} else {
// PT_TLS segment contains only SHF_TLS sections, PT_PHDR no sections at all
match seg.p_type {
PT_TLS | PT_PHDR => return false,
_ => (),
}
}

// PT_LOAD and similar segments only have SHF_ALLOC sections.
if (sec.sh_flags as u32 & SHF_ALLOC) == 0 {
match seg.p_type {
PT_LOAD | PT_DYNAMIC | PT_GNU_EH_FRAME | PT_GNU_RELRO | PT_GNU_STACK => return false,
_ => (),
}
} else {
// For SHF_ALLOC section, see if its VMA is contained by the segment.
let sec_start = sec.sh_addr;
let sec_end = sec_start + sec.sh_size;

let seg_start = seg.p_vaddr;
let seg_end = seg_start + seg.p_memsz;

if sec_start < seg_start {
return false;
}
if sec_end > seg_end {
return false;
}
}

if sec.sh_type == SHT_NOBITS {
return true;
}

// Verify file offsets
{
let sec_f_start = sec.sh_offset;
let sec_f_end = sec_f_start + sec.sh_size;

let seg_f_start = seg.p_offset;
let seg_f_end = seg_f_start + seg.p_filesz;

if sec_f_start < seg_f_start {
return false;
}
if sec_f_end > seg_f_end {
return false;
}
}

return true;
}

// ____ _ _ _ _ _
Expand All @@ -127,7 +254,7 @@ fn print_section_table(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
.section_headers_with_strtab()
.expect("Failed to read section table and string table");
let (shdrs, strtab) = (shdrs, strtab.unwrap());
let mut table = Table::new();
let mut table = table();
table.set_header([
"index",
"name",
Expand Down Expand Up @@ -160,7 +287,10 @@ fn print_section_table(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
];
table.add_row(cells);
}
println!("Section Headers:");
println!();
println!("{table}");
println!();
}

// ____ _ _ _____ _ _
Expand All @@ -182,7 +312,7 @@ fn print_symbol_table(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
}
};

let mut table = Table::new();
let mut table = table();
table.set_header([
"ndx",
"value",
Expand All @@ -209,7 +339,10 @@ fn print_symbol_table(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
];
table.add_row(cells);
}
println!("Symbol Table:");
println!();
println!("{table}");
println!();
}

// ____ ____
Expand Down Expand Up @@ -249,7 +382,7 @@ fn print_dynamic_symbol_table(elf_file: &mut ElfStream<AnyEndian, std::fs::File>
.symbol_version_table()
.expect("Failed to parse GNU symbol versions");

let mut table = Table::new();
let mut table = table();
table.set_header([
"ndx",
"value",
Expand Down Expand Up @@ -291,7 +424,10 @@ fn print_dynamic_symbol_table(elf_file: &mut ElfStream<AnyEndian, std::fs::File>
];
table.add_row(cells);
}
println!("Dynamic symbols:");
println!();
println!("{table}");
println!();
}

// _ _
Expand All @@ -310,7 +446,7 @@ fn print_dynamic(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
}
};

let mut table = Table::new();
let mut table = table();
table.set_header(["d_tag", "d_ptr/d_val"]);
for d in dyns.iter() {
let d_tag_str = elf::to_str::d_tag_to_str(d.d_tag)
Expand All @@ -321,7 +457,10 @@ fn print_dynamic(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
];
table.add_row(cells);
}
println!("Dynamic:");
println!();
println!("{table}");
println!();
}

// _
Expand All @@ -332,7 +471,7 @@ fn print_dynamic(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
//

fn print_rels(rels: RelIterator<AnyEndian>) {
let mut table = Table::new();
let mut table = table();
table.set_header(["r_type", "r_sym", "r_offset"]);
for r in rels {
let cells: Vec<Cell> = vec![
Expand All @@ -342,11 +481,14 @@ fn print_rels(rels: RelIterator<AnyEndian>) {
];
table.add_row(cells);
}
println!("Rels:");
println!();
println!("{table}");
println!();
}

fn print_relas(relas: RelaIterator<AnyEndian>) {
let mut table = Table::new();
let mut table = table();
table.set_header(["r_type", "r_sym", "r_offset", "r_addend"]);
for r in relas {
let cells: Vec<Cell> = vec![
Expand All @@ -357,7 +499,10 @@ fn print_relas(relas: RelaIterator<AnyEndian>) {
];
table.add_row(cells);
}
println!("Relas:");
println!();
println!("{table}");
println!();
}

fn print_relocations(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
Expand Down Expand Up @@ -431,7 +576,7 @@ fn print_notes(elf_file: &mut ElfStream<AnyEndian, std::fs::File>) {
println!();
}
Note::Unknown(any) => {
let mut table = Table::new();
let mut table = table();
table.set_header(["type", "name", "desc"]);
let cells: Vec<Cell> = vec![
any.n_type.into(),
Expand Down Expand Up @@ -461,6 +606,7 @@ fn main() {

if args.program_headers {
print_program_headers(&mut elf_file);
print_segment_mapping(&mut elf_file);
}

if args.section_headers {
Expand Down