From: Matt Mullins Date: Mon, 26 May 2014 02:04:51 +0000 (-0700) Subject: Use the LLVM disassembler to advance %rip. X-Git-Url: http://git.mmlx.us/?a=commitdiff_plain;h=2cdbc1fa72f23617d4efb09055f9f70f866c89ff;p=fuckit_dot_so.git Use the LLVM disassembler to advance %rip. This contains logic to only permit the LLVM disassembler to read the page containing the faulting address, so this cannot handle instructions that span two pages. The effect of doing so would likely be ++%rip, but that has not been tested yet. --- diff --git a/fuckit.cpp b/fuckit.cpp index 5042857..c726297 100644 --- a/fuckit.cpp +++ b/fuckit.cpp @@ -3,26 +3,64 @@ #include #include +#include +#include +#include +#include +#include +#include #include #include static const llvm::Target* target; static const llvm::MCDisassembler* disassembler; +static size_t page_size; +static size_t page_mask; static void handle_sigsegv(int signal, siginfo_t *info, void *_context) { (void)(signal); // it's unused, stfu gcc struct ucontext *context = (struct ucontext *) _context; + char* addr = (char*)context->uc_mcontext.gregs[REG_RIP]; + fprintf(stderr, "Caught SIGSEGV for address %p\n", info->si_addr); - fprintf(stderr, "Code address: %p\n", (void*)context->uc_mcontext.gregs[REG_RIP]); + fprintf(stderr, "Code address: %p\n", addr); + + /* Use only the page containing the faulty instruction, or + * else we might ourselves access invalid memory. + */ + char *page_base = (char*)((long)addr & ~page_mask); + int page_offset = addr - page_base; + llvm::StringRef sr_data(page_base, page_size); + llvm::StringRefMemoryObject data(sr_data); + + llvm::MCInst inst; + uint64_t inst_len; - context->uc_mcontext.gregs[REG_RIP]++; + switch (disassembler->getInstruction( + inst /* reference */, inst_len /* reference */, + data /* const reference */, page_offset, + llvm::nulls(), llvm::nulls())) + { + case llvm::MCDisassembler::Success: + fprintf(stderr, "Code was %lu bytes\n", inst_len); + break; + case llvm::MCDisassembler::Fail: + case llvm::MCDisassembler::SoftFail: + inst_len = 1; + break; + } + + context->uc_mcontext.gregs[REG_RIP] += inst_len; } __attribute__((constructor)) static void setup_signals() { + page_size = sysconf(_SC_PAGESIZE); + page_mask = page_size - 1; + fprintf(stderr, "Set up LLVM\n"); llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs();