#include #include #include #include #include #include #include #include "elf.hpp" enum { GETOPT_FIRST = 256, GETOPT_HELP, GETOPT_VERSION, }; static struct option const long_opts[] = { {"print-elf-header", no_argument, 0, 'e'}, {"print-interp", no_argument, 0, 'i'}, {"print-needed", no_argument, 0, 'n'}, {"print-rpath", no_argument, 0, 'R'}, {"print-soname", no_argument, 0, 's'}, {"print-symbols-provided", no_argument, 0, 'p'}, {"print-symbols-undefined", no_argument, 0, 'u'}, {"help", no_argument, 0, GETOPT_HELP}, {"version", no_argument, 0, GETOPT_VERSION}, {0, 0, 0, 0} }; char *program_name; enum command { COMMAND_PRINT_ELF_HEADER, COMMAND_PRINT_INTERP, COMMAND_PRINT_NEEDED, COMMAND_PRINT_RPATH, COMMAND_PRINT_SONAME, COMMAND_PRINT_SYMBOLS_PROVIDED, COMMAND_PRINT_SYMBOLS_UNDEFINED, }; static void process_elf_header (Elf::file *file) { std::cout << (unsigned int) file->get_class () << ' ' << (unsigned int) file->get_data () << ' ' << file->get_machine () << ' ' << file->get_flags () << '\n'; } static void process_dynamics (Elf::file *file, int64_t tag) { const Elf::section_type *section = file->get_section_DYNAMIC (); if (!section) return; for (std::vector::const_iterator it = section->get_dynamics ().begin (); it != section->get_dynamics ().end (); ++it) { Elf::dynamic *dynamic = *it; if (dynamic->get_tag () == tag) std::cout << dynamic->get_val_string () << '\n'; } } static void process_symbols_provided (const Elf::section_type *section) { if (!section) return; for (std::vector::const_iterator it = section->get_symbols ().begin (); it != section->get_symbols ().end (); ++it) { const Elf::symbol *symbol = *it; uint8_t bind = symbol->get_bind (); uint16_t shndx = symbol->get_shndx (); uint8_t type = symbol->get_type (); const std::string &name = symbol->get_name_string (); if (bind != STB_GLOBAL && bind != STB_WEAK) continue; if (shndx == SHN_UNDEF || shndx == SHN_ABS) continue; if (type != STT_NOTYPE && type != STT_OBJECT && type != STT_FUNC && type != STT_COMMON && type != STT_TLS) continue; if (!name.size()) continue; std::cout << name << ' ' << (bind == STB_WEAK ? "True" : "False") << ' ' << symbol->get_version() << ' ' << (symbol->get_version_data() & 0x8000 ? "False" : "True") << '\n'; } } static void process_symbols_undefined (const Elf::section_type *section) { if (!section) return; for (std::vector::const_iterator it = section->get_symbols ().begin (); it != section->get_symbols ().end (); ++it) { const Elf::symbol *symbol = *it; uint8_t bind = symbol->get_bind (); uint16_t shndx = symbol->get_shndx (); uint8_t type = symbol->get_type (); const std::string &name = symbol->get_name_string (); if (bind != STB_GLOBAL && bind != STB_WEAK) continue; if (shndx != SHN_UNDEF) continue; if (type != STT_NOTYPE && type != STT_OBJECT && type != STT_FUNC && type != STT_COMMON && type != STT_TLS) continue; if (!name.size()) continue; std::cout << name << ' ' << (bind == STB_WEAK ? "True" : "False") << ' ' << symbol->get_version() << ' ' << symbol->get_version_file() << '\n'; } } static void process (command cmd, const char *filename) { Elf::file *file = Elf::file::open (filename); switch (cmd) { case COMMAND_PRINT_ELF_HEADER: process_elf_header (file); break; case COMMAND_PRINT_INTERP: if (file->get_segment_INTERP ()) std::cout << file->get_segment_INTERP ()->get_interp () << '\n'; break; case COMMAND_PRINT_NEEDED: process_dynamics (file, DT_NEEDED); break; case COMMAND_PRINT_RPATH: process_dynamics (file, DT_RPATH); process_dynamics (file, DT_RUNPATH); break; case COMMAND_PRINT_SONAME: process_dynamics (file, DT_SONAME); break; case COMMAND_PRINT_SYMBOLS_PROVIDED: process_symbols_provided (file->get_section_DYNSYM ()); break; case COMMAND_PRINT_SYMBOLS_UNDEFINED: process_symbols_undefined (file->get_section_DYNSYM ()); break; } } static void usage (int status) __attribute__ ((noreturn)); static void usage (int status) { if (status != 0) fprintf (stderr, "Try `%s --help' for more information.\n", program_name); else { fprintf (stdout, "\ Usage: %s [OPTION]... FILE...\n\ Prints informations about ELF shared objects and executables.\n\ \n\ ", program_name); fputs ("\ Mandatory arguments to long options are mandatory for short options too.\n\ ", stdout); fputs ("\ -i, --print-interp Print interpreter of executable\n\ -n, --print-needed Print needed shared libs\n\ -R, --print-rpath Print rpath setting\n\ -s, --print-soname Print soname of shared object\n\ -p, --print-symbols-provided Print provided symbols\n\ -u, --print-symbols-undefined Print undefined symbols\n\ --help Display this help and exit\n\ --version Output version information and exit\n\ ", stdout); } exit (status); } int main (int argc, char *argv[]) { int c; command cmd = COMMAND_PRINT_SYMBOLS_PROVIDED; program_name = argv[0]; while ((c = getopt_long (argc, argv, "einpRsu", long_opts, NULL)) != -1) { switch (c) { case 0: break; case 'e': cmd = COMMAND_PRINT_ELF_HEADER; break; case 'i': cmd = COMMAND_PRINT_INTERP; break; case 'n': cmd = COMMAND_PRINT_NEEDED; break; case 'p': cmd = COMMAND_PRINT_SYMBOLS_PROVIDED; break; case 'R': cmd = COMMAND_PRINT_RPATH; break; case 's': cmd = COMMAND_PRINT_SONAME; break; case 'u': cmd = COMMAND_PRINT_SYMBOLS_UNDEFINED; break; case GETOPT_HELP: usage (EXIT_SUCCESS); case GETOPT_VERSION: fputs (PACKAGE_STRING, stdout); fputs ("\n\n\ This is free software; see the source for copying conditions. There is NO\n\ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ ", stdout); exit (EXIT_SUCCESS); break; default: usage (EXIT_FAILURE); } } for (int i = optind; i < argc; ++i) process (cmd, argv[i]); }