Split out libmach-o

This commit is contained in:
Lubos Dolezel 2012-08-06 12:32:24 +02:00
parent 5c904a0754
commit cc423dd3a7
90 changed files with 1552 additions and 1308 deletions

5
.gitignore vendored
View File

@ -21,4 +21,9 @@ Thumbs.db
.kdev_include_paths
*~
Makefile
CMakeFiles
cmake_install.cmake
CMakeCache.txt

View File

@ -5,5 +5,43 @@ if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)
add_subdirectory(dyld)
add_subdirectory(libSystem)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src/libmach-o)
set(mach-o_SRCS
src/libmach-o/MachO.cpp
src/libmach-o/FatMachO.cpp
src/libmach-o/RebaseState.cpp
src/libmach-o/BindState.cpp
src/libmach-o/leb.cpp
src/libmach-o/MachOImpl.cpp
src/libmach-o/log.cc
)
add_library(mach-o SHARED ${mach-o_SRCS})
set_target_properties(mach-o PROPERTIES VERSION 1.0.0 SOVERSION 1.0)
set_target_properties(mach-o PROPERTIES COMPILE_FLAGS "-fvisibility=hidden")
target_link_libraries(mach-o -ldl -lpthread)
set(dyld_SRCS
src/dyld/FileMap.cpp
src/dyld/ld-mac.cc
src/dyld/log.cc
)
add_executable(dyld ${dyld_SRCS})
target_link_libraries(dyld -ldl -lpthread mach-o)
set(fatmacho-exract_SRCS
src/dyld/extract.cpp
)
add_executable(fatmacho-exract ${fatmacho-exract_SRCS})
target_link_libraries(fatmacho-exract -ldl -lpthread mach-o)
install(TARGETS dyld fatmacho-exract DESTINATION bin)
add_subdirectory(src/libSystem)

View File

