You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
326 lines
10 KiB
326 lines
10 KiB
// 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 <elf.h>
|
|
#include <fcntl.h>
|
|
#include <stdint.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
}
|
|
|
|
#include <cerrno>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <string>
|
|
|
|
#include "globals-vixl.h"
|
|
#include "aarch32/disasm-aarch32.h"
|
|
#include "aarch32/instructions-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<Elf32_Addr, Symbol> {
|
|
public:
|
|
void insert(const Symbol& sym) {
|
|
VIXL_ASSERT(find(sym.GetAddress()) == end());
|
|
std::map<Elf32_Addr, Symbol>::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<const Elf32_Shdr*>(
|
|
reinterpret_cast<const char*>(ehdr) + ehdr->e_shoff);
|
|
// shstrtab holds the section names as an offset in the file.
|
|
shstrtab_ =
|
|
reinterpret_cast<const char*>(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 <typename VISITOR>
|
|
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<const Elf32_Shdr*>(
|
|
reinterpret_cast<const char*>(ehdr) + ehdr->e_shoff);
|
|
|
|
const char* symnames =
|
|
reinterpret_cast<const char*>(ehdr) + strtab->sh_offset;
|
|
VIXL_CHECK(symnames != NULL);
|
|
|
|
int nsym = symtab->sh_size / symtab->sh_entsize;
|
|
const Elf32_Sym* sym = reinterpret_cast<const Elf32_Sym*>(
|
|
reinterpret_cast<const char*>(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<const Elf32_Shdr*>(
|
|
reinterpret_cast<const char*>(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 <file>\n"
|
|
"where <file> 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<char*>(
|
|
mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, elf_in, 0))) !=
|
|
0);
|
|
|
|
const Elf32_Ehdr* ehdr = reinterpret_cast<const Elf32_Ehdr*>(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<const Elf32_Shdr*>(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<uint16_t*>(
|
|
base_addr + symbol.GetMemoryAddress()),
|
|
func_size);
|
|
} else {
|
|
dis.SetCodeAddress(func_addr);
|
|
dis.DisassembleA32Buffer(reinterpret_cast<uint32_t*>(
|
|
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__
|