diff --git a/src/rust-readelf.rs b/src/rust-readelf.rs index a7e15d9..f0c990d 100644 --- a/src/rust-readelf.rs +++ b/src/rust-readelf.rs @@ -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 +} + // _____ _ _ _ _ _ // | ___(_) | ___| | | | ___ __ _ __| | ___ _ __ // | |_ | | |/ _ \ |_| |/ _ \/ _` |/ _` |/ _ \ '__| @@ -95,12 +101,14 @@ fn print_file_header(ehdr: &elf::file::FileHeader) { // fn print_program_headers(elf_file: &mut ElfStream) { - 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 = 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(), @@ -112,7 +120,126 @@ fn print_program_headers(elf_file: &mut ElfStream) { ]; table.add_row(cells); } + println!("Program Headers (Segments):"); + println!(); println!("{table}"); + println!(); +} + +fn print_segment_mapping(elf_file: &mut ElfStream) { + 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 = 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 { + "" + } else { + sec_strtab.get(sec.sh_name.try_into().unwrap()).unwrap() + }; + section_names.push(name.to_string()); + } + } + + let cells: Vec = 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; } // ____ _ _ _ _ _ @@ -127,7 +254,7 @@ fn print_section_table(elf_file: &mut ElfStream) { .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", @@ -160,7 +287,10 @@ fn print_section_table(elf_file: &mut ElfStream) { ]; table.add_row(cells); } + println!("Section Headers:"); + println!(); println!("{table}"); + println!(); } // ____ _ _ _____ _ _ @@ -182,7 +312,7 @@ fn print_symbol_table(elf_file: &mut ElfStream) { } }; - let mut table = Table::new(); + let mut table = table(); table.set_header([ "ndx", "value", @@ -209,7 +339,10 @@ fn print_symbol_table(elf_file: &mut ElfStream) { ]; table.add_row(cells); } + println!("Symbol Table:"); + println!(); println!("{table}"); + println!(); } // ____ ____ @@ -249,7 +382,7 @@ fn print_dynamic_symbol_table(elf_file: &mut ElfStream .symbol_version_table() .expect("Failed to parse GNU symbol versions"); - let mut table = Table::new(); + let mut table = table(); table.set_header([ "ndx", "value", @@ -291,7 +424,10 @@ fn print_dynamic_symbol_table(elf_file: &mut ElfStream ]; table.add_row(cells); } + println!("Dynamic symbols:"); + println!(); println!("{table}"); + println!(); } // _ _ @@ -310,7 +446,7 @@ fn print_dynamic(elf_file: &mut ElfStream) { } }; - 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) @@ -321,7 +457,10 @@ fn print_dynamic(elf_file: &mut ElfStream) { ]; table.add_row(cells); } + println!("Dynamic:"); + println!(); println!("{table}"); + println!(); } // _ @@ -332,7 +471,7 @@ fn print_dynamic(elf_file: &mut ElfStream) { // fn print_rels(rels: RelIterator) { - 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 = vec![ @@ -342,11 +481,14 @@ fn print_rels(rels: RelIterator) { ]; table.add_row(cells); } + println!("Rels:"); + println!(); println!("{table}"); + println!(); } fn print_relas(relas: RelaIterator) { - 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 = vec![ @@ -357,7 +499,10 @@ fn print_relas(relas: RelaIterator) { ]; table.add_row(cells); } + println!("Relas:"); + println!(); println!("{table}"); + println!(); } fn print_relocations(elf_file: &mut ElfStream) { @@ -431,7 +576,7 @@ fn print_notes(elf_file: &mut ElfStream) { println!(); } Note::Unknown(any) => { - let mut table = Table::new(); + let mut table = table(); table.set_header(["type", "name", "desc"]); let cells: Vec = vec![ any.n_type.into(), @@ -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 {