@ -1,840 +0,0 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "FatMachO.h"
#include "log.h"
#include "MachO.h"
#include <mach-o/loader.h>
DEFINE_bool(READ_SYMTAB,
#ifdef NDEBUG
false,
#else
true,
#endif
"Read symtab for better backtrace");
DEFINE_bool(READ_DYSYMTAB, false, "Read dysymtab");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
struct sym {
uint32_t name;
uint32_t addr;
uint32_t flag;
};
struct sym64 {
uint32_t name;
uint64_t addr;
uint32_t flag;
};
// See mach-o/nlist.h for this layout
struct nlist {
uint32_t n_strx;
uint8_t n_type;
uint8_t n_sect;
uint16_t n_desc;
uint64_t n_value;
};
#define N_WEAK_DEF 0x0080
static uint64_t uleb128(const uint8_t*& p) {
uint64_t r = 0;
int s = 0;
do {
r |= (uint64_t)(*p & 0x7f) << s;
s += 7;
} while (*p++ >= 0x80);
return r;
}
static int64_t sleb128(const uint8_t*& p) {
int64_t r = 0;
int s = 0;
for (;;) {
uint8_t b = *p++;
if (b < 0x80) {
if (b & 0x40) {
r -= (0x80 - b) << s;
}
else {
r |= (b & 0x3f) << s;
}
break;
}
r |= (b & 0x7f) << s;
s += 7;
}
return r;
}
class MachOImpl : public MachO {
public:
// Take ownership of fd.
// If len is 0, the size of file will be used as len.
MachOImpl(const char* filename, int fd, size_t offset, size_t len,
bool need_exports);
virtual ~MachOImpl();
virtual void close();
private:
class RebaseState;
friend class MachOImpl::RebaseState;
class BindState;
friend class MachOImpl::BindState;
template <class segment_command, class section>
void readSegment(char* cmds_ptr,
vector<segment_command*>* segments,
vector<section*>* bind_sections);
void readRebase(const uint8_t* p, const uint8_t* end);
void readBind(const uint8_t* p, const uint8_t* end, bool is_weak);
void readExport(const uint8_t* start, const uint8_t* p, const uint8_t* end,
string* name_buf);
template <class section>
void readClassicBind(const section& sec,
uint32_t* dysyms,
uint32_t* symtab,
const char* symstrtab) {
uint32_t indirect_offset = sec.reserved1;
int count = sec.size / m_ptrsize;
for (int i = 0; i < count; i++) {
uint32_t dysym = dysyms[indirect_offset + i];
uint32_t index = dysym & 0x3fffffff;
nlist* sym = (nlist*)(symtab + index * (m_is64 ? 4 : 3));
MachO::Bind* bind = new MachO::Bind();
bind->name = symstrtab + sym->n_strx;
bind->vmaddr = sec.addr + i * m_ptrsize;
bind->value = sym->n_value;
bind->type = BIND_TYPE_POINTER;
bind->ordinal = 1;
bind->is_weak = ((sym->n_desc & N_WEAK_DEF) != 0);
bind->is_classic = true;
LOGF("add classic bind! %s type=%d sect=%d desc=%d value=%lld "
"vmaddr=%p is_weak=%d\n",
bind->name.c_str(), sym->n_type, sym->n_sect, sym->n_desc, (ll)sym->n_value,
(void*)(bind->vmaddr), bind->is_weak);
m_binds.push_back(bind);
}
}
char* mapped_;
size_t mapped_size_;
bool need_m_exports;
};
template <class segment_command, class section>
void MachOImpl::readSegment(char* cmds_ptr,
vector<segment_command*>* segments,
vector<section*>* bind_sections) {
segment_command* segment =
reinterpret_cast<segment_command*>(cmds_ptr);
segments->push_back(segment);
LOGF("segment %s: vmaddr=%p vmsize=%llu "
"fileoff=%llu filesize=%llu "
"maxprot=%d initprot=%d nsects=%u flags=%u\n",
segment->segname,
(void*)(intptr_t)segment->vmaddr, (ull)segment->vmsize,
(ull)segment->fileoff, (ull)segment->filesize,
segment->maxprot, segment->initprot,
segment->nsects, segment->flags);
section* sections = reinterpret_cast<section*>(
cmds_ptr + sizeof(segment_command));
for (uint32_t j = 0; j < segment->nsects; j++) {
const section& sec = sections[j];
LOGF("section %s in %s: "
"addr=%p size=%llu offset=%u align=%u "
"reloff=%u nreloc=%u flags=%u "
"reserved1=%u reserved2=%u\n",
sec.sectname, sec.segname,
(void*)(intptr_t)sec.addr, (ull)sec.size,
sec.offset, sec.align,
sec.reloff, sec.nreloc, sec.flags,
sec.reserved1, sec.reserved2);
if (!strcmp(sec.sectname, "__dyld") &&
!strcmp(sec.segname, "__DATA")) {
m_dyld_data = sec.addr;
}
int section_type = sec.flags & SECTION_TYPE;
switch (section_type) {
case S_REGULAR:
/* Regular section: nothing to do */
break;
case S_MOD_INIT_FUNC_POINTERS: {
for (uint64_t p = sec.addr; p < sec.addr + sec.size; p += m_ptrsize) {
m_init_funcs.push_back(p);
}
break;
}
case S_MOD_TERM_FUNC_POINTERS:
for (uint64_t p = sec.addr; p < sec.addr + sec.size; p += m_ptrsize) {
m_exit_funcs.push_back(p);
}
break;
case S_NON_LAZY_SYMBOL_POINTERS:
case S_LAZY_SYMBOL_POINTERS: {
bind_sections->push_back(sections + j);
break;
}
case S_ZEROFILL:
case S_CSTRING_LITERALS:
case S_4BYTE_LITERALS:
case S_8BYTE_LITERALS:
case S_LITERAL_POINTERS:
case S_SYMBOL_STUBS:
case S_COALESCED:
case S_GB_ZEROFILL:
case S_INTERPOSING:
case S_16BYTE_LITERALS:
case S_DTRACE_DOF:
case S_LAZY_DYLIB_SYMBOL_POINTERS:
LOGF("FIXME: section type %d will not be handled for %s in %s\n",
section_type, sec.sectname, sec.segname);
break;
default:
fprintf(stderr, "Unknown section type: %d\n", section_type);
abort();
break;
}
}
}
struct MachOImpl::RebaseState {
explicit RebaseState(MachOImpl* mach0)
: mach(mach0), type(0), seg_index(0), seg_offset(0) {}
bool readRebaseOp(const uint8_t*& p) {
uint8_t op = *p & REBASE_OPCODE_MASK;
uint8_t imm = *p & REBASE_IMMEDIATE_MASK;
p++;
switch (op) {
case REBASE_OPCODE_DONE:
return false;
case REBASE_OPCODE_SET_TYPE_IMM:
type = imm;
break;
case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
seg_index = imm;
seg_offset = uleb128(p);
break;
case REBASE_OPCODE_ADD_ADDR_ULEB:
seg_offset += uleb128(p);
break;
case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
seg_offset += imm * mach->m_ptrsize;
break;
case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
for (int i = 0; i < imm; i++) {
addRebase();
}
break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES: {
int count = uleb128(p);
for (int i = 0; i < count; i++) {
addRebase();
}
break;
}
case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
addRebase();
seg_offset += uleb128(p);
break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: {
int count = uleb128(p);
uint64_t skip = uleb128(p);
for (int i = 0; i < count; i++) {
addRebase();
seg_offset += skip;
}
break;
}
default:
fprintf(stderr, "unknown op: %x\n", op);
}
return true;
}
void addRebase() {
MachO::Rebase* rebase = new MachO::Rebase();
uint64_t vmaddr;
if (mach->m_is64) {
vmaddr = mach->m_segments64[seg_index]->vmaddr;
} else {
vmaddr = mach->m_segments[seg_index]->vmaddr;
}
LOGF("add rebase! seg_index=%d seg_offset=%llu type=%d vmaddr=%p\n",
seg_index, (ull)seg_offset, type, (void*)vmaddr);
rebase->vmaddr = vmaddr + seg_offset;
rebase->type = type;
mach->m_rebases.push_back(rebase);
seg_offset += mach->m_ptrsize;
}
MachOImpl* mach;
uint8_t type;
int seg_index;
uint64_t seg_offset;
};
void MachOImpl::readRebase(const uint8_t* p, const uint8_t* end) {
RebaseState state(this);
while (p < end) {
if (!state.readRebaseOp(p))
break;
}
}
struct MachOImpl::BindState {
BindState(MachOImpl* mach0, bool is_weak0)
: mach(mach0), ordinal(0), sym_name(NULL), type(BIND_TYPE_POINTER),
addend(0), seg_index(0), seg_offset(0), is_weak(is_weak0) {}
void readBindOp(const uint8_t*& p) {
uint8_t op = *p & BIND_OPCODE_MASK;
uint8_t imm = *p & BIND_IMMEDIATE_MASK;
p++;
LOGF("bind: op=%x imm=%d\n", op, imm);
switch (op) {
case BIND_OPCODE_DONE:
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
ordinal = imm;
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
ordinal = uleb128(p);
break;
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
if (imm == 0) {
ordinal = 0;
} else {
ordinal = BIND_OPCODE_MASK | imm;
}
break;
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
sym_name = reinterpret_cast<const char*>(p);
p += strlen(sym_name) + 1;
LOGF("sym_name=%s\n", sym_name);
break;
case BIND_OPCODE_SET_TYPE_IMM:
type = imm;
break;
case BIND_OPCODE_SET_ADDEND_SLEB:
addend = sleb128(p);
break;
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
seg_index = imm;
seg_offset = uleb128(p);
break;
case BIND_OPCODE_ADD_ADDR_ULEB:
seg_offset += uleb128(p);
break;
case BIND_OPCODE_DO_BIND:
addBind();
break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
LOGF("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
addBind();
seg_offset += uleb128(p);
break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
LOGF("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED %d\n", (int)imm);
addBind();
seg_offset += imm * mach->m_ptrsize;
break;
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: {
uint64_t count = uleb128(p);
uint64_t skip = uleb128(p);
LOGF("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB %u %u\n",
(unsigned)count, (unsigned)skip);
for (uint64_t i = 0; i < count; i++) {
addBind();
seg_offset += skip;
}
break;
}
default:
fprintf(stderr, "unknown op: %x\n", op);
}
}
void addBind() {
MachO::Bind* bind = new MachO::Bind();
uint64_t vmaddr;
if (mach->m_is64) {
vmaddr = mach->m_segments64[seg_index]->vmaddr;
} else {
vmaddr = mach->m_segments[seg_index]->vmaddr;
}
LOGF("add bind! %s seg_index=%d seg_offset=%llu "
"type=%d ordinal=%d addend=%lld vmaddr=%p is_weak=%d\n",
sym_name, seg_index, (ull)seg_offset,
type, ordinal, (ll)addend, (void*)(vmaddr + seg_offset), is_weak);
bind->name = sym_name;
bind->vmaddr = vmaddr + seg_offset;
bind->addend = addend;
bind->type = type;
bind->ordinal = ordinal;
bind->is_weak = is_weak;
mach->m_binds.push_back(bind);
seg_offset += mach->m_ptrsize;
}
MachOImpl* mach;
uint8_t ordinal;
const char* sym_name;
uint8_t type;
int64_t addend;
int seg_index;
uint64_t seg_offset;
bool is_weak;
};
void MachOImpl::readBind(const uint8_t* p, const uint8_t* end, bool is_weak) {
BindState state(this, is_weak);
while (p < end) {
state.readBindOp(p);
}
}
void MachOImpl::readExport(const uint8_t* start,
const uint8_t* p,
const uint8_t* end,
string* name_buf) {
LOGF("readExport: %p-%p\n", p, end);
#if 0
char buf[17];
buf[16] = '\0';
for (int i = 0; i < 16*8; i++) {
LOGF("%02x ", p[i]);
buf[i % 16] = p[i] < 32 ? '?' : p[i];
if (i % 16 == 15) LOGF("%s\n", buf);
}
#endif
if (p >= end) {
fprintf(stderr, "broken export trie\n");
exit(1);
}
if (uint8_t term_size = *p++) {
const uint8_t* expected_term_end = p + term_size;
Export* exp = new Export;
exp->name = *name_buf;
exp->flag = uleb128(p);
exp->addr = uleb128(p);
LOGF("export: %s %lu %p\n",
name_buf->c_str(), (long)exp->flag, (void*)exp->addr);
m_exports.push_back(exp);
CHECK(expected_term_end == p);
}
const uint8_t num_children = *p++;
for (uint8_t i = 0; i < num_children; i++) {
size_t orig_name_size = name_buf->size();
while (*p) {
name_buf->push_back(*p++);
}
p++;
uint64_t off = uleb128(p);
CHECK(off != 0);
readExport(start, start + off, end, name_buf);
name_buf->resize(orig_name_size);
}
}
MachOImpl::MachOImpl(const char* filename, int fd, size_t offset, size_t len,
bool need_exports)
: mapped_(NULL), mapped_size_(len) {
m_filename = filename;
need_m_exports = need_exports;
m_dyld_data = 0;
CHECK(fd);
m_fd = fd;
m_offset = offset;
if (!mapped_size_) {
mapped_size_ = lseek(m_fd, 0, SEEK_END);
}
lseek(fd, 0, SEEK_SET);
char* bin = mapped_ = reinterpret_cast<char*>(
mmap(NULL, mapped_size_,
PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, m_fd, offset));
m_base = bin;
mach_header* header = reinterpret_cast<mach_header*>(bin);
LOGF("magic=%x cpu=%d cpusub=%d file=%d ncmds=%d sizecmd=%d flags=%x\n",
header->magic, header->cputype, header->cpusubtype,
header->filetype, header->ncmds, header->sizeofcmds,
header->flags);
m_is64 = false;
if (header->magic == MH_MAGIC_64) {
m_is64 = true;
} else if (header->magic != MH_MAGIC) {
fprintf(stderr, "Not mach-o: %s\n", filename);
exit(1);
}
m_ptrsize = m_is64 ? 8 : 4;
if ((header->cputype & 0x00ffffff) != CPU_TYPE_X86) {
fprintf(stderr, "Unsupported CPU\n");
exit(1);
}
struct load_command* cmds_ptr = reinterpret_cast<struct load_command*>(
bin + (m_is64 ? sizeof(mach_header_64)
: sizeof(mach_header)));
uint32_t* symtab = NULL;
uint32_t* dysyms = NULL;
const char* symstrtab = NULL;
dyld_info_command* dyinfo = NULL;
vector<section_64*> bind_sections_64;
vector<section*> bind_sections_32;
for (uint32_t ii = 0; ii < header->ncmds; ii++) {
LOGF("cmd type:%x\n", cmds_ptr->cmd);
switch (cmds_ptr->cmd) {
case LC_SEGMENT_64: {
readSegment<segment_command_64, section_64>(
(char*)cmds_ptr, &m_segments64, &bind_sections_64);
break;
}
case LC_SEGMENT: {
readSegment<segment_command, section>(
(char*)cmds_ptr, &m_segments, &bind_sections_32);
break;
}
case LC_DYLD_INFO:
case LC_DYLD_INFO_ONLY: {
dyinfo = reinterpret_cast<dyld_info_command*>(cmds_ptr);
LOGF("dyld info: rebase_off=%u rebase_size=%u "
"bind_off=%u bind_size=%u "
"weak_bind_off=%u weak_bind_size=%u "
"lazy_bind_off=%u lazy_bind_size=%u "
"export_off=%u export_size=%u\n",
dyinfo->rebase_off, dyinfo->rebase_size,
dyinfo->bind_off, dyinfo->bind_size,
dyinfo->weak_bind_off, dyinfo->weak_bind_size,
dyinfo->lazy_bind_off, dyinfo->lazy_bind_size,
dyinfo->export_off, dyinfo->export_size);
{
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->rebase_off);
const uint8_t* end = p + dyinfo->rebase_size;
if (dyinfo->rebase_off && dyinfo->rebase_size) {
readRebase(p, end);
}
}
{
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->bind_off);
const uint8_t* end = p + dyinfo->bind_size;
readBind(p, end, false);
}
{
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->lazy_bind_off);
const uint8_t* end = p + dyinfo->lazy_bind_size;
readBind(p, end, false);
}
{
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->weak_bind_off);
const uint8_t* end = p + dyinfo->weak_bind_size;
readBind(p, end, true);
}
if (need_m_exports) {
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->export_off);
const uint8_t* end = p + dyinfo->export_size;
if (dyinfo->export_off && dyinfo->export_size) {
string buf;
readExport(p, p, end, &buf);
}
}
break;
}
case LC_SYMTAB: {
symtab_command* symtab_cmd =
reinterpret_cast<symtab_command*>(cmds_ptr);
LOGF("symoff=%u nsysm=%u stroff=%u strsize=%u\n",
symtab_cmd->symoff, symtab_cmd->nsyms,
symtab_cmd->stroff, symtab_cmd->strsize);
uint32_t* symtab_top = symtab =
reinterpret_cast<uint32_t*>(bin + symtab_cmd->symoff);
symstrtab = bin + symtab_cmd->stroff;
if (FLAGS_READ_SYMTAB) {
for (uint32_t i = 0; i < symtab_cmd->nsyms; i++) {
Symbol sym;
nlist* nl = (nlist*)symtab;
sym.name = symstrtab + nl->n_strx;
if (m_is64) {
sym.addr = nl->n_value;
symtab += 4;
} else {
sym.addr = (uint32_t)nl->n_value;
symtab += 3;
}
LOGF("%d %s(%d) %p\n",
i, sym.name.c_str(), nl->n_strx, (void*)sym.addr);
m_symbols.push_back(sym);
}
}
// Will be used by other load commands.
symtab = symtab_top;
break;
}
case LC_DYSYMTAB: {
dysymtab_command* dysymtab_cmd =
reinterpret_cast<dysymtab_command*>(cmds_ptr);
LOGF("dysym:\n"
" ilocalsym=%u nlocalsym=%u\n"
" iextdefsym=%u nextdefsym=%u\n"
" iundefsym=%u nundefsym=%u\n"
" tocoff=%u ntoc=%u\n"
" modtaboff=%u nmodtab=%u\n"
" extrefsymoff=%u nextrefsyms=%u\n"
" indirectsymoff=%u nindirectsyms=%u\n"
" extreloff=%u nextrel=%u\n"
" locreloff=%u nlocrel=%u\n"
,
dysymtab_cmd->ilocalsym, dysymtab_cmd->nlocalsym,
dysymtab_cmd->iextdefsym, dysymtab_cmd->nextdefsym,
dysymtab_cmd->iundefsym, dysymtab_cmd->nundefsym,
dysymtab_cmd->tocoff, dysymtab_cmd->ntoc,
dysymtab_cmd->modtaboff, dysymtab_cmd->nmodtab,
dysymtab_cmd->extrefsymoff, dysymtab_cmd->nextrefsyms,
dysymtab_cmd->indirectsymoff, dysymtab_cmd->nindirectsyms,
dysymtab_cmd->extreloff, dysymtab_cmd->nextrel,
dysymtab_cmd->locreloff, dysymtab_cmd->nlocrel);
if (dysymtab_cmd->nindirectsyms) {
dysyms = reinterpret_cast<uint32_t*>(
bin + dysymtab_cmd->indirectsymoff);
}
if (FLAGS_READ_DYSYMTAB) {
for (uint32_t j = 0; j < dysymtab_cmd->nindirectsyms; j++) {
uint32_t dysym = dysyms[j];
uint32_t index = dysym & 0x3fffffff;
const char* local =
(dysym & INDIRECT_SYMBOL_LOCAL) ? " local" : "";
const char* abs =
(dysym & INDIRECT_SYMBOL_ABS) ? " abs" : "";
uint32_t* sym = symtab;
sym += index * (m_is64 ? 4 : 3);
LOGF("dysym %d %s(%u)%s%s\n",
j, symstrtab + sym[0], index, local, abs);
}
uint32_t* dymods = reinterpret_cast<uint32_t*>(
bin + dysymtab_cmd->modtaboff);
for (uint32_t j = 0; j < dysymtab_cmd->nmodtab; j++) {
LOGF("dymods: %u\n", dymods[j]);
}
}
break;
}
case LC_LOAD_DYLINKER: {
lc_str name = reinterpret_cast<struct dylinker_command*>(cmds_ptr)->name;
LOGF("dylinker: %s\n", (char*)cmds_ptr + name.offset);
break;
}
case LC_UUID:
break;
case LC_UNIXTHREAD: {
uint32_t* p = reinterpret_cast<uint32_t*>(cmds_ptr);
LOGF("UNIXTHREAD");
for (uint32_t i = 2; i < p[1]; i++) {
LOGF(" %d:%x", i, p[i]);
}
LOGF("\n");
if (m_is64) {
m_entry = reinterpret_cast<uint64_t*>(cmds_ptr)[18];
} else {
m_entry = reinterpret_cast<uint32_t*>(cmds_ptr)[14];
}
LOGF("entry=%llx\n", (ull)m_entry);
break;
}
case LC_LOAD_DYLIB: {
dylib* lib = &reinterpret_cast<dylib_command*>(cmds_ptr)->dylib;
LOGF("dylib: '%s'\n", (char*)cmds_ptr + lib->name.offset);
m_dylibs.push_back((char*)cmds_ptr + lib->name.offset);
break;
}
}
cmds_ptr = reinterpret_cast<load_command*>(
reinterpret_cast<char*>(cmds_ptr) + cmds_ptr->cmdsize);
}
LOGF("%p vs %p\n", cmds_ptr, bin + mapped_size_);
// No LC_DYLD_INFO_ONLY, we will read classic binding info.
if (!dyinfo && dysyms && symtab && symstrtab) {
for (size_t i = 0; i < bind_sections_64.size(); i++) {
readClassicBind<section_64>(
*bind_sections_64[i], dysyms, symtab, symstrtab);
}
for (size_t i = 0; i < bind_sections_32.size(); i++) {
readClassicBind<section>(
*bind_sections_32[i], dysyms, symtab, symstrtab);
}
}
}
MachOImpl::~MachOImpl() {
close();
}
void MachOImpl::close() {
for (size_t i = 0; i < m_binds.size(); i++) {
delete m_binds[i];
}
m_binds.clear();
for (size_t i = 0; i < m_rebases.size(); i++) {
delete m_rebases[i];
}
m_rebases.clear();
for (size_t i = 0; i < m_exports.size(); i++) {
delete m_exports[i];
}
m_exports.clear();
if (mapped_) {
munmap(mapped_, mapped_size_);
::close(m_fd);
mapped_ = NULL;
m_fd = -1;
}
}
MachO* MachO::readFile(std::string path, const char* arch, bool need_exports) {
int fd = open(path.c_str(), O_RDONLY);
if (fd < 0) {
fprintf(stderr, "%s: %s\n", path.c_str(), strerror(errno));
exit(1);
}
size_t offset = 0, len = 0;
map<string, fat_arch> archs;
if (FatMachO::readFatInfo(fd, &archs)) {
map<string, fat_arch>::const_iterator found = archs.find(arch);
if (found == archs.end()) {
fprintf(stderr,
"%s is a fat binary, but doesn't contain %s binary\n",
path.c_str(), arch);
exit(1);
}
offset = found->second.offset;
len = found->second.size;
LOGF("fat offset=%lu, len=%lu\n",
(unsigned long)offset, (unsigned long)len);
}
return new MachOImpl(path.c_str(), fd, offset, len, need_exports);
}

