// Copyright 2016, VIXL authors // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of ARM Limited nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // The example assumes support for ELF binaries. #ifdef __linux__ extern "C" { #include #include #include #include #include #include #include } #include #include #include #include #include "globals-vixl.h" #include "aarch32/instructions-aarch32.h" #include "aarch32/disasm-aarch32.h" class Symbol { Elf32_Addr addr_; int32_t offset_; uint32_t size_; int section_; std::string name_; public: Symbol(const char* name, Elf32_Addr addr, int32_t offset, uint32_t size, int section) : addr_(addr), offset_(offset), size_(size), section_(section), name_(name) {} Symbol(const Symbol& ref) : addr_(ref.addr_), offset_(ref.offset_), size_(ref.size_), section_(ref.section_), name_(ref.name_) {} Elf32_Addr GetAddress() const { return addr_; } Elf32_Addr GetMemoryAddress() const { return (addr_ & ~1) + offset_; } uint32_t GetSize() const { return size_; } const std::string& GetName() const { return name_; } int GetSection() const { return section_; } }; class SymbolTable : public std::map { public: void insert(const Symbol& sym) { VIXL_ASSERT(find(sym.GetAddress()) == end()); std::map::insert( std::make_pair(sym.GetMemoryAddress(), sym)); } }; class SectionLocator { const Elf32_Shdr* shdr_; int nsections_; const char* shstrtab_; public: explicit SectionLocator(const Elf32_Ehdr* ehdr) { shdr_ = reinterpret_cast( reinterpret_cast(ehdr) + ehdr->e_shoff); // shstrtab holds the section names as an offset in the file. shstrtab_ = reinterpret_cast(ehdr) + shdr_[ehdr->e_shstrndx].sh_offset; nsections_ = ehdr->e_shnum; } const Elf32_Shdr* Locate(Elf32_Word type, const std::string& section_name) const { for (int shnum = 1; shnum < nsections_; shnum++) { if ((shdr_[shnum].sh_type == type) && std::string(shstrtab_ + shdr_[shnum].sh_name) == section_name) { return &shdr_[shnum]; } } return NULL; } }; template void LocateSymbols(const Elf32_Ehdr* ehdr, const Elf32_Shdr* symtab, const Elf32_Shdr* strtab, VISITOR* visitor) { if ((symtab != NULL) && (strtab != NULL)) { const Elf32_Shdr* shdr = reinterpret_cast( reinterpret_cast(ehdr) + ehdr->e_shoff); const char* symnames = reinterpret_cast(ehdr) + strtab->sh_offset; VIXL_CHECK(symnames != NULL); int nsym = symtab->sh_size / symtab->sh_entsize; const Elf32_Sym* sym = reinterpret_cast( reinterpret_cast(ehdr) + symtab->sh_offset); for (int snum = 0; snum < nsym; snum++) { if ((sym[snum].st_shndx > 0) && (sym[snum].st_shndx < ehdr->e_shnum) && (sym[snum].st_value != 0) && (shdr[sym[snum].st_shndx].sh_type == SHT_PROGBITS) && ((ELF32_ST_BIND(sym[snum].st_info) == STB_LOCAL) || (ELF32_ST_BIND(sym[snum].st_info) == STB_GLOBAL)) && (ELF32_ST_TYPE(sym[snum].st_info) == STT_FUNC)) { visitor->visit(symnames + sym[snum].st_name, sym[snum]); } } } } class DynamicSymbolVisitor { SymbolTable* symbols_; public: explicit DynamicSymbolVisitor(SymbolTable* symbols) : symbols_(symbols) {} void visit(const char* symname, const Elf32_Sym& sym) { symbols_->insert( Symbol(symname, sym.st_value, 0, sym.st_size, sym.st_shndx)); } }; class StaticSymbolVisitor { const Elf32_Ehdr* ehdr_; const Elf32_Shdr* shdr_; SymbolTable* symbols_; public: StaticSymbolVisitor(const Elf32_Ehdr* ehdr, SymbolTable* symbols) : ehdr_(ehdr), shdr_(reinterpret_cast( reinterpret_cast(ehdr) + ehdr->e_shoff)), symbols_(symbols) {} void visit(const char* symname, const Elf32_Sym& sym) { if (ehdr_->e_type == ET_REL) { symbols_->insert(Symbol(symname, sym.st_value, shdr_[sym.st_shndx].sh_offset, sym.st_size, sym.st_shndx)); } else { symbols_->insert( Symbol(symname, sym.st_value, shdr_[sym.st_shndx].sh_offset - shdr_[sym.st_shndx].sh_addr, sym.st_size, sym.st_shndx)); } } }; void usage() { std::cout << "usage: disasm-a32 \n" "where is an ELF ARM binaryfile, either an executable, " "a shared object, or an object file." << std::endl; } int main(int argc, char** argv) { const int kErrorNotARMELF32 = -1; const int kErrorArguments = -2; if (argc < 2) { usage(); return kErrorArguments; } const char* filename = argv[1]; struct stat sb; if (lstat(filename, &sb) == -1) { std::cerr << "Cannot stat this file" << filename << std::endl; return errno; } if (S_ISLNK(sb.st_mode)) { static char linkname[4096]; filename = realpath(argv[1], linkname); if (lstat(linkname, &sb) == -1) { std::cerr << "Cannot stat this file: " << linkname << std::endl; return errno; } } int elf_in; if ((elf_in = open(filename, O_RDONLY)) < 0) { std::cerr << "Cannot open: " << argv[1]; if (filename != argv[1]) std::cerr << " aka " << filename; std::cerr << std::endl; return errno; } char* base_addr; VIXL_CHECK((base_addr = reinterpret_cast( mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, elf_in, 0))) != 0); const Elf32_Ehdr* ehdr = reinterpret_cast(base_addr); if ((ehdr->e_ident[0] != 0x7f) || (ehdr->e_ident[1] != 'E') || (ehdr->e_ident[2] != 'L') || (ehdr->e_ident[3] != 'F') || (ehdr->e_ehsize != sizeof(Elf32_Ehdr))) { std::cerr << "This file is not an 32-bit ELF file." << std::endl; munmap(base_addr, sb.st_size); return kErrorNotARMELF32; } if (ehdr->e_machine != EM_ARM) { std::cerr << "This file is not using the ARM isa." << std::endl; munmap(base_addr, sb.st_size); return kErrorNotARMELF32; } // shstrtab holds the section names as an offset in the file. const Elf32_Shdr* shdr = reinterpret_cast(base_addr + ehdr->e_shoff); SectionLocator section_locator(ehdr); SymbolTable symbol_names; // Traverse the dynamic symbols defined in any text section DynamicSymbolVisitor dynamic_visitor(&symbol_names); LocateSymbols(ehdr, section_locator.Locate(SHT_DYNSYM, ".dynsym"), section_locator.Locate(SHT_STRTAB, ".dynstr"), &dynamic_visitor); // Traverse the static symbols defined in the any test section StaticSymbolVisitor static_visitor(ehdr, &symbol_names); LocateSymbols(ehdr, section_locator.Locate(SHT_SYMTAB, ".symtab"), section_locator.Locate(SHT_STRTAB, ".strtab"), &static_visitor); vixl::aarch32::PrintDisassembler dis(std::cout, 0); for (SymbolTable::iterator sres = symbol_names.begin(); sres != symbol_names.end(); sres++) { const Symbol& symbol = sres->second; uint32_t func_addr = symbol.GetAddress(); uint32_t func_size = symbol.GetSize(); if (func_size == 0) { SymbolTable::iterator next_func = sres; next_func++; if (next_func == symbol_names.end()) { const Elf32_Shdr& shndx = shdr[sres->second.GetSection()]; func_size = (shndx.sh_offset + shndx.sh_size) - sres->first; } else { func_size = next_func->first - sres->first; } } std::cout << "--- " << symbol.GetName() << ":" << std::endl; if ((func_addr & 1) == 1) { func_addr &= ~1; dis.SetCodeAddress(func_addr); dis.DisassembleT32Buffer(reinterpret_cast( base_addr + symbol.GetMemoryAddress()), func_size); } else { dis.SetCodeAddress(func_addr); dis.DisassembleA32Buffer(reinterpret_cast( base_addr + symbol.GetMemoryAddress()), func_size); } } munmap(base_addr, sb.st_size); return 0; } #else #include "globals-vixl.h" // TODO: Implement this example for macOS. int main(void) { VIXL_WARNING("This example has not been implemented for macOS."); return 0; } #endif // __linux__