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