View File

@ -1,129 +0,0 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#ifndef MACH_O_H_
#define MACH_O_H_
#include <stdint.h>
#include <string>
#include <vector>
#include "mach-o/loader.h"
using namespace std;
class MachO {
public:
struct Rebase {
uint64_t vmaddr;
uint8_t type;
};
struct Bind {
uint64_t vmaddr;
const char* name;
union {
int64_t addend;
uint64_t value;
};
uint8_t type;
uint8_t ordinal;
bool is_weak;
bool is_classic;
};
struct Export {
string name;
uint64_t addr;
uint32_t flag;
};
struct Symbol {
string name;
uint64_t addr;
};
static MachO* read(const char* path, const char* arch,
bool need_exports = true);
virtual ~MachO() {}
virtual void close() = 0;
const string& filename() const { return filename_; }
const vector<segment_command_64*>& segments64() const {
return segments64_;
}
const vector<segment_command*>& segments() const {
return segments_;
}
const vector<const char*>& dylibs() const { return dylibs_; }
const vector<Rebase*>& rebases() const { return rebases_; }
const vector<Bind*>& binds() const { return binds_; }
const vector<Export*>& exports() const { return exports_; }
const vector<Symbol>& symbols() const { return symbols_; }
const char* base() const { return base_; }
uint64_t entry() const { return entry_; }
const vector<uint64_t>& init_funcs() const { return init_funcs_; }
uint64_t dyld_data() const { return dyld_data_; }
bool is64() const { return is64_; }
int fd() const { return fd_; }
size_t offset() const { return offset_; }
protected:
string filename_;
vector<segment_command_64*> segments64_;
vector<segment_command*> segments_;
vector<const char*> dylibs_;
vector<Rebase*> rebases_;
vector<Bind*> binds_;
vector<Export*> exports_;
vector<Symbol> symbols_;
const char* base_;
uint64_t entry_;
vector<uint64_t> init_funcs_;
uint64_t dyld_data_;
bool is64_;
int ptrsize_;
int fd_;
size_t offset_;
};
#endif // MACH_O_H_

