mirror of
https://github.com/darlinghq/darling.git
synced 2024-11-23 12:19:43 +00:00
Split out libmach-o
This commit is contained in:
parent
5c904a0754
commit
cc423dd3a7
5
.gitignore
vendored
5
.gitignore
vendored
@ -21,4 +21,9 @@ Thumbs.db
|
||||
|
||||
.kdev_include_paths
|
||||
*~
|
||||
Makefile
|
||||
CMakeFiles
|
||||
cmake_install.cmake
|
||||
CMakeCache.txt
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
840
dyld/mach-o.cc
840
dyld/mach-o.cc
@ -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);
|
||||
}
|
129
dyld/mach-o.h
129
dyld/mach-o.h
@ -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_
|
@ -1 +0,0 @@
|
||||
/home/lubos/Projects/darling/libmac/xnu
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
@ -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
97
src/dyld/FileMap.cpp
Normal 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
59
src/dyld/FileMap.h
Normal 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
|
@ -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;
|
||||
|
@ -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
153
src/libmach-o/BindState.cpp
Normal 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
53
src/libmach-o/BindState.h
Normal 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
|
||||
|
25
src/libmach-o/CMakeLists.txt
Normal file
25
src/libmach-o/CMakeLists.txt
Normal 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)
|
@ -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
68
src/libmach-o/MachO.cpp
Normal 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);
|
||||
}
|
@ -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
535
src/libmach-o/MachOImpl.cpp
Normal 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
93
src/libmach-o/MachOImpl.h
Normal 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
|
123
src/libmach-o/RebaseState.cpp
Normal file
123
src/libmach-o/RebaseState.cpp
Normal 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;
|
||||
}
|
||||
|
47
src/libmach-o/RebaseState.h
Normal file
47
src/libmach-o/RebaseState.h
Normal 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
56
src/libmach-o/env_flags.h
Normal 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
63
src/libmach-o/leb.cpp
Normal 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
36
src/libmach-o/leb.h
Normal 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
|
1
src/libmach-o/libmach-o.so.1.0
Symbolic link
1
src/libmach-o/libmach-o.so.1.0
Symbolic link
@ -0,0 +1 @@
|
||||
libmach-o.so.1.0.0
|
BIN
src/libmach-o/libmach-o.so.1.0.0
Executable file
BIN
src/libmach-o/libmach-o.so.1.0.0
Executable file
Binary file not shown.
30
src/libmach-o/log.cc
Normal file
30
src/libmach-o/log.cc
Normal 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
54
src/libmach-o/log.h
Normal 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
|
Loading…
Reference in New Issue
Block a user