From 2cdbc1fa72f23617d4efb09055f9f70f866c89ff Mon Sep 17 00:00:00 2001 From: Matt Mullins Date: Sun, 25 May 2014 19:04:51 -0700 Subject: [PATCH] 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. --- fuckit.cpp | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) 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(); -- 2.11.0