View File

@ -1 +0,0 @@
/home/lubos/Projects/darling/libmac/xnu

View File

@ -1,216 +0,0 @@
#include "vm.h"
#include "task.h"
#include "mach-stub.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
#include <cstring>
static bool memory_readable(const void* ptr, size_t bytes)
{
int fd = ::open("/dev/null", O_WRONLY);
if (fd == -1)
return false;
int r = ::write(fd, ptr, bytes);
::close(fd);
if (r != bytes)
{
if (errno == EFAULT)
return false;
}
return true;
}
static bool memory_writable(void* ptr, size_t bytes)
{
int fd = ::open("/dev/zero", O_RDONLY);
if (fd == -1)
return false;
int r = ::read(fd, ptr, bytes);
::close(fd);
if (r != bytes)
{
if (errno == EFAULT)
return false;
}
return true;
}
kern_return_t vm_msync(vm_task_t target_task, void* addr, vm_size_t size, vm_sync_t in_flags)
{
CHECK_TASK_SELF(target_task);
int flags = 0;
if (in_flags & VM_SYNC_SYNCHRONOUS)
flags |= MS_SYNC;
if (in_flags & VM_SYNC_ASYNCHRONOUS)
flags |= MS_ASYNC;
if (in_flags & VM_SYNC_INVALIDATE)
flags |= MS_INVALIDATE;
if (::msync(addr, size, flags) == -1)
return KERN_INVALID_ADDRESS;
else
return KERN_SUCCESS;
}
kern_return_t vm_allocate(vm_task_t target_task, void** addr, vm_size_t size, boolean_t anywhere)
{
CHECK_TASK_SELF(target_task);
int flags = MAP_ANONYMOUS|MAP_PRIVATE;
if (!anywhere)
flags |= MAP_FIXED;
// Give the memory all permissions, as per vm_allocate definition
*addr = ::mmap(*addr, size, PROT_EXEC|PROT_READ|PROT_WRITE, flags, 0, 0);
if (!*addr)
{
if (errno == EINVAL)
return KERN_INVALID_ADDRESS;
else
return KERN_NO_SPACE; // No other return values are permitted
}
else
return KERN_SUCCESS;
}
kern_return_t vm_deallocate(vm_task_t target_task, void* addr, vm_size_t size)
{
CHECK_TASK_SELF(target_task);
if (::munmap(addr, size) == -1)
return KERN_INVALID_ADDRESS;
else
return KERN_SUCCESS;
}
kern_return_t vm_copy(vm_task_t target_task, const void* source_address, vm_size_t count, void* dest_address)
{
CHECK_TASK_SELF(target_task);
if (!memory_readable(source_address, count))
return KERN_INVALID_ADDRESS;
if (!memory_writable(dest_address, count))
return KERN_INVALID_ADDRESS;
::memcpy(dest_address, source_address, count);
return KERN_SUCCESS;
}
kern_return_t vm_write(vm_task_t target_task, void* address, const void* data, vm_size_t data_count)
{
CHECK_TASK_SELF(target_task);
if (!memory_writable(address, data_count))
return KERN_INVALID_ADDRESS;
if (!memory_readable(data, data_count))
return KERN_INVALID_ADDRESS;
::memcpy(address, data, data_count);
return KERN_SUCCESS;
}
kern_return_t vm_behavior_set (vm_task_t target_task, void* address, vm_size_t size, vm_behavior_t behavior)
{
CHECK_TASK_SELF(target_task);
MACH_STUB();
}
kern_return_t vm_inherit (vm_task_t target_task, void* address, vm_size_t size, vm_inherit_t new_inheritance)
{
CHECK_TASK_SELF(target_task);
MACH_STUB();
}
kern_return_t vm_machine_attribute(vm_task_t target_task, void* address, vm_size_t size, vm_machine_attribute_t attribute, vm_machine_attribute_val_t value)
{
CHECK_TASK_SELF(target_task);
MACH_STUB();
}
kern_return_t vm_map(vm_task_t target_task, void* address, vm_size_t size, void* mask, boolean_t anywhere, memory_object_t memory_object, vm_offset_t offset,
boolean_t copy, vm_prot_t cur_protection, vm_prot_t max_protection, vm_inherit_t inheritance)
{
CHECK_TASK_SELF(target_task);
MACH_STUB();
}
kern_return_t vm_protect(vm_task_t target_task, void* address, vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection)
{
CHECK_TASK_SELF(target_task);
// FIXME: Here we ignore set_maximum, not sure what to do with that
int flags = 0;
if (new_protection & VM_PROT_READ)
flags |= PROT_READ;
if (new_protection & VM_PROT_WRITE)
flags |= PROT_WRITE;
if (new_protection & VM_PROT_EXECUTE)
flags |= PROT_EXEC;
if (::mprotect(address, size, flags) == -1)
{
if (errno == EACCES)
return KERN_PROTECTION_FAILURE;
else if (errno == EINVAL || errno == ENOMEM)
return KERN_INVALID_ADDRESS;
else
return KERN_FAILURE;
}
else
return KERN_SUCCESS;
}
kern_return_t vm_read(vm_task_t target_task, const void* address, vm_size_t size, void** data_out, natural_t* data_count)
{
CHECK_TASK_SELF(target_task);
if (!memory_readable(address, size))
return KERN_INVALID_ADDRESS;
kern_return_t ret = vm_allocate(mach_task_self_, data_out, size, true);
if (ret != KERN_SUCCESS)
return ret;
::memcpy(*data_out, address, size);
*data_count = size; // Is this correct?
return KERN_SUCCESS;
}
kern_return_t vm_read_overwrite (vm_task_t target_task, void* address, vm_size_t size, void* data_in, natural_t* data_count)
{
CHECK_TASK_SELF(target_task);
MACH_STUB();
}
kern_return_t vm_region(vm_task_t target_task, void* address, vm_size_t size, vm_region_flavor_t flavor, vm_region_info_t info, mach_msg_type_number_t info_count, memory_object_name_t object_name)
{
CHECK_TASK_SELF(target_task);
MACH_STUB();
}
kern_return_t vm_remap(vm_task_t target_task, void* target_address, vm_size_t size, void* mask, boolean_t anywhere, mach_port_t source_task, void* source_address, boolean_t copy,
vm_prot_t cur_protection, vm_prot_t max_protection, vm_inherit_t inheritance)
{
CHECK_TASK_SELF(target_task);
MACH_STUB();
}
kern_return_t vm_wire(host_priv_t host, vm_task_t target_task, void* address, vm_size_t size, vm_prot_t wired_access)
{
CHECK_TASK_SELF(target_task);
MACH_STUB();
}

View File

@ -1,38 +0,0 @@
#include "MachO.h"
#include "FatMachO.h"
#include <cstdio>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <string>
#include <map>
MachO* MachO::read(std::string path, const char* arch, bool need_exports)
{
int fd = ::open(path.c_str(), O_RDONLY);
if (fd < 0)
{
std::cerr << path << ": " << strerror(errno) << std::endl;
return 0;
}
size_t offset = 0, len = 0;
std::map<std::string, fat_arch> archs;
if (FatMachO::readFatInfo(fd, &archs))
{
std::map<string, fat_arch>::const_iterator found = archs.find(arch);
if (found == archs.end())
{
std::cerr << path << " is a fat binary, but doesn't support the following architecture: " << arch << std::endl;
return 0;
}
offset = found->second.offset;
len = found->second.size;
LOGF("fat offset=%lu, len=%lu\n", (unsigned long)offset, (unsigned long)len);
}
return new MachOImpl(path, fd, offset, len, need_exports);
}

View File

@ -10,10 +10,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../libmach-o)
set(dyld_SRCS
FatMachO.cpp
FileMap.cpp
ld-mac.cc
log.cc
mach-o.cc
)
add_executable(dyld ${dyld_SRCS})
@ -22,11 +21,10 @@ target_link_libraries(dyld -ldl -lpthread)
set(fatmacho-exract_SRCS
extract.cpp
FatMachO.cpp
)
add_executable(fatmacho-exract ${fatmacho-exract_SRCS})
target_link_libraries(fatmacho-exract -ldl -lpthread)
target_link_libraries(fatmacho-exract -ldl -lpthread mach-o)
install(TARGETS dyld fatmacho-exract DESTINATION bin)

97
src/dyld/FileMap.cpp Normal file
View File

@ -0,0 +1,97 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#include "FileMap.h"
#include <cassert>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <err.h>
void FileMap::add(const MachO& mach, uintptr_t slide, uintptr_t base)
{
SymbolMap* symbol_map = new SymbolMap();
symbol_map->filename = mach.filename();
symbol_map->base = base;
if (!m_maps.insert(std::make_pair(base, symbol_map)).second)
{
err(1, "dupicated base addr: %p in %s",
(void*)base, mach.filename().c_str());
}
for (size_t i = 0; i < mach.symbols().size(); i++)
{
MachO::Symbol sym = mach.symbols()[i];
if (sym.name.empty() || sym.name[0] != '_')
continue;
sym.addr += slide;
if (sym.addr < base)
continue;
symbol_map->symbols.insert(std::make_pair(sym.addr, sym.name.substr(1)));
}
}
void FileMap::addWatchDog(uintptr_t addr)
{
bool r = m_maps.insert(std::make_pair(addr, (SymbolMap*)NULL)).second;
assert(r);
}
const char* FileMap::dumpSymbol(void* p)
{
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
std::map<uintptr_t, SymbolMap*>::const_iterator found = m_maps.upper_bound(addr);
if (found == m_maps.begin() || found == m_maps.end())
{
return 0;
}
--found;
return dumpSymbolFromMap(*found->second, addr);
}
const char* FileMap::dumpSymbolFromMap(const SymbolMap& symbol_map, uintptr_t addr)
{
uintptr_t file_offset = addr - symbol_map.base;
// Use lower_bound as PC may be in just after call.
std::map<uintptr_t, std::string>::const_iterator found = symbol_map.symbols.lower_bound(addr);
if (found == symbol_map.symbols.begin())
{
snprintf(m_dumped_stack_frame_buf, 4095, "%s [%p(%lx)]",
symbol_map.filename.c_str(), (void*)addr, (long)file_offset);
return m_dumped_stack_frame_buf;
}
--found;
const char* name = found->second.c_str();
uintptr_t func_offset = addr - found->first;
snprintf(m_dumped_stack_frame_buf, 4095, "%s(%s+%lx) [%p(%lx)]",
symbol_map.filename.c_str(), name, (long)func_offset,
(void*)addr, (long)file_offset);
return m_dumped_stack_frame_buf;
}

59
src/dyld/FileMap.h Normal file
View File

@ -0,0 +1,59 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#ifndef FILEMAP_H
#define FILEMAP_H
#include <stdint.h>
#include <string>
#include <map>
#include "MachO.h"
class FileMap
{
public:
void add(const MachO& mach, uintptr_t slide, uintptr_t base);
void addWatchDog(uintptr_t addr);
const char* dumpSymbol(void* p);
private:
struct SymbolMap
{
std::string filename;
std::map<uintptr_t, std::string> symbols;
uintptr_t base;
};
const char* dumpSymbolFromMap(const SymbolMap& symbol_map, uintptr_t addr);
std::map<uintptr_t, SymbolMap*> m_maps;
char m_dumped_stack_frame_buf[4096];
};
#endif

View File

@ -55,6 +55,7 @@
#include "FatMachO.h"
#include "log.h"
#include "MachO.h"
#include "FileMap.h"
using namespace std;
using namespace std::tr1;
@ -87,75 +88,6 @@ struct Timer {
clock_t start_time;
};
class FileMap {
public:
void add(const MachO& mach, uintptr_t slide, uintptr_t base) {
SymbolMap* symbol_map = new SymbolMap();
symbol_map->filename = mach.filename();
symbol_map->base = base;
if (!maps_.insert(make_pair(base, symbol_map)).second) {
err(1, "dupicated base addr: %p in %s",
(void*)base, mach.filename().c_str());
}
for (size_t i = 0; i < mach.symbols().size(); i++) {
MachO::Symbol sym = mach.symbols()[i];
if (sym.name.empty() || sym.name[0] != '_')
continue;
sym.addr += slide;
if (sym.addr < base)
continue;
symbol_map->symbols.insert(make_pair(sym.addr, sym.name.substr(1)));
}
}
void addWatchDog(uintptr_t addr) {
bool r = maps_.insert(make_pair(addr, (SymbolMap*)NULL)).second;
CHECK(r);
}
const char* dumpSymbol(void* p) {
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
map<uintptr_t, SymbolMap*>::const_iterator found = maps_.upper_bound(addr);
if (found == maps_.begin() || found == maps_.end()) {
return NULL;
}
--found;
return dumpSymbolFromMap(*found->second, addr);
}
private:
struct SymbolMap {
string filename;
map<uintptr_t, string> symbols;
uintptr_t base;
};
const char* dumpSymbolFromMap(const SymbolMap& symbol_map, uintptr_t addr) {
uintptr_t file_offset = addr - symbol_map.base;
// Use lower_bound as PC may be in just after call.
map<uintptr_t, string>::const_iterator found =
symbol_map.symbols.lower_bound(addr);
if (found == symbol_map.symbols.begin()) {
snprintf(dumped_stack_frame_buf_, 4095, "%s [%p(%lx)]",
symbol_map.filename.c_str(), (void*)addr, (long)file_offset);
return dumped_stack_frame_buf_;
}
--found;
const char* name = found->second.c_str();
uintptr_t func_offset = addr - found->first;
snprintf(dumped_stack_frame_buf_, 4095, "%s(%s+%lx) [%p(%lx)]",
symbol_map.filename.c_str(), name, (long)func_offset,
(void*)addr, (long)file_offset);
return dumped_stack_frame_buf_;
}
map<uintptr_t, SymbolMap*> maps_;
char dumped_stack_frame_buf_[4096];
};
static FileMap g_file_map;

View File

