#include <unistd.h>
#include <ucontext.h>
+#include <llvm/ADT/StringRef.h>
+#include <llvm/MC/MCDisassembler.h>
+#include <llvm/MC/MCInst.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/MemoryObject.h>
+#include <llvm/Support/StringRefMemoryObject.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Support/TargetSelect.h>
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();