Home | History | Annotate | Download | only in aarch32
      1 // Copyright 2016, VIXL authors
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are met:
      6 //
      7 //   * Redistributions of source code must retain the above copyright notice,
      8 //     this list of conditions and the following disclaimer.
      9 //   * Redistributions in binary form must reproduce the above copyright notice,
     10 //     this list of conditions and the following disclaimer in the documentation
     11 //     and/or other materials provided with the distribution.
     12 //   * Neither the name of ARM Limited nor the names of its contributors may be
     13 //     used to endorse or promote products derived from this software without
     14 //     specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
     17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
     20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 
     27 
     28 // The example assumes support for ELF binaries.
     29 #ifdef __linux__
     30 
     31 extern "C" {
     32 #include <elf.h>
     33 #include <fcntl.h>
     34 #include <stdint.h>
     35 #include <sys/mman.h>
     36 #include <sys/stat.h>
     37 #include <sys/types.h>
     38 #include <unistd.h>
     39 }
     40 
     41 #include <cerrno>
     42 #include <iostream>
     43 #include <map>
     44 #include <string>
     45 
     46 #include "globals-vixl.h"
     47 #include "aarch32/disasm-aarch32.h"
     48 #include "aarch32/instructions-aarch32.h"
     49 
     50 class Symbol {
     51   Elf32_Addr addr_;
     52   int32_t offset_;
     53   uint32_t size_;
     54   int section_;
     55   std::string name_;
     56 
     57  public:
     58   Symbol(const char* name,
     59          Elf32_Addr addr,
     60          int32_t offset,
     61          uint32_t size,
     62          int section)
     63       : addr_(addr),
     64         offset_(offset),
     65         size_(size),
     66         section_(section),
     67         name_(name) {}
     68   Symbol(const Symbol& ref)
     69       : addr_(ref.addr_),
     70         offset_(ref.offset_),
     71         size_(ref.size_),
     72         section_(ref.section_),
     73         name_(ref.name_) {}
     74 
     75   Elf32_Addr GetAddress() const { return addr_; }
     76   Elf32_Addr GetMemoryAddress() const { return (addr_ & ~1) + offset_; }
     77   uint32_t GetSize() const { return size_; }
     78   const std::string& GetName() const { return name_; }
     79   int GetSection() const { return section_; }
     80 };
     81 
     82 
     83 class SymbolTable : public std::map<Elf32_Addr, Symbol> {
     84  public:
     85   void insert(const Symbol& sym) {
     86     VIXL_ASSERT(find(sym.GetAddress()) == end());
     87     std::map<Elf32_Addr, Symbol>::insert(
     88         std::make_pair(sym.GetMemoryAddress(), sym));
     89   }
     90 };
     91 
     92 
     93 class SectionLocator {
     94   const Elf32_Shdr* shdr_;
     95   int nsections_;
     96   const char* shstrtab_;
     97 
     98  public:
     99   explicit SectionLocator(const Elf32_Ehdr* ehdr) {
    100     shdr_ = reinterpret_cast<const Elf32_Shdr*>(
    101         reinterpret_cast<const char*>(ehdr) + ehdr->e_shoff);
    102     // shstrtab holds the section names as an offset in the file.
    103     shstrtab_ =
    104         reinterpret_cast<const char*>(ehdr) + shdr_[ehdr->e_shstrndx].sh_offset;
    105     nsections_ = ehdr->e_shnum;
    106   }
    107 
    108   const Elf32_Shdr* Locate(Elf32_Word type,
    109                            const std::string& section_name) const {
    110     for (int shnum = 1; shnum < nsections_; shnum++) {
    111       if ((shdr_[shnum].sh_type == type) &&
    112           std::string(shstrtab_ + shdr_[shnum].sh_name) == section_name) {
    113         return &shdr_[shnum];
    114       }
    115     }
    116     return NULL;
    117   }
    118 };
    119 
    120 
    121 template <typename VISITOR>
    122 void LocateSymbols(const Elf32_Ehdr* ehdr,
    123                    const Elf32_Shdr* symtab,
    124                    const Elf32_Shdr* strtab,
    125                    VISITOR* visitor) {
    126   if ((symtab != NULL) && (strtab != NULL)) {
    127     const Elf32_Shdr* shdr = reinterpret_cast<const Elf32_Shdr*>(
    128         reinterpret_cast<const char*>(ehdr) + ehdr->e_shoff);
    129 
    130     const char* symnames =
    131         reinterpret_cast<const char*>(ehdr) + strtab->sh_offset;
    132     VIXL_CHECK(symnames != NULL);
    133 
    134     int nsym = symtab->sh_size / symtab->sh_entsize;
    135     const Elf32_Sym* sym = reinterpret_cast<const Elf32_Sym*>(
    136         reinterpret_cast<const char*>(ehdr) + symtab->sh_offset);
    137     for (int snum = 0; snum < nsym; snum++) {
    138       if ((sym[snum].st_shndx > 0) && (sym[snum].st_shndx < ehdr->e_shnum) &&
    139           (sym[snum].st_value != 0) &&
    140           (shdr[sym[snum].st_shndx].sh_type == SHT_PROGBITS) &&
    141           ((ELF32_ST_BIND(sym[snum].st_info) == STB_LOCAL) ||
    142            (ELF32_ST_BIND(sym[snum].st_info) == STB_GLOBAL)) &&
    143           (ELF32_ST_TYPE(sym[snum].st_info) == STT_FUNC)) {
    144         visitor->visit(symnames + sym[snum].st_name, sym[snum]);
    145       }
    146     }
    147   }
    148 }
    149 
    150 
    151 class DynamicSymbolVisitor {
    152   SymbolTable* symbols_;
    153 
    154  public:
    155   explicit DynamicSymbolVisitor(SymbolTable* symbols) : symbols_(symbols) {}
    156   void visit(const char* symname, const Elf32_Sym& sym) {
    157     symbols_->insert(
    158         Symbol(symname, sym.st_value, 0, sym.st_size, sym.st_shndx));
    159   }
    160 };
    161 
    162 
    163 class StaticSymbolVisitor {
    164   const Elf32_Ehdr* ehdr_;
    165   const Elf32_Shdr* shdr_;
    166   SymbolTable* symbols_;
    167 
    168  public:
    169   StaticSymbolVisitor(const Elf32_Ehdr* ehdr, SymbolTable* symbols)
    170       : ehdr_(ehdr),
    171         shdr_(reinterpret_cast<const Elf32_Shdr*>(
    172             reinterpret_cast<const char*>(ehdr) + ehdr->e_shoff)),
    173         symbols_(symbols) {}
    174   void visit(const char* symname, const Elf32_Sym& sym) {
    175     if (ehdr_->e_type == ET_REL) {
    176       symbols_->insert(Symbol(symname,
    177                               sym.st_value,
    178                               shdr_[sym.st_shndx].sh_offset,
    179                               sym.st_size,
    180                               sym.st_shndx));
    181     } else {
    182       symbols_->insert(
    183           Symbol(symname,
    184                  sym.st_value,
    185                  shdr_[sym.st_shndx].sh_offset - shdr_[sym.st_shndx].sh_addr,
    186                  sym.st_size,
    187                  sym.st_shndx));
    188     }
    189   }
    190 };
    191 
    192 
    193 void usage() {
    194   std::cout << "usage: disasm-a32 <file>\n"
    195                "where <file> is an ELF ARM binaryfile, either an executable, "
    196                "a shared object, or an object file."
    197             << std::endl;
    198 }
    199 
    200 
    201 int main(int argc, char** argv) {
    202   const int kErrorNotARMELF32 = -1;
    203   const int kErrorArguments = -2;
    204   if (argc < 2) {
    205     usage();
    206     return kErrorArguments;
    207   }
    208 
    209   const char* filename = argv[1];
    210   struct stat sb;
    211 
    212 
    213   if (lstat(filename, &sb) == -1) {
    214     std::cerr << "Cannot stat this file" << filename << std::endl;
    215     return errno;
    216   }
    217 
    218   if (S_ISLNK(sb.st_mode)) {
    219     static char linkname[4096];
    220     filename = realpath(argv[1], linkname);
    221     if (lstat(linkname, &sb) == -1) {
    222       std::cerr << "Cannot stat this file: " << linkname << std::endl;
    223       return errno;
    224     }
    225   }
    226 
    227   int elf_in;
    228   if ((elf_in = open(filename, O_RDONLY)) < 0) {
    229     std::cerr << "Cannot open: " << argv[1];
    230     if (filename != argv[1]) std::cerr << " aka " << filename;
    231     std::cerr << std::endl;
    232     return errno;
    233   }
    234 
    235   char* base_addr;
    236   VIXL_CHECK((base_addr = reinterpret_cast<char*>(
    237                   mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, elf_in, 0))) !=
    238              0);
    239 
    240   const Elf32_Ehdr* ehdr = reinterpret_cast<const Elf32_Ehdr*>(base_addr);
    241   if ((ehdr->e_ident[0] != 0x7f) || (ehdr->e_ident[1] != 'E') ||
    242       (ehdr->e_ident[2] != 'L') || (ehdr->e_ident[3] != 'F') ||
    243       (ehdr->e_ehsize != sizeof(Elf32_Ehdr))) {
    244     std::cerr << "This file is not an 32-bit ELF file." << std::endl;
    245     munmap(base_addr, sb.st_size);
    246     return kErrorNotARMELF32;
    247   }
    248 
    249   if (ehdr->e_machine != EM_ARM) {
    250     std::cerr << "This file is not using the ARM isa." << std::endl;
    251     munmap(base_addr, sb.st_size);
    252     return kErrorNotARMELF32;
    253   }
    254 
    255   // shstrtab holds the section names as an offset in the file.
    256   const Elf32_Shdr* shdr =
    257       reinterpret_cast<const Elf32_Shdr*>(base_addr + ehdr->e_shoff);
    258 
    259   SectionLocator section_locator(ehdr);
    260 
    261   SymbolTable symbol_names;
    262 
    263   // Traverse the dynamic symbols defined in any text section
    264   DynamicSymbolVisitor dynamic_visitor(&symbol_names);
    265   LocateSymbols(ehdr,
    266                 section_locator.Locate(SHT_DYNSYM, ".dynsym"),
    267                 section_locator.Locate(SHT_STRTAB, ".dynstr"),
    268                 &dynamic_visitor);
    269 
    270   // Traverse the static symbols defined in the any test section
    271   StaticSymbolVisitor static_visitor(ehdr, &symbol_names);
    272   LocateSymbols(ehdr,
    273                 section_locator.Locate(SHT_SYMTAB, ".symtab"),
    274                 section_locator.Locate(SHT_STRTAB, ".strtab"),
    275                 &static_visitor);
    276 
    277 
    278   vixl::aarch32::PrintDisassembler dis(std::cout, 0);
    279   for (SymbolTable::iterator sres = symbol_names.begin();
    280        sres != symbol_names.end();
    281        sres++) {
    282     const Symbol& symbol = sres->second;
    283     uint32_t func_addr = symbol.GetAddress();
    284     uint32_t func_size = symbol.GetSize();
    285     if (func_size == 0) {
    286       SymbolTable::iterator next_func = sres;
    287       next_func++;
    288       if (next_func == symbol_names.end()) {
    289         const Elf32_Shdr& shndx = shdr[sres->second.GetSection()];
    290         func_size = (shndx.sh_offset + shndx.sh_size) - sres->first;
    291       } else {
    292         func_size = next_func->first - sres->first;
    293       }
    294     }
    295 
    296     std::cout << "--- " << symbol.GetName() << ":" << std::endl;
    297     if ((func_addr & 1) == 1) {
    298       func_addr &= ~1;
    299       dis.SetCodeAddress(func_addr);
    300       dis.DisassembleT32Buffer(reinterpret_cast<uint16_t*>(
    301                                    base_addr + symbol.GetMemoryAddress()),
    302                                func_size);
    303     } else {
    304       dis.SetCodeAddress(func_addr);
    305       dis.DisassembleA32Buffer(reinterpret_cast<uint32_t*>(
    306                                    base_addr + symbol.GetMemoryAddress()),
    307                                func_size);
    308     }
    309   }
    310   munmap(base_addr, sb.st_size);
    311   return 0;
    312 }
    313 
    314 
    315 #else
    316 
    317 #include "globals-vixl.h"
    318 
    319 // TODO: Implement this example for macOS.
    320 int main(void) {
    321   VIXL_WARNING("This example has not been implemented for macOS.");
    322   return 0;
    323 }
    324 
    325 #endif  // __linux__
    326