@ -1,5 +1,5 @@
#define _POSIX_C_SOURCE 200112L
#undef _GNU_SOURCE // for proper strerror_r
#include <string.h>
#include <errno.h>
#include <cstring>
#include <cstdio>
@ -15,6 +15,10 @@ static int linux_to_darwin[130];
extern "C" const char * const __darwin_sys_errlist[0];
extern "C" const int __darwin_sys_nerr = 0;
// For a non-gnu version of strerror_r
extern "C" int __xpg_strerror_r (int __errnum, char *__buf, size_t __buflen)
__THROW __nonnull ((2));
int cthread_errno()
{
return errno;
@ -58,7 +62,7 @@ char* __darwin_strerror(int errnum)
int __darwin_strerror_r(int errnum, char *strerrbuf, size_t buflen)
{
errnum = errnoDarwinToLinux(errnum);
return ::strerror_r(errnum, strerrbuf, buflen);
return ::__xpg_strerror_r(errnum, strerrbuf, buflen);
}
void __darwin_perror(const char *s)

153
src/libmach-o/BindState.cpp Normal file
View File

@ -0,0 +1,153 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#include "BindState.h"
#include "MachO.h"
#include "MachOImpl.h"
#include "log.h"
#include "leb.h"
#include <cstdio>
typedef long long ll;
typedef unsigned long long ull;
BindState::BindState(MachOImpl* mach0, bool is_weak0)
: mach(mach0), ordinal(0), sym_name(NULL), type(BIND_TYPE_POINTER),
addend(0), seg_index(0), seg_offset(0), is_weak(is_weak0)
{
}
void BindState::readBindOp(const uint8_t*& p)
{
uint8_t op = *p & BIND_OPCODE_MASK;
uint8_t imm = *p & BIND_IMMEDIATE_MASK;
p++;
LOGF("bind: op=%x imm=%d\n", op, imm);
switch (op)
{
case BIND_OPCODE_DONE:
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
ordinal = imm;
break;
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
ordinal = uleb128(p);
break;
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
if (imm == 0)
ordinal = 0;
else
ordinal = BIND_OPCODE_MASK | imm;
break;
case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
sym_name = reinterpret_cast<const char*>(p);
p += strlen(sym_name) + 1;
LOGF("sym_name=%s\n", sym_name);
break;
case BIND_OPCODE_SET_TYPE_IMM:
type = imm;
break;
case BIND_OPCODE_SET_ADDEND_SLEB:
addend = sleb128(p);
break;
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
seg_index = imm;
seg_offset = uleb128(p);
break;
case BIND_OPCODE_ADD_ADDR_ULEB:
seg_offset += uleb128(p);
break;
case BIND_OPCODE_DO_BIND:
addBind();
break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
LOGF("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB\n");
addBind();
seg_offset += uleb128(p);
break;
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
LOGF("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED %d\n", (int)imm);
addBind();
seg_offset += imm * mach->m_ptrsize;
break;
case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: {
uint64_t count = uleb128(p);
uint64_t skip = uleb128(p);
LOGF("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB %u %u\n",
(unsigned)count, (unsigned)skip);
for (uint64_t i = 0; i < count; i++)
{
addBind();
seg_offset += skip;
}
break;
}
default:
fprintf(stderr, "unknown op: %x\n", op);
}
}
void BindState::addBind()
{
MachO::Bind* bind = new MachO::Bind();
uint64_t vmaddr;
if (mach->m_is64)
vmaddr = mach->m_segments64[seg_index]->vmaddr;
else
vmaddr = mach->m_segments[seg_index]->vmaddr;
LOGF("add bind! %s seg_index=%d seg_offset=%llu "
"type=%d ordinal=%d addend=%lld vmaddr=%p is_weak=%d\n",
sym_name, seg_index, (ull)seg_offset,
type, ordinal, (ll)addend, (void*)(vmaddr + seg_offset), is_weak);
bind->name = sym_name;
bind->vmaddr = vmaddr + seg_offset;
bind->addend = addend;
bind->type = type;
bind->ordinal = ordinal;
bind->is_weak = is_weak;
mach->m_binds.push_back(bind);
seg_offset += mach->m_ptrsize;
}

53
src/libmach-o/BindState.h Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#ifndef BINDSTATE_H
#define BINDSTATE_H
#include "MachOImpl.h"
struct BindState
{
BindState(MachOImpl* mach0, bool is_weak0);
void readBindOp(const uint8_t*& p);
void addBind();
MachOImpl* mach;
uint8_t ordinal;
const char* sym_name;
uint8_t type;
int64_t addend;
int seg_index;
uint64_t seg_offset;
bool is_weak;
};
#endif

View File

@ -0,0 +1,25 @@
project(mach-o)
cmake_minimum_required(VERSION 2.4.0)
if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
set(mach-o_SRCS
MachO.cpp
FatMachO.cpp
RebaseState.cpp
BindState.cpp
leb.cpp
MachOImpl.cpp
)
add_library(mach-o SHARED ${mach-o_SRCS})
set_target_properties(mach-o PROPERTIES VERSION 1.0.0 SOVERSION 1.0)
target_link_libraries(mach-o -ldl -lpthread)
install(TARGETS mach-o DESTINATION lib)

View File

@ -37,6 +37,7 @@ namespace FatMachO
{
// Reads fd and fills fat info. Returns true if fd is a valid fat binary.
__attribute__ ((visibility ("default")))
bool readFatInfo(int fd, std::map<std::string, fat_arch>* fat);
}

68
src/libmach-o/MachO.cpp Normal file
View File

@ -0,0 +1,68 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#include "MachO.h"
#include "FatMachO.h"
#include "MachOImpl.h"
#include <cstdio>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <string>
#include <cstring>
#include <map>
MachO* MachO::readFile(std::string path, const char* arch, bool need_exports)
{
int fd = ::open(path.c_str(), O_RDONLY);
if (fd < 0)
{
std::cerr << path << ": " << strerror(errno) << std::endl;
return 0;
}
size_t offset = 0, len = 0;
std::map<std::string, fat_arch> archs;
if (FatMachO::readFatInfo(fd, &archs))
{
std::map<std::string, fat_arch>::const_iterator found = archs.find(arch);
if (found == archs.end())
{
std::cerr << path << " is a fat binary, but doesn't support the following architecture: " << arch << std::endl;
return 0;
}
offset = found->second.offset;
len = found->second.size;
// LOGF("fat offset=%lu, len=%lu\n", (unsigned long)offset, (unsigned long)len);
}
return new MachOImpl(path.c_str(), fd, offset, len, need_exports);
}

View File

@ -39,6 +39,7 @@
class MachO
{
public:
__attribute__ ((visibility ("default")))
static MachO* readFile(std::string path, const char* arch, bool need_exports = true);
virtual ~MachO() {}
@ -80,13 +81,9 @@ public:
uint64_t addr;
};
const std::vector<segment_command_64*>& segments64() const {
return m_segments64;
}
const std::vector<segment_command_64*>& segments64() const { return m_segments64; }
const std::vector<segment_command*>& segments() const {
return m_segments;
}
const std::vector<segment_command*>& segments() const { return m_segments; }
const std::vector<const char*>& dylibs() const { return m_dylibs; }

535
src/libmach-o/MachOImpl.cpp Normal file
View File

@ -0,0 +1,535 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#include "MachOImpl.h"
#include "log.h"
#include "RebaseState.h"
#include "BindState.h"
#include "leb.h"
#include <mach-o/loader.h>
#include <sys/mman.h>
#include <cstdio>
#define N_WEAK_DEF 0x0080
#define FLAGS_READ_SYMTAB 1
#define FLAGS_READ_DYSYMTAB 1
template <class section>
void MachOImpl::readClassicBind(const section& sec, uint32_t* dysyms, uint32_t* symtab, const char* symstrtab)
{
uint32_t indirect_offset = sec.reserved1;
int count = sec.size / m_ptrsize;
for (int i = 0; i < count; i++)
{
uint32_t dysym = dysyms[indirect_offset + i];
uint32_t index = dysym & 0x3fffffff;
nlist* sym = (nlist*)(symtab + index * (m_is64 ? 4 : 3));
MachO::Bind* bind = new MachO::Bind();
bind->name = symstrtab + sym->n_strx;
bind->vmaddr = sec.addr + i * m_ptrsize;
bind->value = sym->n_value;
bind->type = BIND_TYPE_POINTER;
bind->ordinal = 1;
bind->is_weak = ((sym->n_desc & N_WEAK_DEF) != 0);
bind->is_classic = true;
LOGF("add classic bind! %s type=%d sect=%d desc=%d value=%lld "
"vmaddr=%p is_weak=%d\n",
bind->name.c_str(), sym->n_type, sym->n_sect, sym->n_desc, (ll)sym->n_value,
(void*)(bind->vmaddr), bind->is_weak);
m_binds.push_back(bind);
}
}
template <class segment_command, class section>
void MachOImpl::readSegment(char* cmds_ptr, std::vector<segment_command*>* segments, std::vector<section*>* bind_sections)
{
segment_command* segment = reinterpret_cast<segment_command*>(cmds_ptr);
segments->push_back(segment);
LOGF("segment %s: vmaddr=%p vmsize=%llu "
"fileoff=%llu filesize=%llu "
"maxprot=%d initprot=%d nsects=%u flags=%u\n",
segment->segname,
(void*)(intptr_t)segment->vmaddr, (ull)segment->vmsize,
(ull)segment->fileoff, (ull)segment->filesize,
segment->maxprot, segment->initprot,
segment->nsects, segment->flags);
section* sections = reinterpret_cast<section*>(cmds_ptr + sizeof(segment_command));
for (uint32_t j = 0; j < segment->nsects; j++)
{
const section& sec = sections[j];
LOGF("section %s in %s: "
"addr=%p size=%llu offset=%u align=%u "
"reloff=%u nreloc=%u flags=%u "
"reserved1=%u reserved2=%u\n",
sec.sectname, sec.segname,
(void*)(intptr_t)sec.addr, (ull)sec.size,
sec.offset, sec.align,
sec.reloff, sec.nreloc, sec.flags,
sec.reserved1, sec.reserved2);
if (!strcmp(sec.sectname, "__dyld") && !strcmp(sec.segname, "__DATA"))
m_dyld_data = sec.addr;
int section_type = sec.flags & SECTION_TYPE;
switch (section_type)
{
case S_REGULAR:
/* Regular section: nothing to do */
break;
case S_MOD_INIT_FUNC_POINTERS:
{
for (uint64_t p = sec.addr; p < sec.addr + sec.size; p += m_ptrsize)
m_init_funcs.push_back(p);
break;
}
case S_MOD_TERM_FUNC_POINTERS:
for (uint64_t p = sec.addr; p < sec.addr + sec.size; p += m_ptrsize)
m_exit_funcs.push_back(p);
break;
case S_NON_LAZY_SYMBOL_POINTERS:
case S_LAZY_SYMBOL_POINTERS:
bind_sections->push_back(sections + j);
break;
case S_ZEROFILL:
case S_CSTRING_LITERALS:
case S_4BYTE_LITERALS:
case S_8BYTE_LITERALS:
case S_LITERAL_POINTERS:
case S_SYMBOL_STUBS:
case S_COALESCED:
case S_GB_ZEROFILL:
case S_INTERPOSING:
case S_16BYTE_LITERALS:
case S_DTRACE_DOF:
case S_LAZY_DYLIB_SYMBOL_POINTERS:
LOGF("FIXME: section type %d will not be handled for %s in %s\n",
section_type, sec.sectname, sec.segname);
break;
default:
fprintf(stderr, "Unknown section type: %d\n", section_type);
abort();
break;
}
}
}
void MachOImpl::readRebase(const uint8_t* p, const uint8_t* end)
{
RebaseState state(this);
while (p < end)
{
if (!state.readRebaseOp(p))
break;
}
}
void MachOImpl::readBind(const uint8_t* p, const uint8_t* end, bool is_weak)
{
BindState state(this, is_weak);
while (p < end)
{
state.readBindOp(p);
}
}
void MachOImpl::readExport(const uint8_t* start, const uint8_t* p, const uint8_t* end, std::string* name_buf)
{
LOGF("readExport: %p-%p\n", p, end);
#if 0
char buf[17];
buf[16] = '\0';
for (int i = 0; i < 16*8; i++) {
LOGF("%02x ", p[i]);
buf[i % 16] = p[i] < 32 ? '?' : p[i];
if (i % 16 == 15) LOGF("%s\n", buf);
}
#endif
if (p >= end)
{
fprintf(stderr, "broken export trie\n"); // TODO: throw an exception instead
exit(1);
}
if (uint8_t term_size = *p++)
{
const uint8_t* expected_term_end = p + term_size;
Export* exp = new Export;
exp->name = *name_buf;
exp->flag = uleb128(p);
exp->addr = uleb128(p);
LOGF("export: %s %lu %p\n",
name_buf->c_str(), (long)exp->flag, (void*)exp->addr);
m_exports.push_back(exp);
CHECK(expected_term_end == p);
}
const uint8_t num_children = *p++;
for (uint8_t i = 0; i < num_children; i++)
{
size_t orig_name_size = name_buf->size();
while (*p)
name_buf->push_back(*p++);
p++;
uint64_t off = uleb128(p);
CHECK(off != 0);
readExport(start, start + off, end, name_buf);
name_buf->resize(orig_name_size);
}
}
MachOImpl::MachOImpl(const char* filename, int fd, size_t offset, size_t len, bool need_exports)
: m_mapped(0), m_mapped_size(len)
{
m_filename = filename;
m_need_exports = need_exports;
m_dyld_data = 0;
CHECK(fd);
m_fd = fd;
m_offset = offset;
if (!m_mapped_size)
m_mapped_size = ::lseek(m_fd, 0, SEEK_END);
::lseek(fd, 0, SEEK_SET);
char* bin = m_mapped = reinterpret_cast<char*>(
::mmap(NULL, m_mapped_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, m_fd, offset)
);
m_base = bin;
mach_header* header = reinterpret_cast<mach_header*>(bin);
LOGF("magic=%x cpu=%d cpusub=%d file=%d ncmds=%d sizecmd=%d flags=%x\n",
header->magic, header->cputype, header->cpusubtype,
header->filetype, header->ncmds, header->sizeofcmds,
header->flags);
m_is64 = false;
if (header->magic == MH_MAGIC_64)
m_is64 = true;
else if (header->magic != MH_MAGIC)
{
fprintf(stderr, "Not mach-o: %s\n", filename);
exit(1); // TODO: throw instead
}
m_ptrsize = m_is64 ? 8 : 4;
if ((header->cputype & 0x00ffffff) != CPU_TYPE_X86)
{
fprintf(stderr, "Unsupported CPU\n");
exit(1); // TODO: throw instead
}
// TODO: split into a method
struct load_command* cmds_ptr = reinterpret_cast<struct load_command*>(
bin + (m_is64 ? sizeof(mach_header_64) : sizeof(mach_header))
);
uint32_t* symtab = 0;
uint32_t* dysyms = 0;
const char* symstrtab = 0;
dyld_info_command* dyinfo = 0;
std::vector<section_64*> bind_sections_64;
std::vector<section*> bind_sections_32;
for (uint32_t ii = 0; ii < header->ncmds; ii++)
{
LOGF("cmd type:%x\n", cmds_ptr->cmd);
switch (cmds_ptr->cmd)
{
case LC_SEGMENT_64:
readSegment<segment_command_64, section_64>((char*)cmds_ptr, &m_segments64, &bind_sections_64);
break;
case LC_SEGMENT:
readSegment<segment_command, section>((char*)cmds_ptr, &m_segments, &bind_sections_32);
break;
case LC_DYLD_INFO:
case LC_DYLD_INFO_ONLY:
{
dyinfo = reinterpret_cast<dyld_info_command*>(cmds_ptr);
LOGF("dyld info: rebase_off=%u rebase_size=%u "
"bind_off=%u bind_size=%u "
"weak_bind_off=%u weak_bind_size=%u "
"lazy_bind_off=%u lazy_bind_size=%u "
"export_off=%u export_size=%u\n",
dyinfo->rebase_off, dyinfo->rebase_size,
dyinfo->bind_off, dyinfo->bind_size,
dyinfo->weak_bind_off, dyinfo->weak_bind_size,
dyinfo->lazy_bind_off, dyinfo->lazy_bind_size,
dyinfo->export_off, dyinfo->export_size);
{
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->rebase_off);
const uint8_t* end = p + dyinfo->rebase_size;
if (dyinfo->rebase_off && dyinfo->rebase_size)
readRebase(p, end);
}
{
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->bind_off);
const uint8_t* end = p + dyinfo->bind_size;
readBind(p, end, false);
}
{
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->lazy_bind_off);
const uint8_t* end = p + dyinfo->lazy_bind_size;
readBind(p, end, false);
}
{
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->weak_bind_off);
const uint8_t* end = p + dyinfo->weak_bind_size;
readBind(p, end, true);
}
if (m_need_exports)
{
const uint8_t* p = reinterpret_cast<uint8_t*>(
bin + dyinfo->export_off);
const uint8_t* end = p + dyinfo->export_size;
if (dyinfo->export_off && dyinfo->export_size)
{
std::string buf;
readExport(p, p, end, &buf);
}
}
break;
}
case LC_SYMTAB:
{
symtab_command* symtab_cmd = reinterpret_cast<symtab_command*>(cmds_ptr);
LOGF("symoff=%u nsysm=%u stroff=%u strsize=%u\n",
symtab_cmd->symoff, symtab_cmd->nsyms,
symtab_cmd->stroff, symtab_cmd->strsize);
uint32_t* symtab_top = symtab = reinterpret_cast<uint32_t*>(bin + symtab_cmd->symoff);
symstrtab = bin + symtab_cmd->stroff;
if (FLAGS_READ_SYMTAB)
{
for (uint32_t i = 0; i < symtab_cmd->nsyms; i++)
{
Symbol sym;
nlist* nl = (nlist*)symtab;
sym.name = symstrtab + nl->n_strx;
if (m_is64)
{
sym.addr = nl->n_value;
symtab += 4;
}
else
{
sym.addr = (uint32_t)nl->n_value;
symtab += 3;
}
LOGF("%d %s(%d) %p\n",
i, sym.name.c_str(), nl->n_strx, (void*)sym.addr);
m_symbols.push_back(sym);
}
}
// Will be used by other load commands.
symtab = symtab_top;
break;
}
case LC_DYSYMTAB:
{
dysymtab_command* dysymtab_cmd = reinterpret_cast<dysymtab_command*>(cmds_ptr);
LOGF("dysym:\n"
" ilocalsym=%u nlocalsym=%u\n"
" iextdefsym=%u nextdefsym=%u\n"
" iundefsym=%u nundefsym=%u\n"
" tocoff=%u ntoc=%u\n"
" modtaboff=%u nmodtab=%u\n"
" extrefsymoff=%u nextrefsyms=%u\n"
" indirectsymoff=%u nindirectsyms=%u\n"
" extreloff=%u nextrel=%u\n"
" locreloff=%u nlocrel=%u\n"
,
dysymtab_cmd->ilocalsym, dysymtab_cmd->nlocalsym,
dysymtab_cmd->iextdefsym, dysymtab_cmd->nextdefsym,
dysymtab_cmd->iundefsym, dysymtab_cmd->nundefsym,
dysymtab_cmd->tocoff, dysymtab_cmd->ntoc,
dysymtab_cmd->modtaboff, dysymtab_cmd->nmodtab,
dysymtab_cmd->extrefsymoff, dysymtab_cmd->nextrefsyms,
dysymtab_cmd->indirectsymoff, dysymtab_cmd->nindirectsyms,
dysymtab_cmd->extreloff, dysymtab_cmd->nextrel,
dysymtab_cmd->locreloff, dysymtab_cmd->nlocrel);
if (dysymtab_cmd->nindirectsyms)
{
dysyms = reinterpret_cast<uint32_t*>(
bin + dysymtab_cmd->indirectsymoff);
}
if (FLAGS_READ_DYSYMTAB)
{
for (uint32_t j = 0; j < dysymtab_cmd->nindirectsyms; j++)
{
uint32_t dysym = dysyms[j];
uint32_t index = dysym & 0x3fffffff;
const char* local =
(dysym & INDIRECT_SYMBOL_LOCAL) ? " local" : "";
const char* abs =
(dysym & INDIRECT_SYMBOL_ABS) ? " abs" : "";
uint32_t* sym = symtab;
sym += index * (m_is64 ? 4 : 3);
LOGF("dysym %d %s(%u)%s%s\n", j, symstrtab + sym[0], index, local, abs);
}
uint32_t* dymods = reinterpret_cast<uint32_t*>( bin + dysymtab_cmd->modtaboff);
for (uint32_t j = 0; j < dysymtab_cmd->nmodtab; j++)
LOGF("dymods: %u\n", dymods[j]);
}
break;
}
case LC_LOAD_DYLINKER:
{
lc_str name = reinterpret_cast<struct dylinker_command*>(cmds_ptr)->name;
LOGF("dylinker: %s\n", (char*)cmds_ptr + name.offset);
break;
}
case LC_UUID:
break;
case LC_UNIXTHREAD:
{
uint32_t* p = reinterpret_cast<uint32_t*>(cmds_ptr);
LOGF("UNIXTHREAD");
for (uint32_t i = 2; i < p[1]; i++)
LOGF(" %d:%x", i, p[i]);
LOGF("\n");
if (m_is64)
m_entry = reinterpret_cast<uint64_t*>(cmds_ptr)[18];
else
m_entry = reinterpret_cast<uint32_t*>(cmds_ptr)[14];
LOGF("entry=%llx\n", (ull)m_entry);
break;
}
case LC_LOAD_DYLIB:
{
dylib* lib = &reinterpret_cast<dylib_command*>(cmds_ptr)->dylib;
LOGF("dylib: '%s'\n", (char*)cmds_ptr + lib->name.offset);
m_dylibs.push_back((char*)cmds_ptr + lib->name.offset);
break;
}
}
cmds_ptr = reinterpret_cast<load_command*>(
reinterpret_cast<char*>(cmds_ptr) + cmds_ptr->cmdsize);
}
LOGF("%p vs %p\n", cmds_ptr, bin + m_mapped_size);
// No LC_DYLD_INFO_ONLY, we will read classic binding info.
if (!dyinfo && dysyms && symtab && symstrtab)
{
for (size_t i = 0; i < bind_sections_64.size(); i++)
{
readClassicBind<section_64>(*bind_sections_64[i], dysyms, symtab, symstrtab);
}
for (size_t i = 0; i < bind_sections_32.size(); i++)
{
readClassicBind<section>(*bind_sections_32[i], dysyms, symtab, symstrtab);
}
}
}
MachOImpl::~MachOImpl()
{
close();
}
void MachOImpl::close()
{
for (size_t i = 0; i < m_binds.size(); i++)
delete m_binds[i];
m_binds.clear();
for (size_t i = 0; i < m_rebases.size(); i++)
delete m_rebases[i];
m_rebases.clear();
for (size_t i = 0; i < m_exports.size(); i++)
delete m_exports[i];
m_exports.clear();
if (m_mapped)
{
::munmap(m_mapped, m_mapped_size);
::close(m_fd);
m_mapped = 0;
m_fd = -1;
}
}

