2020-12-29 11:04:29 +03:00
/*
2022-01-20 00:50:58 +03:00
* Copyright ( c ) 2020 - 2022 , the SerenityOS developers .
2020-12-29 11:04:29 +03:00
*
2021-04-22 11:24:48 +03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-12-29 11:04:29 +03:00
*/
2022-12-04 21:02:33 +03:00
# include <AK/DeprecatedString.h>
2022-10-28 17:30:27 +03:00
# include <AK/LexicalPath.h>
2020-12-29 11:04:29 +03:00
# include <AK/StringBuilder.h>
# include <AK/StringView.h>
# include <LibCore/ArgsParser.h>
2021-11-23 13:32:25 +03:00
# include <LibCore/MappedFile.h>
2022-03-21 10:59:45 +03:00
# include <LibCore/System.h>
2021-03-22 08:58:28 +03:00
# include <LibELF/DynamicLoader.h>
# include <LibELF/DynamicObject.h>
2020-12-29 11:04:29 +03:00
# include <LibELF/Image.h>
# include <LibELF/Validation.h>
2022-03-21 10:59:45 +03:00
# include <LibMain/Main.h>
2020-12-29 11:04:29 +03:00
# include <ctype.h>
2021-04-11 06:53:37 +03:00
# include <fcntl.h>
2020-12-29 11:04:29 +03:00
# include <stdio.h>
2021-03-12 19:29:37 +03:00
# include <unistd.h>
2020-12-29 11:04:29 +03:00
2022-04-01 20:58:27 +03:00
static char const * object_program_header_type_to_string ( ElfW ( Word ) type )
2020-12-29 11:04:29 +03:00
{
switch ( type ) {
case PT_NULL :
return " NULL " ;
case PT_LOAD :
return " LOAD " ;
case PT_DYNAMIC :
return " DYNAMIC " ;
case PT_INTERP :
return " INTERP " ;
case PT_NOTE :
return " NOTE " ;
case PT_SHLIB :
return " SHLIB " ;
case PT_PHDR :
return " PHDR " ;
case PT_TLS :
return " TLS " ;
case PT_LOOS :
return " LOOS " ;
case PT_HIOS :
return " HIOS " ;
case PT_LOPROC :
return " LOPROC " ;
case PT_HIPROC :
return " HIPROC " ;
case PT_GNU_EH_FRAME :
return " GNU_EH_FRAME " ;
case PT_GNU_RELRO :
return " GNU_RELRO " ;
case PT_GNU_STACK :
return " GNU_STACK " ;
case PT_OPENBSD_RANDOMIZE :
return " OPENBSD_RANDOMIZE " ;
case PT_OPENBSD_WXNEEDED :
return " OPENBSD_WXNEEDED " ;
case PT_OPENBSD_BOOTDATA :
return " OPENBSD_BOOTDATA " ;
default :
return " (?) " ;
}
}
2022-04-01 20:58:27 +03:00
static char const * object_section_header_type_to_string ( ElfW ( Word ) type )
2020-12-29 11:04:29 +03:00
{
switch ( type ) {
case SHT_NULL :
return " NULL " ;
case SHT_PROGBITS :
return " PROGBITS " ;
case SHT_SYMTAB :
return " SYMTAB " ;
case SHT_STRTAB :
return " STRTAB " ;
case SHT_RELA :
return " RELA " ;
case SHT_HASH :
return " HASH " ;
case SHT_DYNAMIC :
return " DYNAMIC " ;
case SHT_NOTE :
return " NOTE " ;
case SHT_NOBITS :
return " NOBITS " ;
case SHT_REL :
return " REL " ;
case SHT_SHLIB :
return " SHLIB " ;
case SHT_DYNSYM :
return " DYNSYM " ;
case SHT_NUM :
return " NUM " ;
case SHT_INIT_ARRAY :
return " INIT_ARRAY " ;
case SHT_FINI_ARRAY :
return " FINI_ARRAY " ;
case SHT_PREINIT_ARRAY :
return " PREINIT_ARRAY " ;
case SHT_GROUP :
return " GROUP " ;
case SHT_SYMTAB_SHNDX :
return " SYMTAB_SHNDX " ;
2022-02-11 00:38:55 +03:00
case SHT_RELR :
return " RELR " ;
2020-12-29 11:04:29 +03:00
case SHT_LOOS :
return " SOOS " ;
case SHT_SUNW_dof :
return " SUNW_dof " ;
case SHT_GNU_LIBLIST :
return " GNU_LIBLIST " ;
case SHT_SUNW_move :
return " SUNW_move " ;
case SHT_SUNW_syminfo :
return " SUNW_syminfo " ;
case SHT_SUNW_verdef :
return " SUNW_verdef " ;
case SHT_SUNW_verneed :
return " SUNW_verneed " ;
case SHT_SUNW_versym : // or SHT_HIOS
return " SUNW_versym " ;
case SHT_LOPROC :
return " LOPROC " ;
case SHT_HIPROC :
return " HIPROC " ;
case SHT_LOUSER :
return " LOUSER " ;
case SHT_HIUSER :
return " HIUSER " ;
case SHT_GNU_HASH :
return " GNU_HASH " ;
default :
return " (?) " ;
}
}
2022-04-01 20:58:27 +03:00
static char const * object_symbol_type_to_string ( ElfW ( Word ) type )
2020-12-29 11:04:29 +03:00
{
switch ( type ) {
case STT_NOTYPE :
return " NOTYPE " ;
case STT_OBJECT :
return " OBJECT " ;
case STT_FUNC :
return " FUNC " ;
case STT_SECTION :
return " SECTION " ;
case STT_FILE :
return " FILE " ;
case STT_TLS :
return " TLS " ;
2022-03-13 11:27:41 +03:00
case STT_GNU_IFUNC :
return " IFUNC " ;
2020-12-29 11:04:29 +03:00
case STT_LOPROC :
return " LOPROC " ;
case STT_HIPROC :
return " HIPROC " ;
default :
return " (?) " ;
}
}
2022-04-01 20:58:27 +03:00
static char const * object_symbol_binding_to_string ( ElfW ( Word ) type )
2020-12-29 11:04:29 +03:00
{
switch ( type ) {
case STB_LOCAL :
return " LOCAL " ;
case STB_GLOBAL :
return " GLOBAL " ;
case STB_WEAK :
return " WEAK " ;
case STB_NUM :
return " NUM " ;
case STB_LOPROC :
return " LOPROC " ;
case STB_HIPROC :
return " HIPROC " ;
default :
return " (?) " ;
}
}
2022-04-01 20:58:27 +03:00
static char const * object_relocation_type_to_string ( ElfW ( Word ) type )
2021-03-14 13:58:44 +03:00
{
switch ( type ) {
2022-10-04 02:51:58 +03:00
# if ARCH(x86_64)
2021-07-16 19:34:02 +03:00
case R_X86_64_NONE :
return " R_X86_64_NONE " ;
case R_X86_64_64 :
return " R_X86_64 " ;
case R_X86_64_GLOB_DAT :
return " R_x86_64_GLOB_DAT " ;
case R_X86_64_JUMP_SLOT :
return " R_X86_64_JUMP_SLOT " ;
case R_X86_64_RELATIVE :
return " R_X86_64_RELATIVE " ;
case R_X86_64_TPOFF64 :
return " R_X86_64_TPOFF64 " ;
# endif
2021-03-14 13:58:44 +03:00
default :
return " (?) " ;
}
}
2022-03-21 10:59:45 +03:00
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
2020-12-29 11:04:29 +03:00
{
2022-03-21 10:59:45 +03:00
TRY ( Core : : System : : pledge ( " stdio rpath " ) ) ;
2020-12-29 11:04:29 +03:00
2022-12-04 21:02:33 +03:00
DeprecatedString path { } ;
2020-12-29 11:04:29 +03:00
static bool display_all = false ;
static bool display_elf_header = false ;
static bool display_program_headers = false ;
static bool display_section_headers = false ;
static bool display_headers = false ;
static bool display_symbol_table = false ;
static bool display_dynamic_symbol_table = false ;
static bool display_core_notes = false ;
static bool display_relocations = false ;
static bool display_unwind_info = false ;
static bool display_dynamic_section = false ;
2021-03-19 08:52:16 +03:00
static bool display_hardening = false ;
2022-01-20 00:50:58 +03:00
StringView string_dump_section { } ;
2020-12-29 11:04:29 +03:00
Core : : ArgsParser args_parser ;
args_parser . add_option ( display_all , " Display all " , " all " , ' a ' ) ;
args_parser . add_option ( display_elf_header , " Display ELF header " , " file-header " , ' h ' ) ;
args_parser . add_option ( display_program_headers , " Display program headers " , " program-headers " , ' l ' ) ;
args_parser . add_option ( display_section_headers , " Display section headers " , " section-headers " , ' S ' ) ;
2021-03-19 08:52:16 +03:00
args_parser . add_option ( display_headers , " Equivalent to: -h -l -S -s -r -d -n -u -c " , " headers " , ' e ' ) ;
2020-12-29 11:04:29 +03:00
args_parser . add_option ( display_symbol_table , " Display the symbol table " , " syms " , ' s ' ) ;
2021-03-22 08:58:28 +03:00
args_parser . add_option ( display_dynamic_symbol_table , " Display the dynamic symbol table " , " dyn-syms " , ' \0 ' ) ;
2021-03-14 13:58:44 +03:00
args_parser . add_option ( display_dynamic_section , " Display the dynamic section " , " dynamic " , ' d ' ) ;
args_parser . add_option ( display_core_notes , " Display core notes " , " notes " , ' n ' ) ;
args_parser . add_option ( display_relocations , " Display relocations " , " relocs " , ' r ' ) ;
args_parser . add_option ( display_unwind_info , " Display unwind info " , " unwind " , ' u ' ) ;
2021-03-19 08:52:16 +03:00
args_parser . add_option ( display_hardening , " Display security hardening info " , " checksec " , ' c ' ) ;
2022-01-20 00:50:58 +03:00
args_parser . add_option ( string_dump_section , " Display the contents of a section as strings " , " string-dump " , ' p ' , " section-name " ) ;
2020-12-29 11:04:29 +03:00
args_parser . add_positional_argument ( path , " ELF path " , " path " ) ;
2022-03-21 10:59:45 +03:00
args_parser . parse ( arguments ) ;
2020-12-29 11:04:29 +03:00
2022-03-21 10:59:45 +03:00
if ( arguments . argc < 3 ) {
args_parser . print_usage ( stderr , arguments . argv [ 0 ] ) ;
return Error : : from_errno ( EINVAL ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_headers ) {
display_elf_header = true ;
display_program_headers = true ;
display_section_headers = true ;
}
if ( display_all ) {
display_elf_header = true ;
display_program_headers = true ;
display_section_headers = true ;
2021-09-10 04:22:46 +03:00
display_dynamic_symbol_table = true ;
display_dynamic_section = true ;
2021-03-14 13:58:44 +03:00
display_core_notes = true ;
display_relocations = true ;
display_unwind_info = true ;
2020-12-29 11:04:29 +03:00
display_symbol_table = true ;
2021-03-19 08:52:16 +03:00
display_hardening = true ;
2020-12-29 11:04:29 +03:00
}
2022-10-28 17:30:27 +03:00
path = LexicalPath : : absolute_path ( TRY ( Core : : System : : getcwd ( ) ) , path ) ;
2021-11-23 13:32:25 +03:00
auto file_or_error = Core : : MappedFile : : map ( path ) ;
2020-12-29 11:04:29 +03:00
2021-01-10 17:55:54 +03:00
if ( file_or_error . is_error ( ) ) {
warnln ( " Unable to map file {}: {} " , path , file_or_error . error ( ) ) ;
2020-12-29 11:04:29 +03:00
return - 1 ;
}
2021-01-10 17:55:54 +03:00
auto elf_image_data = file_or_error . value ( ) - > bytes ( ) ;
2021-03-22 08:58:28 +03:00
ELF : : Image elf_image ( elf_image_data ) ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
if ( ! elf_image . is_valid ( ) ) {
2021-05-31 17:43:25 +03:00
warnln ( " File is not a valid ELF object " ) ;
2020-12-29 11:04:29 +03:00
return - 1 ;
}
2022-01-13 19:50:17 +03:00
StringBuilder interpreter_path_builder ;
2022-01-13 21:54:53 +03:00
auto result_or_error = ELF : : validate_program_headers ( * ( const ElfW ( Ehdr ) * ) elf_image_data . data ( ) , elf_image_data . size ( ) , elf_image_data , & interpreter_path_builder ) ;
2022-01-13 19:50:17 +03:00
if ( result_or_error . is_error ( ) | | ! result_or_error . value ( ) ) {
2021-05-31 17:43:25 +03:00
warnln ( " Invalid ELF headers " ) ;
2020-12-29 11:04:29 +03:00
return - 1 ;
}
2022-01-13 19:50:17 +03:00
auto interpreter_path = interpreter_path_builder . string_view ( ) ;
2020-12-29 11:04:29 +03:00
2021-06-28 18:24:08 +03:00
auto & header = * reinterpret_cast < const ElfW ( Ehdr ) * > ( elf_image_data . data ( ) ) ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
RefPtr < ELF : : DynamicObject > object = nullptr ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
if ( elf_image . is_dynamic ( ) ) {
2022-01-16 22:12:57 +03:00
if ( interpreter_path . is_empty ( ) ) {
2022-01-13 19:50:17 +03:00
interpreter_path = " /usr/lib/Loader.so " sv ;
2021-05-31 17:43:25 +03:00
warnln ( " Warning: Dynamic ELF object has no interpreter path. Using: {} " , interpreter_path ) ;
2021-03-22 08:58:28 +03:00
}
2020-12-29 11:04:29 +03:00
2021-11-23 13:32:25 +03:00
auto interpreter_file_or_error = Core : : MappedFile : : map ( interpreter_path ) ;
2021-03-22 08:58:28 +03:00
if ( interpreter_file_or_error . is_error ( ) ) {
warnln ( " Unable to map interpreter file {}: {} " , interpreter_path , interpreter_file_or_error . error ( ) ) ;
2022-05-01 08:43:20 +03:00
} else {
auto interpreter_image_data = interpreter_file_or_error . value ( ) - > bytes ( ) ;
2021-03-22 08:58:28 +03:00
2022-05-01 08:43:20 +03:00
ELF : : Image interpreter_image ( interpreter_image_data ) ;
2021-03-22 08:58:28 +03:00
2022-05-01 08:43:20 +03:00
if ( ! interpreter_image . is_valid ( ) ) {
warnln ( " ELF interpreter image is invalid " ) ;
}
2021-03-22 08:58:28 +03:00
}
2022-03-21 10:59:45 +03:00
int fd = TRY ( Core : : System : : open ( path , O_RDONLY ) ) ;
2022-10-28 17:48:48 +03:00
auto result = ELF : : DynamicLoader : : try_create ( fd , path ) ;
2021-04-24 21:39:58 +03:00
if ( result . is_error ( ) ) {
outln ( " {} " , result . error ( ) . text ) ;
return 1 ;
}
auto & loader = result . value ( ) ;
if ( ! loader - > is_valid ( ) ) {
outln ( " {} is not a valid ELF dynamic shared object! " , path ) ;
2021-03-22 08:58:28 +03:00
return 1 ;
}
object = loader - > map ( ) ;
if ( ! object ) {
2021-04-24 21:39:58 +03:00
outln ( " Failed to map dynamic ELF object {} " , path ) ;
2021-03-22 08:58:28 +03:00
return 1 ;
}
}
2020-12-29 11:04:29 +03:00
if ( display_elf_header ) {
2021-05-31 17:43:25 +03:00
outln ( " ELF header: " ) ;
2020-12-29 11:04:29 +03:00
2021-05-31 17:43:25 +03:00
out ( " Magic: " ) ;
2021-04-21 23:53:05 +03:00
for ( char i : StringView { header . e_ident , sizeof ( header . e_ident ) } ) {
2021-03-22 08:58:28 +03:00
if ( isprint ( i ) ) {
2021-05-31 17:43:25 +03:00
out ( " {:c} " , i ) ;
2020-12-29 11:04:29 +03:00
} else {
2021-05-31 17:43:25 +03:00
out ( " {:02x} " , i ) ;
2020-12-29 11:04:29 +03:00
}
}
2021-05-31 17:43:25 +03:00
outln ( ) ;
2022-07-11 20:32:29 +03:00
outln ( " Type: {} ({}) " , header . e_type , ELF : : Image : : object_file_type_to_string ( header . e_type ) . value_or ( " (?) " sv ) ) ;
outln ( " Machine: {} ({}) " , header . e_machine , ELF : : Image : : object_machine_type_to_string ( header . e_machine ) . value_or ( " (?) " sv ) ) ;
2021-05-31 17:43:25 +03:00
outln ( " Version: {:#x} " , header . e_version ) ;
outln ( " Entry point address: {:#x} " , header . e_entry ) ;
outln ( " Start of program headers: {} (bytes into file) " , header . e_phoff ) ;
outln ( " Start of section headers: {} (bytes into file) " , header . e_shoff ) ;
outln ( " Flags: {:#x} " , header . e_flags ) ;
outln ( " Size of this header: {} (bytes) " , header . e_ehsize ) ;
outln ( " Size of program headers: {} (bytes) " , header . e_phentsize ) ;
outln ( " Number of program headers: {} " , header . e_phnum ) ;
outln ( " Size of section headers: {} (bytes) " , header . e_shentsize ) ;
outln ( " Number of section headers: {} " , header . e_shnum ) ;
outln ( " Section header string table index: {} " , header . e_shstrndx ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
2021-07-22 01:47:23 +03:00
auto addr_padding = " " ;
2020-12-29 11:04:29 +03:00
if ( display_section_headers ) {
if ( ! display_all ) {
2021-05-31 17:43:25 +03:00
outln ( " There are {} section headers, starting at offset {:#x}: " , header . e_shnum , header . e_shoff ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
2021-03-22 08:58:28 +03:00
if ( ! elf_image . section_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " There are no sections in this file. " ) ;
2020-12-29 11:04:29 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Section Headers: " ) ;
2021-07-22 01:47:23 +03:00
outln ( " Name Type Address{} Offset{} Size{} Flags " , addr_padding , addr_padding , addr_padding ) ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
elf_image . for_each_section ( [ ] ( const ELF : : Image : : Section & section ) {
2021-05-31 17:43:25 +03:00
out ( " {:19} " , section . name ( ) ) ;
out ( " {:15} " , object_section_header_type_to_string ( section . type ( ) ) ) ;
2021-07-21 20:53:38 +03:00
out ( " {:p} " , section . address ( ) ) ;
out ( " {:p} " , section . offset ( ) ) ;
out ( " {:p} " , section . size ( ) ) ;
2021-05-31 17:43:25 +03:00
out ( " {} " , section . flags ( ) ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
} ) ;
}
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_program_headers ) {
if ( ! display_all ) {
2022-07-11 20:32:29 +03:00
outln ( " ELF file type is {} ({}) " , header . e_type , ELF : : Image : : object_file_type_to_string ( header . e_type ) . value_or ( " (?) " sv ) ) ;
2021-05-31 17:43:25 +03:00
outln ( " Entry point {:#x} \n " , header . e_entry ) ;
outln ( " There are {} program headers, starting at offset {} " , header . e_phnum , header . e_phoff ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
2021-03-29 15:14:41 +03:00
if ( ! elf_image . program_header_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " There are no program headers in this file. " ) ;
2021-03-29 15:14:41 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Program Headers: " ) ;
2021-07-22 01:47:30 +03:00
outln ( " Type Offset{} VirtAddr{} PhysAddr{} FileSiz{} MemSiz{} Flg Align " ,
addr_padding , addr_padding , addr_padding , addr_padding , addr_padding ) ;
2021-03-29 15:14:41 +03:00
elf_image . for_each_program_header ( [ ] ( const ELF : : Image : : ProgramHeader & program_header ) {
2021-05-31 17:43:25 +03:00
out ( " " ) ;
out ( " {:14} " , object_program_header_type_to_string ( program_header . type ( ) ) ) ;
2021-07-22 01:47:30 +03:00
out ( " {:p} " , program_header . offset ( ) ) ;
2021-05-31 17:43:25 +03:00
out ( " {:p} " , program_header . vaddr ( ) . as_ptr ( ) ) ;
out ( " {:p} " , program_header . vaddr ( ) . as_ptr ( ) ) ; // FIXME: assumes PhysAddr = VirtAddr
2021-07-22 01:47:30 +03:00
out ( " {:p} " , program_header . size_in_image ( ) ) ;
out ( " {:p} " , program_header . size_in_memory ( ) ) ;
2021-05-31 17:43:25 +03:00
out ( " {:04x} " , program_header . flags ( ) ) ;
2021-07-22 01:47:30 +03:00
out ( " {:p} " , program_header . alignment ( ) ) ;
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
2021-03-29 15:14:41 +03:00
if ( program_header . type ( ) = = PT_INTERP )
2021-05-31 17:43:25 +03:00
outln ( " [Interpreter: {}] " , program_header . raw_data ( ) ) ;
2021-03-29 15:14:41 +03:00
} ) ;
}
2021-03-14 13:58:44 +03:00
// TODO: Display section to segment mapping
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_dynamic_section ) {
2021-03-14 13:58:44 +03:00
auto found_dynamic_section = false ;
2021-03-22 08:58:28 +03:00
if ( elf_image . is_dynamic ( ) ) {
elf_image . for_each_section ( [ & found_dynamic_section ] ( const ELF : : Image : : Section & section ) {
if ( section . name ( ) ! = ELF_DYNAMIC )
return IterationDecision : : Continue ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
found_dynamic_section = true ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
if ( section . entry_count ( ) ) {
2022-12-06 04:12:49 +03:00
outln ( " Dynamic section '{}' at offset {:#08x} contains {} entries. " , section . name ( ) . to_deprecated_string ( ) , section . offset ( ) , section . entry_count ( ) ) ;
2021-03-22 08:58:28 +03:00
} else {
2022-12-06 04:12:49 +03:00
outln ( " Dynamic section '{}' at offset {:#08x} contains zero entries. " , section . name ( ) . to_deprecated_string ( ) , section . offset ( ) ) ;
2021-03-22 08:58:28 +03:00
}
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
return IterationDecision : : Break ;
} ) ;
2021-03-14 13:58:44 +03:00
2022-12-04 21:02:33 +03:00
Vector < DeprecatedString > libraries ;
2021-03-22 08:58:28 +03:00
object - > for_each_needed_library ( [ & libraries ] ( StringView entry ) {
2022-12-04 21:02:33 +03:00
libraries . append ( DeprecatedString : : formatted ( " {} " , entry ) ) ;
2021-03-22 08:58:28 +03:00
} ) ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
auto library_index = 0 ;
2021-05-31 17:43:25 +03:00
outln ( " Tag Type Name / Value " ) ;
2021-03-22 08:58:28 +03:00
object - > for_each_dynamic_entry ( [ & library_index , & libraries , & object ] ( const ELF : : DynamicObject : : DynamicEntry & entry ) {
2021-05-31 17:43:25 +03:00
out ( " {:#08x} " , entry . tag ( ) ) ;
2021-09-25 17:40:51 +03:00
out ( " {:17} " , ELF : : DynamicObject : : name_for_dtag ( entry . tag ( ) ) ) ;
2021-03-22 08:58:28 +03:00
if ( entry . tag ( ) = = DT_NEEDED ) {
2021-05-31 17:43:25 +03:00
outln ( " Shared library: {} " , libraries [ library_index ] ) ;
2021-03-22 08:58:28 +03:00
library_index + + ;
} else if ( entry . tag ( ) = = DT_RPATH ) {
2021-05-31 17:43:25 +03:00
outln ( " Library rpath: {} " , object - > rpath ( ) ) ;
2021-03-22 08:58:28 +03:00
} else if ( entry . tag ( ) = = DT_RUNPATH ) {
2021-05-31 17:43:25 +03:00
outln ( " Library runpath: {} " , object - > runpath ( ) ) ;
2021-03-22 08:58:28 +03:00
} else if ( entry . tag ( ) = = DT_SONAME ) {
2021-05-31 17:43:25 +03:00
outln ( " Library soname: {} " , object - > soname ( ) ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " {:#08x} " , entry . val ( ) ) ;
2021-03-22 08:58:28 +03:00
}
} ) ;
}
2021-03-14 13:58:44 +03:00
if ( ! found_dynamic_section )
2021-05-31 17:43:25 +03:00
outln ( " No dynamic section in this file. " ) ;
2021-03-14 13:58:44 +03:00
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_relocations ) {
2021-03-22 08:58:28 +03:00
if ( elf_image . is_dynamic ( ) ) {
if ( ! object - > relocation_section ( ) . entry_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " Relocation section '{}' at offset {:#08x} contains zero entries: " , object - > relocation_section ( ) . name ( ) , object - > relocation_section ( ) . offset ( ) ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Relocation section '{}' at offset {:#08x} contains {} entries: " , object - > relocation_section ( ) . name ( ) , object - > relocation_section ( ) . offset ( ) , object - > relocation_section ( ) . entry_count ( ) ) ;
2021-07-22 02:15:10 +03:00
outln ( " Offset{} Type Sym Value{} Sym Name " , addr_padding , addr_padding ) ;
2021-03-22 08:58:28 +03:00
object - > relocation_section ( ) . for_each_relocation ( [ ] ( const ELF : : DynamicObject : : Relocation & reloc ) {
2021-07-22 01:47:30 +03:00
out ( " {:p} " , reloc . offset ( ) ) ;
2021-07-22 02:15:10 +03:00
out ( " {:18} " , object_relocation_type_to_string ( reloc . type ( ) ) ) ;
2021-07-22 01:47:30 +03:00
out ( " {:p} " , reloc . symbol ( ) . value ( ) ) ;
2021-05-31 17:43:25 +03:00
out ( " {} " , reloc . symbol ( ) . name ( ) ) ;
outln ( ) ;
2021-03-22 08:58:28 +03:00
} ) ;
2021-03-14 13:58:44 +03:00
}
2021-05-31 17:43:25 +03:00
outln ( ) ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
if ( ! object - > plt_relocation_section ( ) . entry_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " Relocation section '{}' at offset {:#08x} contains zero entries: " , object - > plt_relocation_section ( ) . name ( ) , object - > plt_relocation_section ( ) . offset ( ) ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Relocation section '{}' at offset {:#08x} contains {} entries: " , object - > plt_relocation_section ( ) . name ( ) , object - > plt_relocation_section ( ) . offset ( ) , object - > plt_relocation_section ( ) . entry_count ( ) ) ;
2021-07-22 02:15:10 +03:00
outln ( " Offset{} Type Sym Value{} Sym Name " , addr_padding , addr_padding ) ;
2021-03-22 08:58:28 +03:00
object - > plt_relocation_section ( ) . for_each_relocation ( [ ] ( const ELF : : DynamicObject : : Relocation & reloc ) {
2021-07-22 01:47:30 +03:00
out ( " {:p} " , reloc . offset ( ) ) ;
2021-07-22 02:15:10 +03:00
out ( " {:18} " , object_relocation_type_to_string ( reloc . type ( ) ) ) ;
2021-07-22 01:47:30 +03:00
out ( " {:p} " , reloc . symbol ( ) . value ( ) ) ;
2021-05-31 17:43:25 +03:00
out ( " {} " , reloc . symbol ( ) . name ( ) ) ;
outln ( ) ;
2021-03-22 08:58:28 +03:00
} ) ;
}
2022-02-11 00:38:55 +03:00
outln ( ) ;
size_t relr_count = 0 ;
object - > for_each_relr_relocation ( [ & relr_count ] ( auto ) { + + relr_count ; } ) ;
if ( relr_count ! = 0 ) {
outln ( " Relocation section '.relr.dyn' at offset {:#08x} contains {} entries: " , object - > relr_relocation_section ( ) . offset ( ) , object - > relr_relocation_section ( ) . entry_count ( ) ) ;
outln ( " {:>8x} offsets " , relr_count ) ;
object - > for_each_relr_relocation ( [ ] ( auto offset ) { outln ( " {:p} " , offset ) ; } ) ;
}
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " No relocations in this file. " ) ;
2021-03-22 08:58:28 +03:00
}
2021-03-14 13:58:44 +03:00
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_unwind_info ) {
// TODO: Unwind info
2022-07-11 20:32:29 +03:00
outln ( " Decoding of unwind sections for machine type {} is not supported. " , ELF : : Image : : object_machine_type_to_string ( header . e_machine ) . value_or ( " ? " sv ) ) ;
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_core_notes ) {
2021-03-14 13:58:44 +03:00
auto found_notes = false ;
2021-03-22 08:58:28 +03:00
elf_image . for_each_program_header ( [ & found_notes ] ( const ELF : : Image : : ProgramHeader & program_header ) {
2021-03-14 13:58:44 +03:00
if ( program_header . type ( ) ! = PT_NOTE )
2021-05-16 12:36:52 +03:00
return ;
2021-03-14 13:58:44 +03:00
found_notes = true ;
2021-05-31 17:43:25 +03:00
outln ( " Displaying notes section '{}' at offset {:#08x} of length {:#08x}: " , object_program_header_type_to_string ( program_header . type ( ) ) , program_header . offset ( ) , program_header . size_in_image ( ) ) ;
2021-03-14 13:58:44 +03:00
// FIXME: Parse CORE notes. Notes are in JSON format on SerenityOS, but vary between systems.
2021-05-31 17:43:25 +03:00
outln ( " {} " , program_header . raw_data ( ) ) ;
2021-03-14 13:58:44 +03:00
} ) ;
if ( ! found_notes )
2021-05-31 17:43:25 +03:00
outln ( " No core notes in this file. " ) ;
2021-03-14 13:58:44 +03:00
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_dynamic_symbol_table | | display_symbol_table ) {
2021-03-14 13:58:44 +03:00
auto found_dynamic_symbol_table = false ;
2021-03-22 08:58:28 +03:00
if ( elf_image . is_dynamic ( ) ) {
elf_image . for_each_section ( [ & found_dynamic_symbol_table ] ( const ELF : : Image : : Section & section ) {
if ( section . name ( ) ! = ELF_DYNSYM )
return IterationDecision : : Continue ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
found_dynamic_symbol_table = true ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
if ( ! section . entry_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " Symbol table '{}' contains zero entries. " , ELF_DYNSYM ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Symbol table '{}' contains {} entries. " , ELF_DYNSYM , section . entry_count ( ) ) ;
2021-03-22 08:58:28 +03:00
}
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
return IterationDecision : : Break ;
} ) ;
2021-03-14 13:58:44 +03:00
2021-03-22 08:58:28 +03:00
if ( object - > symbol_count ( ) ) {
// FIXME: Add support for init/fini/start/main sections
2021-07-22 01:47:23 +03:00
outln ( " Num: Value{} Size{} Type Bind Name " , addr_padding , addr_padding ) ;
2021-03-22 08:58:28 +03:00
object - > for_each_symbol ( [ ] ( const ELF : : DynamicObject : : Symbol & sym ) {
2021-05-31 17:43:25 +03:00
out ( " {:>4}: " , sym . index ( ) ) ;
2021-07-21 20:53:38 +03:00
out ( " {:p} " , sym . value ( ) ) ;
out ( " {:p} " , sym . size ( ) ) ;
2021-05-31 17:43:25 +03:00
out ( " {:8} " , object_symbol_type_to_string ( sym . type ( ) ) ) ;
out ( " {:8} " , object_symbol_binding_to_string ( sym . bind ( ) ) ) ;
out ( " {} " , sym . name ( ) ) ;
outln ( ) ;
2021-03-22 08:58:28 +03:00
} ) ;
}
}
2021-03-14 13:58:44 +03:00
if ( ! found_dynamic_symbol_table )
2021-05-31 17:43:25 +03:00
outln ( " No dynamic symbol information for this file. " ) ;
2021-03-14 13:58:44 +03:00
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
if ( display_symbol_table ) {
2021-03-22 08:58:28 +03:00
if ( elf_image . symbol_count ( ) ) {
2021-05-31 17:43:25 +03:00
outln ( " Symbol table '{}' contains {} entries: " , ELF_SYMTAB , elf_image . symbol_count ( ) ) ;
2021-07-22 01:47:23 +03:00
outln ( " Num: Value{} Size{} Type Bind Name " , addr_padding , addr_padding ) ;
2020-12-29 11:04:29 +03:00
2021-03-22 08:58:28 +03:00
elf_image . for_each_symbol ( [ ] ( const ELF : : Image : : Symbol & sym ) {
2021-05-31 17:43:25 +03:00
out ( " {:>4}: " , sym . index ( ) ) ;
2021-07-21 20:53:38 +03:00
out ( " {:p} " , sym . value ( ) ) ;
out ( " {:p} " , sym . size ( ) ) ;
2021-05-31 17:43:25 +03:00
out ( " {:8} " , object_symbol_type_to_string ( sym . type ( ) ) ) ;
out ( " {:8} " , object_symbol_binding_to_string ( sym . bind ( ) ) ) ;
out ( " {} " , sym . name ( ) ) ;
outln ( ) ;
2020-12-29 11:04:29 +03:00
} ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
outln ( " Symbol table '{}' contains zero entries. " , ELF_SYMTAB ) ;
2020-12-29 11:04:29 +03:00
}
2021-05-31 17:43:25 +03:00
outln ( ) ;
2020-12-29 11:04:29 +03:00
}
2021-03-19 08:52:16 +03:00
if ( display_hardening ) {
2021-05-31 17:43:25 +03:00
outln ( " Security Hardening: " ) ;
outln ( " RELRO Stack Canary NX PIE RPATH RUNPATH Symbols " ) ;
2021-03-19 08:52:16 +03:00
bool relro = false ;
2021-03-22 08:58:28 +03:00
elf_image . for_each_program_header ( [ & relro ] ( const ELF : : Image : : ProgramHeader & program_header ) {
2021-03-19 08:52:16 +03:00
if ( program_header . type ( ) = = PT_GNU_RELRO ) {
relro = true ;
return IterationDecision : : Break ;
}
return IterationDecision : : Continue ;
} ) ;
2021-03-22 08:58:28 +03:00
bool full_relro = false ;
if ( relro ) {
object - > for_each_dynamic_entry ( [ & full_relro ] ( const ELF : : DynamicObject : : DynamicEntry & entry ) {
if ( entry . tag ( ) = = DT_BIND_NOW ) {
full_relro = true ;
return IterationDecision : : Break ;
}
return IterationDecision : : Continue ;
} ) ;
if ( full_relro )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:13} \033 [0m " , " Full RELRO " ) ;
2021-03-22 08:58:28 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;33m{:13} \033 [0m " , " Partial RELRO " ) ;
2021-03-22 08:58:28 +03:00
} else {
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:13} \033 [0m " , " No RELRO " ) ;
2021-03-22 08:58:28 +03:00
}
2021-03-19 08:52:16 +03:00
bool canary = false ;
2021-03-22 08:58:28 +03:00
elf_image . for_each_symbol ( [ & canary ] ( const ELF : : Image : : Symbol & sym ) {
2021-03-19 08:52:16 +03:00
if ( sym . name ( ) = = " __stack_chk_fail " | | sym . name ( ) = = " __intel_security_cookie " ) {
canary = true ;
return IterationDecision : : Break ;
}
return IterationDecision : : Continue ;
} ) ;
if ( canary )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " Canary found " ) ;
2021-03-19 08:52:16 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , " No canary " ) ;
2021-03-19 08:52:16 +03:00
bool nx = false ;
2021-03-22 08:58:28 +03:00
elf_image . for_each_program_header ( [ & nx ] ( const ELF : : Image : : ProgramHeader & program_header ) {
2021-03-19 08:52:16 +03:00
if ( program_header . type ( ) = = PT_GNU_STACK ) {
if ( program_header . flags ( ) & PF_X )
nx = false ;
else
nx = true ;
return IterationDecision : : Break ;
}
return IterationDecision : : Continue ;
} ) ;
if ( nx )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " NX enabled " ) ;
2021-03-19 08:52:16 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , " NX disabled " ) ;
2021-03-19 08:52:16 +03:00
bool pie = false ;
if ( header . e_type = = ET_REL | | header . e_type = = ET_DYN )
pie = true ;
if ( pie )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " PIE enabled " ) ;
2021-03-22 08:58:28 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , " No PIE " ) ;
2021-03-22 08:58:28 +03:00
StringView rpath ;
if ( elf_image . is_dynamic ( ) )
rpath = object - > rpath ( ) ;
if ( rpath . is_empty ( ) )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " No RPATH " ) ;
2021-03-22 08:58:28 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , rpath ) ;
2021-03-22 08:58:28 +03:00
StringView runpath ;
if ( elf_image . is_dynamic ( ) )
runpath = object - > runpath ( ) ;
if ( runpath . is_empty ( ) )
2021-05-31 17:43:25 +03:00
out ( " \033 [0;32m{:12} \033 [0m " , " No RUNPATH " ) ;
2021-03-19 08:52:16 +03:00
else
2021-05-31 17:43:25 +03:00
out ( " \033 [0;31m{:12} \033 [0m " , runpath ) ;
2021-03-19 08:52:16 +03:00
2021-05-31 17:43:25 +03:00
out ( " {} symbols " , elf_image . symbol_count ( ) ) ;
outln ( ) ;
2021-03-19 08:52:16 +03:00
}
2022-01-20 00:50:58 +03:00
if ( ! string_dump_section . is_null ( ) ) {
auto maybe_section = elf_image . lookup_section ( string_dump_section ) ;
if ( maybe_section . has_value ( ) ) {
outln ( " String dump of section \' {} \' : " , string_dump_section ) ;
StringView data ( maybe_section - > raw_data ( ) , maybe_section - > size ( ) ) ;
2022-10-22 16:38:21 +03:00
data . for_each_split_view ( ' \0 ' , SplitBehavior : : Nothing , [ & data ] ( auto string ) {
2022-01-20 00:50:58 +03:00
auto offset = string . characters_without_null_termination ( ) - data . characters_without_null_termination ( ) ;
outln ( " [{:6x}] {} " , offset , string ) ;
} ) ;
} else {
warnln ( " Could not find section \' {} \' " , string_dump_section ) ;
return 1 ;
}
}
2020-12-29 11:04:29 +03:00
return 0 ;
}