93
src/libmach-o/MachOImpl.h Normal file
View File

@ -0,0 +1,93 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#ifndef MACHOIMPL_H
#define MACHOIMPL_H
#include "MachO.h"
#include <mach-o/loader.h>
#include <stdint.h>
#include <vector>
#include <string>
class MachOImpl : public MachO
{
public:
// Takes ownership of fd.
// If len is 0, the size of file will be used as len.
MachOImpl(const char* filename, int fd, size_t offset, size_t len, bool need_exports);
virtual ~MachOImpl();
virtual void close();
typedef long long ll;
typedef unsigned long long ull;
private:
friend class RebaseState;
friend class BindState;
template <class segment_command, class section>
void readSegment(char* cmds_ptr, std::vector<segment_command*>* segments, std::vector<section*>* bind_sections);
void readRebase(const uint8_t* p, const uint8_t* end);
void readBind(const uint8_t* p, const uint8_t* end, bool is_weak);
void readExport(const uint8_t* start, const uint8_t* p, const uint8_t* end, std::string* name_buf);
template <class section>
void readClassicBind(const section& sec, uint32_t* dysyms, uint32_t* symtab, const char* symstrtab);
char* m_mapped;
size_t m_mapped_size;
bool m_need_exports;
struct sym
{
uint32_t name;
uint32_t addr;
uint32_t flag;
};
struct sym64
{
uint32_t name;
uint64_t addr;
uint32_t flag;
};
// See mach-o/nlist.h for this layout
struct nlist
{
uint32_t n_strx;
uint8_t n_type;
uint8_t n_sect;
uint16_t n_desc;
uint64_t n_value;
};
};
#endif

View File

@ -0,0 +1,123 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#include "RebaseState.h"
#include "leb.h"
#include "log.h"
#include "MachOImpl.h"
#include <cstdio>
typedef unsigned long long ull;
RebaseState::RebaseState(MachOImpl* mach0)
: mach(mach0), type(0), seg_index(0), seg_offset(0)
{
}
bool RebaseState::readRebaseOp(const uint8_t*& p)
{
uint8_t op = *p & REBASE_OPCODE_MASK;
uint8_t imm = *p & REBASE_IMMEDIATE_MASK;
p++;
switch (op)
{
case REBASE_OPCODE_DONE:
return false;
case REBASE_OPCODE_SET_TYPE_IMM:
type = imm;
break;
case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
seg_index = imm;
seg_offset = uleb128(p);
break;
case REBASE_OPCODE_ADD_ADDR_ULEB:
seg_offset += uleb128(p);
break;
case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
seg_offset += imm * mach->m_ptrsize;
break;
case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
for (int i = 0; i < imm; i++)
addRebase();
break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
{
int count = uleb128(p);
for (int i = 0; i < count; i++)
addRebase();
break;
}
case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
addRebase();
seg_offset += uleb128(p);
break;
case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
{
int count = uleb128(p);
uint64_t skip = uleb128(p);
for (int i = 0; i < count; i++)
{
addRebase();
seg_offset += skip;
}
break;
}
default:
fprintf(stderr, "unknown op: %x\n", op);
}
return true;
}
void RebaseState::addRebase()
{
MachO::Rebase* rebase = new MachO::Rebase();
uint64_t vmaddr;
if (mach->m_is64)
vmaddr = mach->m_segments64[seg_index]->vmaddr;
else
vmaddr = mach->m_segments[seg_index]->vmaddr;
LOGF("add rebase! seg_index=%d seg_offset=%llu type=%d vmaddr=%p\n",
seg_index, (ull)seg_offset, type, (void*)vmaddr);
rebase->vmaddr = vmaddr + seg_offset;
rebase->type = type;
mach->m_rebases.push_back(rebase);
seg_offset += mach->m_ptrsize;
}

View File

@ -0,0 +1,47 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#ifndef REBASESTATE_H
#define REBASESTATE_H
#include "MachOImpl.h"
#include <stdint.h>
struct RebaseState
{
explicit RebaseState(MachOImpl* mach0);
bool readRebaseOp(const uint8_t*& p);
void addRebase();
MachOImpl* mach;
uint8_t type;
int seg_index;
uint64_t seg_offset;
};
#endif

56
src/libmach-o/env_flags.h Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#ifndef ENV_FLAGS_H_
#define ENV_FLAGS_H_
#include <stdlib.h>
#include <string.h>
#define LD_MAC_EnvToBool(envname, dflt) \
(!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) != NULL)
#define LD_MAC_DECLARE_VARIABLE(type, name, tn) \
namespace FLAG__namespace_do_not_use_directly_use_LD_MAC_DECLARE_##tn##_instead { \
extern type FLAGS_##name; \
} \
using FLAG__namespace_do_not_use_directly_use_LD_MAC_DECLARE_##tn##_instead::FLAGS_##name
#define LD_MAC_DEFINE_VARIABLE(type, name, value, meaning, tn) \
namespace FLAG__namespace_do_not_use_directly_use_LD_MAC_DECLARE_##tn##_instead { \
type FLAGS_##name(value); \
} \
using FLAG__namespace_do_not_use_directly_use_LD_MAC_DECLARE_##tn##_instead::FLAGS_##name;
#define DECLARE_bool(name) \
LD_MAC_DECLARE_VARIABLE(bool, name, bool)
#define DEFINE_bool(name, value, meaning) \
LD_MAC_DEFINE_VARIABLE(bool, name, LD_MAC_EnvToBool("LD_MAC_" #name, value), \
meaning, bool)
#endif // ENV_FLAGS_H_

63
src/libmach-o/leb.cpp Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#include "leb.h"
#include <stdint.h>
uint64_t uleb128(const uint8_t*& p)
{
uint64_t r = 0;
int s = 0;
do
{
r |= (uint64_t)(*p & 0x7f) << s;
s += 7;
}
while (*p++ >= 0x80);
return r;
}
int64_t sleb128(const uint8_t*& p)
{
int64_t r = 0;
int s = 0;
for (;;) {
uint8_t b = *p++;
if (b < 0x80)
{
if (b & 0x40)
r -= (0x80 - b) << s;
else
r |= (b & 0x3f) << s;
break;
}
r |= (b & 0x7f) << s;
s += 7;
}
return r;
}

36
src/libmach-o/leb.h Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#ifndef LEB_H
#define LEB_H
#include <stdint.h>
uint64_t uleb128(const uint8_t*& p);
int64_t sleb128(const uint8_t*& p);
#endif

View File

@ -0,0 +1 @@
libmach-o.so.1.0.0

BIN
src/libmach-o/libmach-o.so.1.0.0 Executable file

Binary file not shown.

30
src/libmach-o/log.cc Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#include "env_flags.h"
DEFINE_bool(LOG, false, "Output bunch of logs");

54
src/libmach-o/log.h Normal file
View File

@ -0,0 +1,54 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. 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.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``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 Shinichiro Hamaji 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.
#ifndef LOG_H_
#define LOG_H_
#include <assert.h>
#include "env_flags.h"
DECLARE_bool(LOG);
#ifdef NOLOG
# define LOG if (0) cout
# define LOGF(...) if (0) fprintf(stderr, __VA_ARGS__)
#else
# define LOG if (FLAGS_LOG) cerr
# define LOGF(...) if (FLAGS_LOG) fprintf(stderr, __VA_ARGS__)
#endif
#define ERR cerr
#ifdef NDEBUG
// Do an extra check to avoid warning around unused local variables.
# define CHECK(r) do { if (!(r)) assert(r); } while (0)
#else
# define CHECK(r) assert(r);
#endif
#endif