Add pre/post cpu_run hooks + Refactoring (#82)
* Add cpu_run pre/post exec hooks, to hook the cpu just before / after it runs target code. * Refactor hooks to separate them in different files * Remove most extern variables * Reduce the amount of extra code in QEMU * Add clang-format script
This commit is contained in:
parent
11b27cc216
commit
86d38fbfa7
@ -52,6 +52,12 @@
|
|||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "sysemu/stats.h"
|
#include "sysemu/stats.h"
|
||||||
|
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
|
#include "libafl/hooks/cpu_run.h"
|
||||||
|
|
||||||
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
/* This check must be after config-host.h is included */
|
/* This check must be after config-host.h is included */
|
||||||
#ifdef CONFIG_EVENTFD
|
#ifdef CONFIG_EVENTFD
|
||||||
#include <sys/eventfd.h>
|
#include <sys/eventfd.h>
|
||||||
@ -2866,10 +2872,22 @@ int kvm_cpu_exec(CPUState *cpu)
|
|||||||
*/
|
*/
|
||||||
smp_rmb();
|
smp_rmb();
|
||||||
|
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
|
libafl_hook_cpu_run_pre_exec(cpu);
|
||||||
|
|
||||||
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);
|
run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);
|
||||||
|
|
||||||
attrs = kvm_arch_post_run(cpu, run);
|
attrs = kvm_arch_post_run(cpu, run);
|
||||||
|
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
|
libafl_hook_cpu_run_post_exec(cpu);
|
||||||
|
|
||||||
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
#ifdef KVM_HAVE_MCE_INJECTION
|
#ifdef KVM_HAVE_MCE_INJECTION
|
||||||
if (unlikely(have_sigbus_pending)) {
|
if (unlikely(have_sigbus_pending)) {
|
||||||
bql_lock();
|
bql_lock();
|
||||||
|
@ -68,7 +68,8 @@
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
#include "libafl/hook.h"
|
#include "libafl/hooks/tcg/block.h"
|
||||||
|
#include "libafl/hooks/tcg/edge.h"
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
@ -284,24 +285,7 @@ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb,
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
struct libafl_block_hook* hook = libafl_block_hooks;
|
libafl_qemu_hook_block_run(pc);
|
||||||
while (hook) {
|
|
||||||
uint64_t cur_id = 0;
|
|
||||||
if (hook->gen)
|
|
||||||
cur_id = hook->gen(hook->data, pc);
|
|
||||||
if (cur_id != (uint64_t)-1 && hook->helper_info.func) {
|
|
||||||
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
|
||||||
TCGv_i64 tmp1 = tcg_constant_i64(cur_id);
|
|
||||||
TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1) };
|
|
||||||
tcg_gen_callN(&hook->helper_info, NULL, tmp2);
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
tcg_temp_free_i64(tmp1);
|
|
||||||
}
|
|
||||||
if (cur_id != (uint64_t)-1 && hook->jit) {
|
|
||||||
hook->jit(hook->data, cur_id);
|
|
||||||
}
|
|
||||||
hook = hook->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
@ -361,21 +345,9 @@ static int libafl_setjmp_gen_code(CPUArchState *env, TranslationBlock *tb,
|
|||||||
#error Unhandled TARGET_INSN_START_EXTRA_WORDS value
|
#error Unhandled TARGET_INSN_START_EXTRA_WORDS value
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct libafl_edge_hook* hook = libafl_edge_hooks;
|
// run edge hooks
|
||||||
while (hook) {
|
libafl_qemu_hook_edge_run();
|
||||||
if (hook->cur_id != (uint64_t)-1 && hook->helper_info.func) {
|
|
||||||
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
|
||||||
TCGv_i64 tmp1 = tcg_constant_i64(hook->cur_id);
|
|
||||||
TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1) };
|
|
||||||
tcg_gen_callN(&hook->helper_info, NULL, tmp2);
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
tcg_temp_free_i64(tmp1);
|
|
||||||
}
|
|
||||||
if (hook->cur_id != (uint64_t)-1 && hook->jit) {
|
|
||||||
hook->jit(hook->data, hook->cur_id);
|
|
||||||
}
|
|
||||||
hook = hook->next;
|
|
||||||
}
|
|
||||||
tcg_gen_goto_tb(0);
|
tcg_gen_goto_tb(0);
|
||||||
tcg_gen_exit_tb(tb, 0);
|
tcg_gen_exit_tb(tb, 0);
|
||||||
|
|
||||||
@ -430,16 +402,7 @@ TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
|
|||||||
QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS);
|
QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS);
|
||||||
|
|
||||||
// edge hooks generation callbacks
|
// edge hooks generation callbacks
|
||||||
struct libafl_edge_hook* hook = libafl_edge_hooks;
|
bool no_exec_hook = libafl_qemu_hook_edge_gen(src_block, dst_block);
|
||||||
int no_exec_hook = 1;
|
|
||||||
while (hook) {
|
|
||||||
hook->cur_id = 0;
|
|
||||||
if (hook->gen)
|
|
||||||
hook->cur_id = hook->gen(hook->data, src_block, dst_block);
|
|
||||||
if (hook->cur_id != (uint64_t)-1 && (hook->helper_info.func || hook->jit))
|
|
||||||
no_exec_hook = 0;
|
|
||||||
hook = hook->next;
|
|
||||||
}
|
|
||||||
if (no_exec_hook)
|
if (no_exec_hook)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -749,13 +712,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||||||
tb->tc.size = gen_code_size;
|
tb->tc.size = gen_code_size;
|
||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
struct libafl_block_hook *hook = libafl_block_hooks;
|
|
||||||
while (hook)
|
libafl_qemu_hook_block_post_gen(tb, pc);
|
||||||
{
|
|
||||||
if (hook->post_gen)
|
|
||||||
hook->post_gen(hook->data, pc, tb->size);
|
|
||||||
hook = hook->next;
|
|
||||||
}
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -104,6 +104,9 @@ static void gen_tb_end(const TranslationBlock *tb, uint32_t cflags,
|
|||||||
#include "libafl/exit.h"
|
#include "libafl/exit.h"
|
||||||
#include "libafl/hook.h"
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
#include "libafl/hooks/tcg/instruction.h"
|
||||||
|
#include "libafl/hooks/tcg/backdoor.h"
|
||||||
|
|
||||||
#ifndef TARGET_LONG_BITS
|
#ifndef TARGET_LONG_BITS
|
||||||
#error "TARGET_LONG_BITS not defined"
|
#error "TARGET_LONG_BITS not defined"
|
||||||
#endif
|
#endif
|
||||||
@ -168,37 +171,10 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
struct libafl_hook* hk = libafl_search_instruction_hook(db->pc_next);
|
libafl_qemu_hook_instruction_run(db->pc_next);
|
||||||
if (hk) {
|
|
||||||
TCGv_i64 tmp0 = tcg_constant_i64(hk->data);
|
|
||||||
#if TARGET_LONG_BITS == 32
|
|
||||||
TCGv_i32 tmp1 = tcg_constant_i32(db->pc_next);
|
|
||||||
TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i32_temp(tmp1) };
|
|
||||||
#else
|
|
||||||
TCGv_i64 tmp1 = tcg_constant_i64(db->pc_next);
|
|
||||||
TCGTemp *tmp2[2] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1) };
|
|
||||||
#endif
|
|
||||||
// tcg_gen_callN(hk->callback, NULL, 2, tmp2);
|
|
||||||
tcg_gen_callN(&hk->helper_info, NULL, tmp2);
|
|
||||||
#if TARGET_LONG_BITS == 32
|
|
||||||
tcg_temp_free_i32(tmp1);
|
|
||||||
#else
|
|
||||||
tcg_temp_free_i64(tmp1);
|
|
||||||
#endif
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_breakpoint* bp = libafl_qemu_breakpoints;
|
|
||||||
while (bp) {
|
|
||||||
if (bp->addr == db->pc_next) {
|
|
||||||
TCGv_i64 tmp0 = tcg_constant_i64((uint64_t)db->pc_next);
|
|
||||||
gen_helper_libafl_qemu_handle_breakpoint(tcg_env, tmp0);
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
}
|
|
||||||
bp = bp->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
libafl_gen_cur_pc = db->pc_next;
|
libafl_gen_cur_pc = db->pc_next;
|
||||||
|
libafl_qemu_breakpoint_run(libafl_gen_cur_pc);
|
||||||
|
|
||||||
// 0x0f, 0x3a, 0xf2, 0x44
|
// 0x0f, 0x3a, 0xf2, 0x44
|
||||||
uint8_t backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next);
|
uint8_t backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next);
|
||||||
@ -209,16 +185,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
|||||||
if (backdoor == 0xf2) {
|
if (backdoor == 0xf2) {
|
||||||
backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next +3);
|
backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next +3);
|
||||||
if (backdoor == 0x44) {
|
if (backdoor == 0x44) {
|
||||||
struct libafl_backdoor_hook* bhk = libafl_backdoor_hooks;
|
libafl_qemu_hook_backdoor_run(db->pc_next);
|
||||||
while (bhk) {
|
|
||||||
TCGv_i64 tmp0 = tcg_constant_i64(bhk->data);
|
|
||||||
TCGv tmp2 = tcg_constant_tl(db->pc_next);
|
|
||||||
TCGTemp *args[3] = { tcgv_i64_temp(tmp0), tcgv_ptr_temp(tcg_env), tcgv_tl_temp(tmp2) };
|
|
||||||
|
|
||||||
tcg_gen_callN(&bhk->helper_info, NULL, args);
|
|
||||||
|
|
||||||
bhk = bhk->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
db->pc_next += 4;
|
db->pc_next += 4;
|
||||||
goto post_translate_insn;
|
goto post_translate_insn;
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "exec/cpu-defs.h"
|
#include "exec/cpu-defs.h"
|
||||||
|
#include "exec/translator.h"
|
||||||
|
|
||||||
#define EXCP_LIBAFL_EXIT 0xf4775747
|
#define EXCP_LIBAFL_EXIT 0xf4775747
|
||||||
|
|
||||||
@ -10,14 +12,13 @@ struct libafl_breakpoint {
|
|||||||
struct libafl_breakpoint* next;
|
struct libafl_breakpoint* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct libafl_breakpoint* libafl_qemu_breakpoints;
|
|
||||||
|
|
||||||
// in cpu-target.c
|
// in cpu-target.c
|
||||||
void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc);
|
void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc);
|
||||||
|
|
||||||
int libafl_qemu_set_breakpoint(target_ulong pc);
|
int libafl_qemu_set_breakpoint(target_ulong pc);
|
||||||
int libafl_qemu_remove_breakpoint(target_ulong pc);
|
int libafl_qemu_remove_breakpoint(target_ulong pc);
|
||||||
void libafl_qemu_trigger_breakpoint(CPUState* cpu);
|
void libafl_qemu_trigger_breakpoint(CPUState* cpu);
|
||||||
|
void libafl_qemu_breakpoint_run(vaddr pc_next);
|
||||||
|
|
||||||
enum libafl_exit_reason_kind {
|
enum libafl_exit_reason_kind {
|
||||||
INTERNAL = 0,
|
INTERNAL = 0,
|
||||||
@ -31,7 +32,8 @@ struct libafl_exit_reason_breakpoint {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// A synchronous exit has been triggered.
|
// A synchronous exit has been triggered.
|
||||||
struct libafl_exit_reason_sync_exit { };
|
struct libafl_exit_reason_sync_exit {
|
||||||
|
};
|
||||||
|
|
||||||
// QEMU exited on its own for some reason.
|
// QEMU exited on its own for some reason.
|
||||||
struct libafl_exit_reason_internal {
|
struct libafl_exit_reason_internal {
|
||||||
@ -58,7 +60,8 @@ void libafl_exit_signal_vm_start(void);
|
|||||||
bool libafl_exit_asap(void);
|
bool libafl_exit_asap(void);
|
||||||
void libafl_sync_exit_cpu(void);
|
void libafl_sync_exit_cpu(void);
|
||||||
|
|
||||||
void libafl_exit_request_internal(CPUState* cpu, uint64_t pc, ShutdownCause cause, int signal);
|
void libafl_exit_request_internal(CPUState* cpu, uint64_t pc,
|
||||||
|
ShutdownCause cause, int signal);
|
||||||
void libafl_exit_request_sync_backdoor(CPUState* cpu, target_ulong pc);
|
void libafl_exit_request_sync_backdoor(CPUState* cpu, target_ulong pc);
|
||||||
void libafl_exit_request_breakpoint(CPUState* cpu, target_ulong pc);
|
void libafl_exit_request_breakpoint(CPUState* cpu, target_ulong pc);
|
||||||
struct libafl_exit_reason* libafl_get_exit_reason(void);
|
struct libafl_exit_reason* libafl_get_exit_reason(void);
|
||||||
|
@ -7,221 +7,55 @@
|
|||||||
#include "tcg/tcg-internal.h"
|
#include "tcg/tcg-internal.h"
|
||||||
#include "tcg/tcg-temp-internal.h"
|
#include "tcg/tcg-temp-internal.h"
|
||||||
|
|
||||||
#define LIBAFL_TABLES_SIZE 16384
|
|
||||||
#define LIBAFL_TABLES_HASH(p) (((13*((size_t)(p))) ^ (((size_t)(p)) >> 15)) % LIBAFL_TABLES_SIZE)
|
|
||||||
#define LIBAFL_MAX_INSNS 16
|
#define LIBAFL_MAX_INSNS 16
|
||||||
|
|
||||||
|
#define GEN_REMOVE_HOOK(name) \
|
||||||
|
int libafl_qemu_remove_##name##_hook(size_t num, int invalidate) \
|
||||||
|
{ \
|
||||||
|
CPUState* cpu; \
|
||||||
|
struct libafl_##name##_hook** hk = &libafl_##name##_hooks; \
|
||||||
|
\
|
||||||
|
while (*hk) { \
|
||||||
|
if ((*hk)->num == num) { \
|
||||||
|
if (invalidate) { \
|
||||||
|
CPU_FOREACH(cpu) { tb_flush(cpu); } \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void* tmp = *hk; \
|
||||||
|
*hk = (*hk)->next; \
|
||||||
|
free(tmp); \
|
||||||
|
return 1; \
|
||||||
|
} else { \
|
||||||
|
hk = &(*hk)->next; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GEN_REMOVE_HOOK1(name) \
|
||||||
|
int libafl_qemu_remove_##name##_hook(size_t num) \
|
||||||
|
{ \
|
||||||
|
struct libafl_##name##_hook** hk = &libafl_##name##_hooks; \
|
||||||
|
\
|
||||||
|
while (*hk) { \
|
||||||
|
if ((*hk)->num == num) { \
|
||||||
|
void* tmp = *hk; \
|
||||||
|
*hk = (*hk)->next; \
|
||||||
|
free(tmp); \
|
||||||
|
return 1; \
|
||||||
|
} else { \
|
||||||
|
hk = &(*hk)->next; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: cleanup this
|
||||||
|
extern target_ulong libafl_gen_cur_pc;
|
||||||
|
extern size_t libafl_qemu_hooks_num;
|
||||||
|
|
||||||
void tcg_gen_callN(TCGHelperInfo* info, TCGTemp* ret, TCGTemp** args);
|
void tcg_gen_callN(TCGHelperInfo* info, TCGTemp* ret, TCGTemp** args);
|
||||||
|
|
||||||
TranslationBlock *libafl_gen_edge(CPUState *cpu, target_ulong src_block,
|
|
||||||
target_ulong dst_block, int exit_n,
|
|
||||||
target_ulong cs_base, uint32_t flags,
|
|
||||||
int cflags);
|
|
||||||
|
|
||||||
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot);
|
|
||||||
void libafl_gen_backdoor(target_ulong pc);
|
|
||||||
|
|
||||||
extern target_ulong libafl_gen_cur_pc;
|
|
||||||
|
|
||||||
struct libafl_hook {
|
|
||||||
target_ulong addr;
|
|
||||||
// void (*callback)(uint64_t, target_ulong);
|
|
||||||
uint64_t data;
|
|
||||||
size_t num;
|
|
||||||
TCGHelperInfo helper_info;
|
|
||||||
struct libafl_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct libafl_hook* libafl_qemu_instruction_hooks[LIBAFL_TABLES_SIZE];
|
|
||||||
extern size_t libafl_qemu_hooks_num;
|
|
||||||
|
|
||||||
size_t libafl_qemu_add_instruction_hooks(target_ulong pc, void (*callback)(uint64_t data, target_ulong pc),
|
|
||||||
uint64_t data, int invalidate);
|
|
||||||
size_t libafl_qemu_remove_instruction_hooks_at(target_ulong addr, int invalidate);
|
|
||||||
int libafl_qemu_remove_instruction_hook(size_t num, int invalidate);
|
|
||||||
struct libafl_hook* libafl_search_instruction_hook(target_ulong addr);
|
|
||||||
|
|
||||||
struct libafl_backdoor_hook {
|
|
||||||
void (*exec)(uint64_t data, CPUArchState* cpu, target_ulong pc);
|
|
||||||
uint64_t data;
|
|
||||||
size_t num;
|
|
||||||
TCGHelperInfo helper_info;
|
|
||||||
struct libafl_backdoor_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct libafl_backdoor_hook* libafl_backdoor_hooks;
|
|
||||||
|
|
||||||
size_t libafl_add_backdoor_hook(void (*exec)(uint64_t data, CPUArchState* cpu, target_ulong pc),
|
|
||||||
uint64_t data);
|
|
||||||
int libafl_qemu_remove_backdoor_hook(size_t num, int invalidate);
|
|
||||||
|
|
||||||
struct libafl_edge_hook {
|
|
||||||
uint64_t (*gen)(uint64_t data, target_ulong src, target_ulong dst);
|
|
||||||
// void (*exec)(uint64_t data, uint64_t id);
|
|
||||||
size_t (*jit)(uint64_t data, uint64_t id); // optional opt
|
|
||||||
uint64_t data;
|
|
||||||
size_t num;
|
|
||||||
uint64_t cur_id;
|
|
||||||
TCGHelperInfo helper_info;
|
|
||||||
struct libafl_edge_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct libafl_edge_hook* libafl_edge_hooks;
|
|
||||||
|
|
||||||
size_t libafl_add_edge_hook(uint64_t (*gen)(uint64_t data, target_ulong src, target_ulong dst),
|
|
||||||
void (*exec)(uint64_t data, uint64_t id),
|
|
||||||
uint64_t data);
|
|
||||||
int libafl_qemu_remove_edge_hook(size_t num, int invalidate);
|
|
||||||
bool libafl_qemu_edge_hook_set_jit(size_t num, size_t (*jit)(uint64_t, uint64_t)); // no param names to avoid to be marked as safe
|
|
||||||
|
|
||||||
struct libafl_block_hook {
|
|
||||||
uint64_t (*gen)(uint64_t data, target_ulong pc);
|
|
||||||
void (*post_gen)(uint64_t data, target_ulong pc, target_ulong block_length);
|
|
||||||
// void (*exec)(uint64_t data, uint64_t id);
|
|
||||||
size_t (*jit)(uint64_t data, uint64_t id); // optional opt
|
|
||||||
uint64_t data;
|
|
||||||
size_t num;
|
|
||||||
TCGHelperInfo helper_info;
|
|
||||||
struct libafl_block_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct libafl_block_hook* libafl_block_hooks;
|
|
||||||
|
|
||||||
size_t libafl_add_block_hook(uint64_t (*gen)(uint64_t data, target_ulong pc),
|
|
||||||
void (*post_gen)(uint64_t data, target_ulong pc, target_ulong block_length),
|
|
||||||
void (*exec)(uint64_t data, uint64_t id), uint64_t data);
|
|
||||||
int libafl_qemu_remove_block_hook(size_t num, int invalidate);
|
|
||||||
bool libafl_qemu_block_hook_set_jit(size_t num, size_t (*jit)(uint64_t, uint64_t)); // no param names to avoid to be marked as safe
|
|
||||||
|
|
||||||
struct libafl_rw_hook {
|
|
||||||
uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi);
|
|
||||||
/*void (*exec1)(uint64_t data, uint64_t id, target_ulong addr);
|
|
||||||
void (*exec2)(uint64_t data, uint64_t id, target_ulong addr);
|
|
||||||
void (*exec4)(uint64_t data, uint64_t id, target_ulong addr);
|
|
||||||
void (*exec8)(uint64_t data, uint64_t id, target_ulong addr);
|
|
||||||
void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size);*/
|
|
||||||
uint64_t data;
|
|
||||||
size_t num;
|
|
||||||
TCGHelperInfo helper_info1;
|
|
||||||
TCGHelperInfo helper_info2;
|
|
||||||
TCGHelperInfo helper_info4;
|
|
||||||
TCGHelperInfo helper_info8;
|
|
||||||
TCGHelperInfo helper_infoN;
|
|
||||||
struct libafl_rw_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
// alias
|
|
||||||
#define libafl_read_hook libafl_rw_hook
|
|
||||||
#define libafl_write_hook libafl_rw_hook
|
|
||||||
|
|
||||||
extern struct libafl_rw_hook* libafl_read_hooks;
|
|
||||||
extern struct libafl_rw_hook* libafl_write_hooks;
|
|
||||||
|
|
||||||
size_t libafl_add_read_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp *addr, MemOpIdx oi),
|
|
||||||
void (*exec1)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec2)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec4)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec8)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size),
|
|
||||||
uint64_t data);
|
|
||||||
size_t libafl_add_write_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp *addr, MemOpIdx oi),
|
|
||||||
void (*exec1)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec2)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec4)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec8)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size),
|
|
||||||
uint64_t data);
|
|
||||||
|
|
||||||
int libafl_qemu_remove_read_hook(size_t num, int invalidate);
|
|
||||||
int libafl_qemu_remove_write_hook(size_t num, int invalidate);
|
|
||||||
|
|
||||||
void libafl_gen_read(TCGTemp *addr, MemOpIdx oi);
|
|
||||||
void libafl_gen_write(TCGTemp *addr, MemOpIdx oi);
|
|
||||||
|
|
||||||
struct libafl_cmp_hook {
|
|
||||||
uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size);
|
|
||||||
/*void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1);
|
|
||||||
void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1);
|
|
||||||
void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1);
|
|
||||||
void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1);*/
|
|
||||||
uint64_t data;
|
|
||||||
size_t num;
|
|
||||||
TCGHelperInfo helper_info1;
|
|
||||||
TCGHelperInfo helper_info2;
|
|
||||||
TCGHelperInfo helper_info4;
|
|
||||||
TCGHelperInfo helper_info8;
|
|
||||||
struct libafl_cmp_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct libafl_cmp_hook* libafl_cmp_hooks;
|
|
||||||
|
|
||||||
size_t libafl_add_cmp_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size),
|
|
||||||
void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1),
|
|
||||||
void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1),
|
|
||||||
void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1),
|
|
||||||
void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1),
|
|
||||||
uint64_t data);
|
|
||||||
int libafl_qemu_remove_cmp_hook(size_t num, int invalidate);
|
|
||||||
|
|
||||||
struct syshook_ret {
|
|
||||||
target_ulong retval;
|
|
||||||
bool skip_syscall;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct libafl_pre_syscall_hook {
|
|
||||||
struct syshook_ret (*callback)(uint64_t data, int sys_num, target_ulong arg0,
|
|
||||||
target_ulong arg1, target_ulong arg2,
|
|
||||||
target_ulong arg3, target_ulong arg4,
|
|
||||||
target_ulong arg5, target_ulong arg6,
|
|
||||||
target_ulong arg7);
|
|
||||||
uint64_t data;
|
|
||||||
size_t num;
|
|
||||||
struct libafl_pre_syscall_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct libafl_post_syscall_hook {
|
|
||||||
target_ulong (*callback)(uint64_t data, target_ulong ret, int sys_num,
|
|
||||||
target_ulong arg0, target_ulong arg1,
|
|
||||||
target_ulong arg2, target_ulong arg3,
|
|
||||||
target_ulong arg4, target_ulong arg5,
|
|
||||||
target_ulong arg6, target_ulong arg7);
|
|
||||||
uint64_t data;
|
|
||||||
size_t num;
|
|
||||||
struct libafl_post_syscall_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct libafl_pre_syscall_hook* libafl_pre_syscall_hooks;
|
|
||||||
extern struct libafl_post_syscall_hook* libafl_post_syscall_hooks;
|
|
||||||
|
|
||||||
size_t libafl_add_pre_syscall_hook(struct syshook_ret (*callback)(
|
|
||||||
uint64_t data, int sys_num, target_ulong arg0,
|
|
||||||
target_ulong arg1, target_ulong arg2,
|
|
||||||
target_ulong arg3, target_ulong arg4,
|
|
||||||
target_ulong arg5, target_ulong arg6,
|
|
||||||
target_ulong arg7),
|
|
||||||
uint64_t data);
|
|
||||||
size_t libafl_add_post_syscall_hook(target_ulong (*callback)(
|
|
||||||
uint64_t data, target_ulong ret, int sys_num,
|
|
||||||
target_ulong arg0, target_ulong arg1,
|
|
||||||
target_ulong arg2, target_ulong arg3,
|
|
||||||
target_ulong arg4, target_ulong arg5,
|
|
||||||
target_ulong arg6, target_ulong arg7),
|
|
||||||
uint64_t data);
|
|
||||||
|
|
||||||
int libafl_qemu_remove_pre_syscall_hook(size_t num);
|
|
||||||
int libafl_qemu_remove_post_syscall_hook(size_t num);
|
|
||||||
|
|
||||||
struct libafl_new_thread_hook {
|
|
||||||
bool (*callback)(uint64_t data, uint32_t tid);
|
|
||||||
uint64_t data;
|
|
||||||
size_t num;
|
|
||||||
struct libafl_new_thread_hook* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct libafl_new_thread_hook* libafl_new_thread_hooks;
|
|
||||||
|
|
||||||
size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data, uint32_t tid),
|
|
||||||
uint64_t data);
|
|
||||||
int libafl_qemu_remove_new_thread_hook(size_t num);
|
|
||||||
|
|
||||||
void libafl_tcg_gen_asan(TCGTemp* addr, size_t size);
|
void libafl_tcg_gen_asan(TCGTemp* addr, size_t size);
|
36
include/libafl/hooks/cpu_run.h
Normal file
36
include/libafl/hooks/cpu_run.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "exec/tb-flush.h"
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
typedef void (*libafl_cpu_run_fn)(uint64_t data, CPUState* cpu);
|
||||||
|
|
||||||
|
struct libafl_cpu_run_hook {
|
||||||
|
// functions
|
||||||
|
libafl_cpu_run_fn pre_cpu_run;
|
||||||
|
libafl_cpu_run_fn post_cpu_run;
|
||||||
|
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_cpu_run_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t libafl_hook_cpu_run_add(libafl_cpu_run_fn pre_cpu_run,
|
||||||
|
libafl_cpu_run_fn post_cpu_run, uint64_t data);
|
||||||
|
|
||||||
|
int libafl_hook_cpu_run_remove(size_t num);
|
||||||
|
|
||||||
|
int libafl_qemu_remove_cpu_run_hook(size_t num);
|
||||||
|
|
||||||
|
void libafl_hook_cpu_run_pre_exec(CPUState* cpu);
|
||||||
|
void libafl_hook_cpu_run_post_exec(CPUState* cpu);
|
76
include/libafl/hooks/syscall.h
Normal file
76
include/libafl/hooks/syscall.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "exec/tb-flush.h"
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
struct syshook_ret {
|
||||||
|
target_ulong retval;
|
||||||
|
bool skip_syscall;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct libafl_pre_syscall_hook {
|
||||||
|
// functions
|
||||||
|
struct syshook_ret (*callback)(uint64_t data, int sys_num,
|
||||||
|
target_ulong arg0, target_ulong arg1,
|
||||||
|
target_ulong arg2, target_ulong arg3,
|
||||||
|
target_ulong arg4, target_ulong arg5,
|
||||||
|
target_ulong arg6, target_ulong arg7);
|
||||||
|
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_pre_syscall_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct libafl_post_syscall_hook {
|
||||||
|
// functions
|
||||||
|
target_ulong (*callback)(uint64_t data, target_ulong ret, int sys_num,
|
||||||
|
target_ulong arg0, target_ulong arg1,
|
||||||
|
target_ulong arg2, target_ulong arg3,
|
||||||
|
target_ulong arg4, target_ulong arg5,
|
||||||
|
target_ulong arg6, target_ulong arg7);
|
||||||
|
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_post_syscall_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t libafl_add_pre_syscall_hook(
|
||||||
|
struct syshook_ret (*callback)(uint64_t data, int sys_num,
|
||||||
|
target_ulong arg0, target_ulong arg1,
|
||||||
|
target_ulong arg2, target_ulong arg3,
|
||||||
|
target_ulong arg4, target_ulong arg5,
|
||||||
|
target_ulong arg6, target_ulong arg7),
|
||||||
|
uint64_t data);
|
||||||
|
size_t libafl_add_post_syscall_hook(
|
||||||
|
target_ulong (*callback)(uint64_t data, target_ulong ret, int sys_num,
|
||||||
|
target_ulong arg0, target_ulong arg1,
|
||||||
|
target_ulong arg2, target_ulong arg3,
|
||||||
|
target_ulong arg4, target_ulong arg5,
|
||||||
|
target_ulong arg6, target_ulong arg7),
|
||||||
|
uint64_t data);
|
||||||
|
|
||||||
|
int libafl_qemu_remove_pre_syscall_hook(size_t num);
|
||||||
|
int libafl_qemu_remove_post_syscall_hook(size_t num);
|
||||||
|
|
||||||
|
bool libafl_hook_syscall_pre_run(CPUArchState* env, int num, abi_long arg1,
|
||||||
|
abi_long arg2, abi_long arg3, abi_long arg4,
|
||||||
|
abi_long arg5, abi_long arg6, abi_long arg7,
|
||||||
|
abi_long arg8, abi_long* ret);
|
||||||
|
|
||||||
|
void libafl_hook_syscall_post_run(int num, abi_long arg1, abi_long arg2,
|
||||||
|
abi_long arg3, abi_long arg4, abi_long arg5,
|
||||||
|
abi_long arg6, abi_long arg7, abi_long arg8,
|
||||||
|
abi_long* ret);
|
38
include/libafl/hooks/tcg/backdoor.h
Normal file
38
include/libafl/hooks/tcg/backdoor.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "exec/tb-flush.h"
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
struct libafl_backdoor_hook {
|
||||||
|
// functions
|
||||||
|
void (*gen)(uint64_t data, CPUArchState* cpu, target_ulong pc);
|
||||||
|
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
TCGHelperInfo helper_info;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_backdoor_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct libafl_backdoor_hook* libafl_backdoor_hooks;
|
||||||
|
|
||||||
|
void libafl_gen_backdoor(target_ulong pc);
|
||||||
|
|
||||||
|
size_t libafl_add_backdoor_hook(void (*exec)(uint64_t data, CPUArchState* cpu,
|
||||||
|
target_ulong pc),
|
||||||
|
uint64_t data);
|
||||||
|
|
||||||
|
int libafl_qemu_remove_backdoor_hook(size_t num, int invalidate);
|
||||||
|
|
||||||
|
void libafl_qemu_hook_backdoor_run(vaddr pc_next);
|
43
include/libafl/hooks/tcg/block.h
Normal file
43
include/libafl/hooks/tcg/block.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "exec/tb-flush.h"
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
struct libafl_block_hook {
|
||||||
|
// functions
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong pc);
|
||||||
|
void (*post_gen)(uint64_t data, target_ulong pc, target_ulong block_length);
|
||||||
|
|
||||||
|
size_t (*jit)(uint64_t data, uint64_t id); // optional opt
|
||||||
|
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
TCGHelperInfo helper_info;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_block_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
void libafl_qemu_hook_block_post_gen(TranslationBlock* tb, vaddr pc);
|
||||||
|
void libafl_qemu_hook_block_run(target_ulong pc);
|
||||||
|
|
||||||
|
bool libafl_qemu_block_hook_set_jit(
|
||||||
|
size_t num,
|
||||||
|
size_t (*jit)(uint64_t,
|
||||||
|
uint64_t)); // no param names to avoid to be marked as safe
|
||||||
|
int libafl_qemu_remove_block_hook(size_t num, int invalidate);
|
||||||
|
size_t libafl_add_block_hook(uint64_t (*gen)(uint64_t data, target_ulong pc),
|
||||||
|
void (*post_gen)(uint64_t data, target_ulong pc,
|
||||||
|
target_ulong block_length),
|
||||||
|
void (*exec)(uint64_t data, uint64_t id),
|
||||||
|
uint64_t data);
|
39
include/libafl/hooks/tcg/cmp.h
Normal file
39
include/libafl/hooks/tcg/cmp.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "exec/tb-flush.h"
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
struct libafl_cmp_hook {
|
||||||
|
// functions
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size);
|
||||||
|
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
TCGHelperInfo helper_info1;
|
||||||
|
TCGHelperInfo helper_info2;
|
||||||
|
TCGHelperInfo helper_info4;
|
||||||
|
TCGHelperInfo helper_info8;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_cmp_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot);
|
||||||
|
size_t libafl_add_cmp_hook(
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size),
|
||||||
|
void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1),
|
||||||
|
void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1),
|
||||||
|
void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1),
|
||||||
|
void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1),
|
||||||
|
uint64_t data);
|
||||||
|
int libafl_qemu_remove_cmp_hook(size_t num, int invalidate);
|
48
include/libafl/hooks/tcg/edge.h
Normal file
48
include/libafl/hooks/tcg/edge.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "exec/tb-flush.h"
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
struct libafl_edge_hook {
|
||||||
|
// functions
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong src, target_ulong dst);
|
||||||
|
size_t (*jit)(uint64_t data, uint64_t id); // optional opt
|
||||||
|
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
uint64_t cur_id;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
TCGHelperInfo helper_info;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_edge_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
TranslationBlock* libafl_gen_edge(CPUState* cpu, target_ulong src_block,
|
||||||
|
target_ulong dst_block, int exit_n,
|
||||||
|
target_ulong cs_base, uint32_t flags,
|
||||||
|
int cflags);
|
||||||
|
|
||||||
|
size_t libafl_add_edge_hook(uint64_t (*gen)(uint64_t data, target_ulong src,
|
||||||
|
target_ulong dst),
|
||||||
|
void (*exec)(uint64_t data, uint64_t id),
|
||||||
|
uint64_t data);
|
||||||
|
|
||||||
|
bool libafl_qemu_edge_hook_set_jit(
|
||||||
|
size_t num,
|
||||||
|
size_t (*jit)(uint64_t,
|
||||||
|
uint64_t)); // no param names to avoid to be marked as safe
|
||||||
|
|
||||||
|
int libafl_qemu_remove_edge_hook(size_t num, int invalidate);
|
||||||
|
|
||||||
|
bool libafl_qemu_hook_edge_gen(target_ulong src_block, target_ulong dst_block);
|
||||||
|
void libafl_qemu_hook_edge_run(void);
|
43
include/libafl/hooks/tcg/instruction.h
Normal file
43
include/libafl/hooks/tcg/instruction.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "exec/tb-flush.h"
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
#define LIBAFL_TABLES_SIZE 16384
|
||||||
|
#define LIBAFL_TABLES_HASH(p) \
|
||||||
|
(((13 * ((size_t)(p))) ^ (((size_t)(p)) >> 15)) % LIBAFL_TABLES_SIZE)
|
||||||
|
|
||||||
|
struct libafl_instruction_hook {
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
target_ulong addr;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
TCGHelperInfo helper_info;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_instruction_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t libafl_qemu_add_instruction_hooks(target_ulong pc,
|
||||||
|
void (*callback)(uint64_t data,
|
||||||
|
target_ulong pc),
|
||||||
|
uint64_t data, int invalidate);
|
||||||
|
|
||||||
|
int libafl_qemu_remove_instruction_hook(size_t num, int invalidate);
|
||||||
|
|
||||||
|
size_t libafl_qemu_remove_instruction_hooks_at(target_ulong addr,
|
||||||
|
int invalidate);
|
||||||
|
|
||||||
|
struct libafl_instruction_hook*
|
||||||
|
libafl_search_instruction_hook(target_ulong addr);
|
||||||
|
|
||||||
|
void libafl_qemu_hook_instruction_run(vaddr pc_next);
|
60
include/libafl/hooks/tcg/read_write.h
Normal file
60
include/libafl/hooks/tcg/read_write.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "exec/tb-flush.h"
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
#define libafl_read_hook libafl_rw_hook
|
||||||
|
#define libafl_write_hook libafl_rw_hook
|
||||||
|
|
||||||
|
#define LIBAFL_TABLES_SIZE 16384
|
||||||
|
#define LIBAFL_TABLES_HASH(p) \
|
||||||
|
(((13 * ((size_t)(p))) ^ (((size_t)(p)) >> 15)) % LIBAFL_TABLES_SIZE)
|
||||||
|
|
||||||
|
struct libafl_rw_hook {
|
||||||
|
// functions
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi);
|
||||||
|
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
TCGHelperInfo helper_info1;
|
||||||
|
TCGHelperInfo helper_info2;
|
||||||
|
TCGHelperInfo helper_info4;
|
||||||
|
TCGHelperInfo helper_info8;
|
||||||
|
TCGHelperInfo helper_infoN;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_rw_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
void libafl_gen_read(TCGTemp* addr, MemOpIdx oi);
|
||||||
|
void libafl_gen_write(TCGTemp* addr, MemOpIdx oi);
|
||||||
|
|
||||||
|
size_t libafl_add_read_hook(
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi),
|
||||||
|
void (*exec1)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec2)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec4)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec8)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size),
|
||||||
|
uint64_t data);
|
||||||
|
size_t libafl_add_write_hook(
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi),
|
||||||
|
void (*exec1)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec2)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec4)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec8)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size),
|
||||||
|
uint64_t data);
|
||||||
|
|
||||||
|
int libafl_qemu_remove_read_hook(size_t num, int invalidate);
|
||||||
|
int libafl_qemu_remove_write_hook(size_t num, int invalidate);
|
31
include/libafl/hooks/thread.h
Normal file
31
include/libafl/hooks/thread.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
|
|
||||||
|
#include "exec/exec-all.h"
|
||||||
|
#include "exec/tb-flush.h"
|
||||||
|
|
||||||
|
#include "libafl/exit.h"
|
||||||
|
#include "libafl/hook.h"
|
||||||
|
|
||||||
|
struct libafl_new_thread_hook {
|
||||||
|
// functions
|
||||||
|
bool (*callback)(uint64_t data, CPUArchState* cpu, uint32_t tid);
|
||||||
|
|
||||||
|
// data
|
||||||
|
uint64_t data;
|
||||||
|
size_t num;
|
||||||
|
|
||||||
|
// next
|
||||||
|
struct libafl_new_thread_hook* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data,
|
||||||
|
CPUArchState* env,
|
||||||
|
uint32_t tid),
|
||||||
|
uint64_t data);
|
||||||
|
int libafl_qemu_remove_new_thread_hook(size_t num);
|
||||||
|
|
||||||
|
bool libafl_hook_new_thread_run(CPUArchState* env);
|
@ -2,14 +2,18 @@
|
|||||||
|
|
||||||
#include "qemu/error-report.h"
|
#include "qemu/error-report.h"
|
||||||
|
|
||||||
#define SYX_PRINTF(format, ...) fprintf(stderr, ("[QEMU-SYX] " format), ##__VA_ARGS__)
|
#define SYX_PRINTF(format, ...) \
|
||||||
|
fprintf(stderr, ("[QEMU-SYX] " format), ##__VA_ARGS__)
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_SYX
|
#ifdef CONFIG_DEBUG_SYX
|
||||||
#define SYX_DEBUG(format, ...) fprintf(stderr, ("[QEMU-SYX] DEBUG: " format), ##__VA_ARGS__)
|
#define SYX_DEBUG(format, ...) \
|
||||||
|
fprintf(stderr, ("[QEMU-SYX] DEBUG: " format), ##__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define SYX_DEBUG(format, ...)
|
#define SYX_DEBUG(format, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SYX_WARNING(format, ...) warn_report(("[QEMU-SYX] " format), ##__VA_ARGS__)
|
#define SYX_WARNING(format, ...) \
|
||||||
|
warn_report(("[QEMU-SYX] " format), ##__VA_ARGS__)
|
||||||
|
|
||||||
#define SYX_ERROR(format, ...) error_report(("[QEMU-SYX] " format), ##__VA_ARGS__)
|
#define SYX_ERROR(format, ...) \
|
||||||
|
error_report(("[QEMU-SYX] " format), ##__VA_ARGS__)
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "migration/qemu-file.h"
|
|
||||||
|
|
||||||
|
#include "migration/qemu-file.h"
|
||||||
#include "io/channel.h"
|
#include "io/channel.h"
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
|
|
||||||
#define QEMU_FILE_RAM_LIMIT (32 * 1024 * 1024)
|
#define QEMU_FILE_RAM_LIMIT (32 * 1024 * 1024)
|
||||||
|
|
||||||
#define TYPE_QIO_CHANNEL_BUFFER_WRITEBACK "qio-channel-buffer-writeback"
|
#define TYPE_QIO_CHANNEL_BUFFER_WRITEBACK "qio-channel-buffer-writeback"
|
||||||
OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelBufferWriteback, QIO_CHANNEL_BUFFER_WRITEBACK)
|
OBJECT_DECLARE_SIMPLE_TYPE(QIOChannelBufferWriteback,
|
||||||
|
QIO_CHANNEL_BUFFER_WRITEBACK)
|
||||||
|
|
||||||
struct QIOChannelBufferWriteback {
|
struct QIOChannelBufferWriteback {
|
||||||
QIOChannel parent;
|
QIOChannel parent;
|
||||||
@ -26,7 +27,10 @@ struct QIOChannelBufferWriteback {
|
|||||||
bool internal_allocation;
|
bool internal_allocation;
|
||||||
};
|
};
|
||||||
|
|
||||||
QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uint8_t* writeback_buf, size_t writeback_buf_capacity, size_t* writeback_buf_usage);
|
QIOChannelBufferWriteback*
|
||||||
|
qio_channel_buffer_writeback_new(size_t capacity, uint8_t* writeback_buf,
|
||||||
|
size_t writeback_buf_capacity,
|
||||||
|
size_t* writeback_buf_usage);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qio_channel_buffer_new_external:
|
* qio_channel_buffer_new_external:
|
||||||
@ -34,5 +38,6 @@ QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uin
|
|||||||
* @capacity: the total capacity of the underlying buffer
|
* @capacity: the total capacity of the underlying buffer
|
||||||
* @usage: The size actually used by the buffer
|
* @usage: The size actually used by the buffer
|
||||||
*/
|
*/
|
||||||
QIOChannelBufferWriteback*
|
QIOChannelBufferWriteback* qio_channel_buffer_writeback_new_external(
|
||||||
qio_channel_buffer_writeback_new_external(uint8_t* buf, size_t capacity, size_t usage, uint8_t* writeback_buf, size_t writeback_buf_capacity, size_t* writeback_buf_usage);
|
uint8_t* buf, size_t capacity, size_t usage, uint8_t* writeback_buf,
|
||||||
|
size_t writeback_buf_capacity, size_t* writeback_buf_usage);
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Rewritten COW cache for block devices, heavily inspired by kAFL/NYX implementation.
|
// Rewritten COW cache for block devices, heavily inspired by kAFL/NYX
|
||||||
|
// implementation.
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "qemu/iov.h"
|
#include "qemu/iov.h"
|
||||||
#include "block/block.h"
|
#include "block/block.h"
|
||||||
|
|
||||||
@ -33,13 +35,17 @@ SyxCowCache* syx_cow_cache_new(void);
|
|||||||
// rhs is freed and nulled.
|
// rhs is freed and nulled.
|
||||||
void syx_cow_cache_move(SyxCowCache* lhs, SyxCowCache** rhs);
|
void syx_cow_cache_move(SyxCowCache* lhs, SyxCowCache** rhs);
|
||||||
|
|
||||||
void syx_cow_cache_push_layer(SyxCowCache* scc, uint64_t chunk_size, uint64_t max_size);
|
void syx_cow_cache_push_layer(SyxCowCache* scc, uint64_t chunk_size,
|
||||||
|
uint64_t max_size);
|
||||||
void syx_cow_cache_pop_layer(SyxCowCache* scc);
|
void syx_cow_cache_pop_layer(SyxCowCache* scc);
|
||||||
|
|
||||||
void syx_cow_cache_flush_highest_layer(SyxCowCache* scc);
|
void syx_cow_cache_flush_highest_layer(SyxCowCache* scc);
|
||||||
|
|
||||||
void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset,
|
void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend* blk,
|
||||||
BdrvRequestFlags flags);
|
int64_t offset, int64_t bytes, QEMUIOVector* qiov,
|
||||||
|
size_t qiov_offset, BdrvRequestFlags flags);
|
||||||
|
|
||||||
bool syx_cow_cache_write_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset,
|
bool syx_cow_cache_write_entry(SyxCowCache* scc, BlockBackend* blk,
|
||||||
|
int64_t offset, int64_t bytes,
|
||||||
|
QEMUIOVector* qiov, size_t qiov_offset,
|
||||||
BdrvRequestFlags flags);
|
BdrvRequestFlags flags);
|
||||||
|
@ -9,11 +9,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "qom/object.h"
|
#include "qom/object.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
|
||||||
#include "device-save.h"
|
#include "device-save.h"
|
||||||
#include "syx-cow-cache.h"
|
#include "syx-cow-cache.h"
|
||||||
|
|
||||||
#include "libafl/syx-misc.h"
|
#include "libafl/syx-misc.h"
|
||||||
|
|
||||||
#define SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE 64
|
#define SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE 64
|
||||||
@ -31,7 +33,9 @@ typedef struct SyxSnapshot {
|
|||||||
SyxSnapshotIncrement* last_incremental_snapshot;
|
SyxSnapshotIncrement* last_incremental_snapshot;
|
||||||
|
|
||||||
SyxCowCache* bdrvs_cow_cache;
|
SyxCowCache* bdrvs_cow_cache;
|
||||||
GHashTable *rbs_dirty_list; // hash map: H(rb) -> GHashTable(offset_within_ramblock). Filled lazily.
|
GHashTable*
|
||||||
|
rbs_dirty_list; // hash map: H(rb) ->
|
||||||
|
// GHashTable(offset_within_ramblock). Filled lazily.
|
||||||
} SyxSnapshot;
|
} SyxSnapshot;
|
||||||
|
|
||||||
typedef struct SyxSnapshotTracker {
|
typedef struct SyxSnapshotTracker {
|
||||||
@ -69,7 +73,8 @@ void syx_snapshot_init(bool cached_bdrvs);
|
|||||||
// Snapshot API
|
// Snapshot API
|
||||||
//
|
//
|
||||||
|
|
||||||
SyxSnapshot *syx_snapshot_new(bool track, bool is_active_bdrv_cache, DeviceSnapshotKind kind, char **devices);
|
SyxSnapshot* syx_snapshot_new(bool track, bool is_active_bdrv_cache,
|
||||||
|
DeviceSnapshotKind kind, char** devices);
|
||||||
|
|
||||||
void syx_snapshot_free(SyxSnapshot* snapshot);
|
void syx_snapshot_free(SyxSnapshot* snapshot);
|
||||||
|
|
||||||
@ -78,14 +83,15 @@ void syx_snapshot_root_restore(SyxSnapshot *snapshot);
|
|||||||
SyxSnapshotCheckResult syx_snapshot_check(SyxSnapshot* ref_snapshot);
|
SyxSnapshotCheckResult syx_snapshot_check(SyxSnapshot* ref_snapshot);
|
||||||
|
|
||||||
// Push the current RAM state and saves it
|
// Push the current RAM state and saves it
|
||||||
void syx_snapshot_increment_push(SyxSnapshot *snapshot, DeviceSnapshotKind kind, char **devices);
|
void syx_snapshot_increment_push(SyxSnapshot* snapshot, DeviceSnapshotKind kind,
|
||||||
|
char** devices);
|
||||||
|
|
||||||
// Restores the last push. Restores the root snapshot if no incremental snapshot is present.
|
// Restores the last push. Restores the root snapshot if no incremental snapshot
|
||||||
|
// is present.
|
||||||
void syx_snapshot_increment_pop(SyxSnapshot* snapshot);
|
void syx_snapshot_increment_pop(SyxSnapshot* snapshot);
|
||||||
|
|
||||||
void syx_snapshot_increment_restore_last(SyxSnapshot* snapshot);
|
void syx_snapshot_increment_restore_last(SyxSnapshot* snapshot);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Snapshot tracker API
|
// Snapshot tracker API
|
||||||
//
|
//
|
||||||
@ -94,8 +100,8 @@ SyxSnapshotTracker syx_snapshot_tracker_init(void);
|
|||||||
|
|
||||||
void syx_snapshot_track(SyxSnapshotTracker* tracker, SyxSnapshot* snapshot);
|
void syx_snapshot_track(SyxSnapshotTracker* tracker, SyxSnapshot* snapshot);
|
||||||
|
|
||||||
void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot);
|
void syx_snapshot_stop_track(SyxSnapshotTracker* tracker,
|
||||||
|
SyxSnapshot* snapshot);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Misc functions
|
// Misc functions
|
||||||
@ -103,7 +109,6 @@ void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot)
|
|||||||
|
|
||||||
bool syx_snapshot_is_enabled(void);
|
bool syx_snapshot_is_enabled(void);
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Dirty list API
|
// Dirty list API
|
||||||
//
|
//
|
||||||
@ -126,8 +131,12 @@ void syx_snapshot_dirty_list_add_hostaddr_range(void *host_addr, uint64_t len);
|
|||||||
*/
|
*/
|
||||||
void syx_snapshot_dirty_list_add_tcg_target(uint64_t dummy, void* host_addr);
|
void syx_snapshot_dirty_list_add_tcg_target(uint64_t dummy, void* host_addr);
|
||||||
|
|
||||||
bool syx_snapshot_cow_cache_read_entry(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset,
|
bool syx_snapshot_cow_cache_read_entry(BlockBackend* blk, int64_t offset,
|
||||||
|
int64_t bytes, QEMUIOVector* qiov,
|
||||||
|
size_t qiov_offset,
|
||||||
BdrvRequestFlags flags);
|
BdrvRequestFlags flags);
|
||||||
|
|
||||||
bool syx_snapshot_cow_cache_write_entry(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset,
|
bool syx_snapshot_cow_cache_write_entry(BlockBackend* blk, int64_t offset,
|
||||||
|
int64_t bytes, QEMUIOVector* qiov,
|
||||||
|
size_t qiov_offset,
|
||||||
BdrvRequestFlags flags);
|
BdrvRequestFlags flags);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
struct libafl_mapinfo {
|
struct libafl_mapinfo {
|
||||||
target_ulong start;
|
target_ulong start;
|
||||||
@ -13,5 +13,9 @@ struct libafl_mapinfo {
|
|||||||
bool is_valid;
|
bool is_valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc);
|
||||||
|
|
||||||
IntervalTreeNode* libafl_maps_first(IntervalTreeRoot* map_info);
|
IntervalTreeNode* libafl_maps_first(IntervalTreeRoot* map_info);
|
||||||
IntervalTreeNode * libafl_maps_next(IntervalTreeNode *pageflags_maps_node, IntervalTreeRoot *proc_maps_node, struct libafl_mapinfo* ret);
|
IntervalTreeNode* libafl_maps_next(IntervalTreeNode* pageflags_maps_node,
|
||||||
|
IntervalTreeRoot* proc_maps_node,
|
||||||
|
struct libafl_mapinfo* ret);
|
||||||
|
9
libafl/.clang-format
Normal file
9
libafl/.clang-format
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
BasedOnStyle: LLVM
|
||||||
|
IndentWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
BreakBeforeBraces: Linux
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
SortIncludes: Never
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
PointerAlignment: Left
|
@ -1,6 +1,11 @@
|
|||||||
#include "libafl/exit.h"
|
#include "libafl/exit.h"
|
||||||
|
|
||||||
|
#include "tcg/tcg.h"
|
||||||
|
#include "tcg/tcg-op.h"
|
||||||
|
#include "tcg/tcg-temp-internal.h"
|
||||||
#include "sysemu/runstate.h"
|
#include "sysemu/runstate.h"
|
||||||
|
#include "exec/translator.h"
|
||||||
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
@ -15,9 +20,7 @@ int libafl_qemu_set_breakpoint(target_ulong pc)
|
|||||||
{
|
{
|
||||||
CPUState* cpu;
|
CPUState* cpu;
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, pc); }
|
||||||
libafl_breakpoint_invalidate(cpu, pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_breakpoint* bp = calloc(sizeof(struct libafl_breakpoint), 1);
|
struct libafl_breakpoint* bp = calloc(sizeof(struct libafl_breakpoint), 1);
|
||||||
bp->addr = pc;
|
bp->addr = pc;
|
||||||
@ -34,9 +37,7 @@ int libafl_qemu_remove_breakpoint(target_ulong pc)
|
|||||||
struct libafl_breakpoint** bp = &libafl_qemu_breakpoints;
|
struct libafl_breakpoint** bp = &libafl_qemu_breakpoints;
|
||||||
while (*bp) {
|
while (*bp) {
|
||||||
if ((*bp)->addr == pc) {
|
if ((*bp)->addr == pc) {
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, pc); }
|
||||||
libafl_breakpoint_invalidate(cpu, pc);
|
|
||||||
}
|
|
||||||
|
|
||||||
*bp = (*bp)->next;
|
*bp = (*bp)->next;
|
||||||
r = 1;
|
r = 1;
|
||||||
@ -61,15 +62,13 @@ void libafl_sync_exit_cpu(void)
|
|||||||
{
|
{
|
||||||
if (last_exit_reason.next_pc) {
|
if (last_exit_reason.next_pc) {
|
||||||
CPUClass* cc = CPU_GET_CLASS(last_exit_reason.cpu);
|
CPUClass* cc = CPU_GET_CLASS(last_exit_reason.cpu);
|
||||||
cc->set_pc(last_exit_reason.cpu, THUMB_MASK(last_exit_reason.cpu, last_exit_reason.next_pc));
|
cc->set_pc(last_exit_reason.cpu,
|
||||||
|
THUMB_MASK(last_exit_reason.cpu, last_exit_reason.next_pc));
|
||||||
}
|
}
|
||||||
last_exit_reason.next_pc = 0;
|
last_exit_reason.next_pc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool libafl_exit_asap(void)
|
bool libafl_exit_asap(void) { return expected_exit; }
|
||||||
{
|
|
||||||
return expected_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void prepare_qemu_exit(CPUState* cpu, target_ulong next_pc)
|
static void prepare_qemu_exit(CPUState* cpu, target_ulong next_pc)
|
||||||
{
|
{
|
||||||
@ -81,7 +80,8 @@ static void prepare_qemu_exit(CPUState* cpu, target_ulong next_pc)
|
|||||||
qemu_system_debug_request();
|
qemu_system_debug_request();
|
||||||
cpu->stopped = true; // TODO check if still needed
|
cpu->stopped = true; // TODO check if still needed
|
||||||
#endif
|
#endif
|
||||||
// in usermode, this may be called from the syscall hook, thus already out of the cpu_exec but still in the cpu_loop
|
// in usermode, this may be called from the syscall hook, thus already out
|
||||||
|
// of the cpu_exec but still in the cpu_loop
|
||||||
if (cpu->running) {
|
if (cpu->running) {
|
||||||
cpu->exception_index = EXCP_LIBAFL_EXIT;
|
cpu->exception_index = EXCP_LIBAFL_EXIT;
|
||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
@ -97,7 +97,8 @@ CPUState* libafl_last_exit_cpu(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void libafl_exit_request_internal(CPUState* cpu, uint64_t pc, ShutdownCause cause, int signal)
|
void libafl_exit_request_internal(CPUState* cpu, uint64_t pc,
|
||||||
|
ShutdownCause cause, int signal)
|
||||||
{
|
{
|
||||||
last_exit_reason.kind = INTERNAL;
|
last_exit_reason.kind = INTERNAL;
|
||||||
last_exit_reason.data.internal.cause = cause;
|
last_exit_reason.data.internal.cause = cause;
|
||||||
@ -143,3 +144,16 @@ struct libafl_exit_reason* libafl_get_exit_reason(void)
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void libafl_qemu_breakpoint_run(vaddr pc_next)
|
||||||
|
{
|
||||||
|
struct libafl_breakpoint* bp = libafl_qemu_breakpoints;
|
||||||
|
while (bp) {
|
||||||
|
if (bp->addr == pc_next) {
|
||||||
|
TCGv_i64 tmp0 = tcg_constant_i64((uint64_t)pc_next);
|
||||||
|
gen_helper_libafl_qemu_handle_breakpoint(tcg_env, tmp0);
|
||||||
|
tcg_temp_free_i64(tmp0);
|
||||||
|
}
|
||||||
|
bp = bp->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
689
libafl/hook.c
689
libafl/hook.c
@ -1,4 +1,5 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
@ -11,683 +12,6 @@
|
|||||||
#error "TARGET_LONG_BITS not defined"
|
#error "TARGET_LONG_BITS not defined"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
target_ulong libafl_gen_cur_pc;
|
|
||||||
|
|
||||||
struct libafl_hook* libafl_qemu_instruction_hooks[LIBAFL_TABLES_SIZE];
|
|
||||||
size_t libafl_qemu_hooks_num = 0;
|
|
||||||
|
|
||||||
size_t libafl_qemu_add_instruction_hooks(target_ulong pc, void (*callback)(uint64_t data, target_ulong pc),
|
|
||||||
uint64_t data, int invalidate)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
|
|
||||||
if (invalidate) {
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
libafl_breakpoint_invalidate(cpu, pc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t idx = LIBAFL_TABLES_HASH(pc);
|
|
||||||
|
|
||||||
struct libafl_hook* hk = calloc(sizeof(struct libafl_hook), 1);
|
|
||||||
hk->addr = pc;
|
|
||||||
// hk->callback = callback;
|
|
||||||
hk->data = data;
|
|
||||||
hk->helper_info.func = callback;
|
|
||||||
hk->helper_info.name = "libafl_hook";
|
|
||||||
hk->helper_info.flags = dh_callflag(void);
|
|
||||||
hk->helper_info.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(tl, 2);
|
|
||||||
// TODO check for overflow
|
|
||||||
hk->num = libafl_qemu_hooks_num++;
|
|
||||||
hk->next = libafl_qemu_instruction_hooks[idx];
|
|
||||||
libafl_qemu_instruction_hooks[idx] = hk;
|
|
||||||
return hk->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t libafl_qemu_remove_instruction_hooks_at(target_ulong addr, int invalidate)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
size_t r = 0;
|
|
||||||
|
|
||||||
size_t idx = LIBAFL_TABLES_HASH(addr);
|
|
||||||
struct libafl_hook** hk = &libafl_qemu_instruction_hooks[idx];
|
|
||||||
while (*hk) {
|
|
||||||
if ((*hk)->addr == addr) {
|
|
||||||
if (invalidate) {
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
libafl_breakpoint_invalidate(cpu, addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *tmp = *hk;
|
|
||||||
*hk = (*hk)->next;
|
|
||||||
free(tmp);
|
|
||||||
r++;
|
|
||||||
} else {
|
|
||||||
hk = &(*hk)->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int libafl_qemu_remove_instruction_hook(size_t num, int invalidate)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
size_t idx;
|
|
||||||
|
|
||||||
for (idx = 0; idx < LIBAFL_TABLES_SIZE; ++idx) {
|
|
||||||
struct libafl_hook** hk = &libafl_qemu_instruction_hooks[idx];
|
|
||||||
while (*hk) {
|
|
||||||
if ((*hk)->num == num) {
|
|
||||||
if (invalidate) {
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
libafl_breakpoint_invalidate(cpu, (*hk)->addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void *tmp = *hk;
|
|
||||||
*hk = (*hk)->next;
|
|
||||||
free(tmp);
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
hk = &(*hk)->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_hook* libafl_search_instruction_hook(target_ulong addr)
|
|
||||||
{
|
|
||||||
size_t idx = LIBAFL_TABLES_HASH(addr);
|
|
||||||
|
|
||||||
struct libafl_hook* hk = libafl_qemu_instruction_hooks[idx];
|
|
||||||
while (hk) {
|
|
||||||
if (hk->addr == addr) {
|
|
||||||
return hk;
|
|
||||||
}
|
|
||||||
hk = hk->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GEN_REMOVE_HOOK(name) \
|
|
||||||
int libafl_qemu_remove_##name##_hook(size_t num, int invalidate) \
|
|
||||||
{ \
|
|
||||||
CPUState *cpu; \
|
|
||||||
struct libafl_##name##_hook** hk = &libafl_##name##_hooks; \
|
|
||||||
\
|
|
||||||
while (*hk) { \
|
|
||||||
if ((*hk)->num == num) { \
|
|
||||||
if (invalidate) { \
|
|
||||||
CPU_FOREACH(cpu) { \
|
|
||||||
tb_flush(cpu); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
void *tmp = *hk; \
|
|
||||||
*hk = (*hk)->next; \
|
|
||||||
free(tmp); \
|
|
||||||
return 1; \
|
|
||||||
} else { \
|
|
||||||
hk = &(*hk)->next; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
return 0; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define GEN_REMOVE_HOOK1(name) \
|
|
||||||
int libafl_qemu_remove_##name##_hook(size_t num) \
|
|
||||||
{ \
|
|
||||||
struct libafl_##name##_hook** hk = &libafl_##name##_hooks; \
|
|
||||||
\
|
|
||||||
while (*hk) { \
|
|
||||||
if ((*hk)->num == num) { \
|
|
||||||
void *tmp = *hk; \
|
|
||||||
*hk = (*hk)->next; \
|
|
||||||
free(tmp); \
|
|
||||||
return 1; \
|
|
||||||
} else { \
|
|
||||||
hk = &(*hk)->next; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
return 0; \
|
|
||||||
}
|
|
||||||
|
|
||||||
static TCGHelperInfo libafl_exec_backdoor_hook_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_backdoor_hook",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0)
|
|
||||||
| dh_typemask(env, 1)
|
|
||||||
| dh_typemask(i64, 2)
|
|
||||||
| dh_typemask(tl, 3)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct libafl_backdoor_hook* libafl_backdoor_hooks;
|
|
||||||
size_t libafl_backdoor_hooks_num = 0;
|
|
||||||
|
|
||||||
size_t libafl_add_backdoor_hook(void (*exec)(uint64_t data, CPUArchState* cpu, target_ulong pc),
|
|
||||||
uint64_t data)
|
|
||||||
{
|
|
||||||
struct libafl_backdoor_hook* hook = calloc(sizeof(struct libafl_backdoor_hook), 1);
|
|
||||||
// hook->exec = exec;
|
|
||||||
hook->data = data;
|
|
||||||
hook->num = libafl_backdoor_hooks_num++;
|
|
||||||
hook->next = libafl_backdoor_hooks;
|
|
||||||
libafl_backdoor_hooks = hook;
|
|
||||||
|
|
||||||
memcpy(&hook->helper_info, &libafl_exec_backdoor_hook_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info.func = exec;
|
|
||||||
|
|
||||||
return hook->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
GEN_REMOVE_HOOK(backdoor)
|
|
||||||
|
|
||||||
static TCGHelperInfo libafl_exec_edge_hook_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_edge_hook",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct libafl_edge_hook* libafl_edge_hooks;
|
|
||||||
size_t libafl_edge_hooks_num = 0;
|
|
||||||
|
|
||||||
size_t libafl_add_edge_hook(uint64_t (*gen)(uint64_t data, target_ulong src, target_ulong dst),
|
|
||||||
void (*exec)(uint64_t data, uint64_t id),
|
|
||||||
uint64_t data)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
tb_flush(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_edge_hook* hook = calloc(sizeof(struct libafl_edge_hook), 1);
|
|
||||||
hook->gen = gen;
|
|
||||||
// hook->exec = exec;
|
|
||||||
hook->data = data;
|
|
||||||
hook->num = libafl_edge_hooks_num++;
|
|
||||||
hook->next = libafl_edge_hooks;
|
|
||||||
libafl_edge_hooks = hook;
|
|
||||||
|
|
||||||
if (exec) {
|
|
||||||
memcpy(&hook->helper_info, &libafl_exec_edge_hook_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info.func = exec;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hook->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
GEN_REMOVE_HOOK(edge)
|
|
||||||
|
|
||||||
bool libafl_qemu_edge_hook_set_jit(size_t num, size_t (*jit)(uint64_t data, uint64_t id)) {
|
|
||||||
struct libafl_edge_hook* hk = libafl_edge_hooks;
|
|
||||||
while (hk) {
|
|
||||||
if (hk->num == num) {
|
|
||||||
hk->jit = jit;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
hk = hk->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TCGHelperInfo libafl_exec_block_hook_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_block_hook", \
|
|
||||||
.flags = dh_callflag(void), \
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct libafl_block_hook* libafl_block_hooks;
|
|
||||||
size_t libafl_block_hooks_num = 0;
|
|
||||||
|
|
||||||
size_t libafl_add_block_hook(uint64_t (*gen)(uint64_t data, target_ulong pc),
|
|
||||||
void (*post_gen)(uint64_t data, target_ulong pc, target_ulong block_length),
|
|
||||||
void (*exec)(uint64_t data, uint64_t id), uint64_t data)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
tb_flush(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_block_hook* hook = calloc(sizeof(struct libafl_block_hook), 1);
|
|
||||||
hook->gen = gen;
|
|
||||||
hook->post_gen = post_gen;
|
|
||||||
// hook->exec = exec;
|
|
||||||
hook->data = data;
|
|
||||||
hook->num = libafl_block_hooks_num++;
|
|
||||||
hook->next = libafl_block_hooks;
|
|
||||||
libafl_block_hooks = hook;
|
|
||||||
|
|
||||||
if (exec) {
|
|
||||||
memcpy(&hook->helper_info, &libafl_exec_block_hook_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info.func = exec;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hook->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
GEN_REMOVE_HOOK(block)
|
|
||||||
|
|
||||||
bool libafl_qemu_block_hook_set_jit(size_t num, size_t (*jit)(uint64_t data, uint64_t id)) {
|
|
||||||
struct libafl_block_hook* hk = libafl_block_hooks;
|
|
||||||
while (hk) {
|
|
||||||
if (hk->num == num) {
|
|
||||||
hk->jit = jit;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
hk = hk->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TCGHelperInfo libafl_exec_read_hook1_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_read_hook1",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_read_hook2_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_read_hook2",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_read_hook4_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_read_hook4",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_read_hook8_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_read_hook8",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_read_hookN_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_read_hookN",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2)
|
|
||||||
| dh_typemask(tl, 3) | dh_typemask(i64, 4)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_write_hook1_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_write_hook1",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_write_hook2_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_write_hook2",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_write_hook4_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_write_hook4",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_write_hook8_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_write_hook8",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2) | dh_typemask(tl, 3)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_write_hookN_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_write_hookN",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2)
|
|
||||||
| dh_typemask(tl, 3) | dh_typemask(i64, 4)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct libafl_rw_hook* libafl_read_hooks;
|
|
||||||
size_t libafl_read_hooks_num = 0;
|
|
||||||
|
|
||||||
size_t libafl_add_read_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp *addr, MemOpIdx oi),
|
|
||||||
void (*exec1)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec2)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec4)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec8)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size),
|
|
||||||
uint64_t data)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
tb_flush(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_rw_hook* hook = calloc(sizeof(struct libafl_rw_hook), 1);
|
|
||||||
hook->gen = gen;
|
|
||||||
/*hook->exec1 = exec1;
|
|
||||||
hook->exec2 = exec2;
|
|
||||||
hook->exec4 = exec4;
|
|
||||||
hook->exec8 = exec8;
|
|
||||||
hook->execN = execN;*/
|
|
||||||
hook->data = data;
|
|
||||||
hook->num = libafl_read_hooks_num++;
|
|
||||||
hook->next = libafl_read_hooks;
|
|
||||||
libafl_read_hooks = hook;
|
|
||||||
|
|
||||||
if (exec1) {
|
|
||||||
memcpy(&hook->helper_info1, &libafl_exec_read_hook1_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info1.func = exec1;
|
|
||||||
}
|
|
||||||
if (exec2) {
|
|
||||||
memcpy(&hook->helper_info2, &libafl_exec_read_hook2_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info2.func = exec2;
|
|
||||||
}
|
|
||||||
if (exec4) {
|
|
||||||
memcpy(&hook->helper_info4, &libafl_exec_read_hook4_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info4.func = exec4;
|
|
||||||
}
|
|
||||||
if (exec8) {
|
|
||||||
memcpy(&hook->helper_info8, &libafl_exec_read_hook8_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info8.func = exec8;
|
|
||||||
}
|
|
||||||
if (execN) {
|
|
||||||
memcpy(&hook->helper_infoN, &libafl_exec_read_hookN_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_infoN.func = execN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hook->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
GEN_REMOVE_HOOK(read)
|
|
||||||
|
|
||||||
struct libafl_rw_hook* libafl_write_hooks;
|
|
||||||
size_t libafl_write_hooks_num = 0;
|
|
||||||
|
|
||||||
size_t libafl_add_write_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp *addr, MemOpIdx oi),
|
|
||||||
void (*exec1)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec2)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec4)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*exec8)(uint64_t data, uint64_t id, target_ulong addr),
|
|
||||||
void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size),
|
|
||||||
uint64_t data)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
tb_flush(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_rw_hook* hook = calloc(sizeof(struct libafl_rw_hook), 1);
|
|
||||||
hook->gen = gen;
|
|
||||||
/*hook->exec1 = exec1;
|
|
||||||
hook->exec2 = exec2;
|
|
||||||
hook->exec4 = exec4;
|
|
||||||
hook->exec8 = exec8;
|
|
||||||
hook->execN = execN;*/
|
|
||||||
hook->data = data;
|
|
||||||
hook->num = libafl_write_hooks_num++;
|
|
||||||
hook->next = libafl_write_hooks;
|
|
||||||
libafl_write_hooks = hook;
|
|
||||||
|
|
||||||
if (exec1) {
|
|
||||||
memcpy(&hook->helper_info1, &libafl_exec_write_hook1_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info1.func = exec1;
|
|
||||||
}
|
|
||||||
if (exec2) {
|
|
||||||
memcpy(&hook->helper_info2, &libafl_exec_write_hook2_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info2.func = exec2;
|
|
||||||
}
|
|
||||||
if (exec4) {
|
|
||||||
memcpy(&hook->helper_info4, &libafl_exec_write_hook4_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info4.func = exec4;
|
|
||||||
}
|
|
||||||
if (exec8) {
|
|
||||||
memcpy(&hook->helper_info8, &libafl_exec_write_hook8_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info8.func = exec8;
|
|
||||||
}
|
|
||||||
if (execN) {
|
|
||||||
memcpy(&hook->helper_infoN, &libafl_exec_write_hookN_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_infoN.func = execN;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hook->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
GEN_REMOVE_HOOK(write)
|
|
||||||
|
|
||||||
static void libafl_gen_rw(TCGTemp *addr, MemOpIdx oi, struct libafl_rw_hook* hook)
|
|
||||||
{
|
|
||||||
size_t size = memop_size(get_memop(oi));
|
|
||||||
|
|
||||||
while (hook) {
|
|
||||||
uint64_t cur_id = 0;
|
|
||||||
if (hook->gen)
|
|
||||||
cur_id = hook->gen(hook->data, libafl_gen_cur_pc, addr, oi);
|
|
||||||
TCGHelperInfo* info = NULL;
|
|
||||||
if (size == 1 && hook->helper_info1.func) info = &hook->helper_info1;
|
|
||||||
else if (size == 2 && hook->helper_info2.func) info = &hook->helper_info2;
|
|
||||||
else if (size == 4 && hook->helper_info4.func) info = &hook->helper_info4;
|
|
||||||
else if (size == 8 && hook->helper_info8.func) info = &hook->helper_info8;
|
|
||||||
if (cur_id != (uint64_t)-1) {
|
|
||||||
if (info) {
|
|
||||||
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
|
||||||
TCGv_i64 tmp1 = tcg_constant_i64(cur_id);
|
|
||||||
TCGTemp *tmp2[3] = { tcgv_i64_temp(tmp0),
|
|
||||||
tcgv_i64_temp(tmp1),
|
|
||||||
addr };
|
|
||||||
tcg_gen_callN(info, NULL, tmp2);
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
tcg_temp_free_i64(tmp1);
|
|
||||||
} else if (hook->helper_infoN.func) {
|
|
||||||
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
|
||||||
TCGv_i64 tmp1 = tcg_constant_i64(cur_id);
|
|
||||||
TCGv tmp2 = tcg_constant_tl(size);
|
|
||||||
TCGTemp *tmp3[4] = { tcgv_i64_temp(tmp0),
|
|
||||||
tcgv_i64_temp(tmp1),
|
|
||||||
addr,
|
|
||||||
#if TARGET_LONG_BITS == 32
|
|
||||||
tcgv_i32_temp(tmp2) };
|
|
||||||
#else
|
|
||||||
tcgv_i64_temp(tmp2) };
|
|
||||||
#endif
|
|
||||||
tcg_gen_callN(&hook->helper_infoN, NULL, tmp3);
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
tcg_temp_free_i64(tmp1);
|
|
||||||
#if TARGET_LONG_BITS == 32
|
|
||||||
tcg_temp_free_i32(tmp2);
|
|
||||||
#else
|
|
||||||
tcg_temp_free_i64(tmp2);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hook = hook->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void libafl_gen_read(TCGTemp *addr, MemOpIdx oi)
|
|
||||||
{
|
|
||||||
libafl_gen_rw(addr, oi, libafl_read_hooks);
|
|
||||||
}
|
|
||||||
|
|
||||||
void libafl_gen_write(TCGTemp *addr, MemOpIdx oi)
|
|
||||||
{
|
|
||||||
libafl_gen_rw(addr, oi, libafl_write_hooks);
|
|
||||||
}
|
|
||||||
|
|
||||||
static TCGHelperInfo libafl_exec_cmp_hook1_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_cmp_hook1",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
|
|
||||||
| dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_cmp_hook2_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_cmp_hook2",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
|
|
||||||
| dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_cmp_hook4_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_cmp_hook4",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
|
|
||||||
| dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4)
|
|
||||||
};
|
|
||||||
static TCGHelperInfo libafl_exec_cmp_hook8_info = {
|
|
||||||
.func = NULL, .name = "libafl_exec_cmp_hook8",
|
|
||||||
.flags = dh_callflag(void),
|
|
||||||
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1)
|
|
||||||
| dh_typemask(i64, 2) | dh_typemask(i64, 3) | dh_typemask(i64, 4)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct libafl_cmp_hook* libafl_cmp_hooks;
|
|
||||||
size_t libafl_cmp_hooks_num = 0;
|
|
||||||
|
|
||||||
size_t libafl_add_cmp_hook(uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size),
|
|
||||||
void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1),
|
|
||||||
void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1),
|
|
||||||
void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1),
|
|
||||||
void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1),
|
|
||||||
uint64_t data)
|
|
||||||
{
|
|
||||||
CPUState *cpu;
|
|
||||||
CPU_FOREACH(cpu) {
|
|
||||||
tb_flush(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_cmp_hook* hook = calloc(sizeof(struct libafl_cmp_hook), 1);
|
|
||||||
hook->gen = gen;
|
|
||||||
/*hook->exec1 = exec1;
|
|
||||||
hook->exec2 = exec2;
|
|
||||||
hook->exec4 = exec4;
|
|
||||||
hook->exec8 = exec8;*/
|
|
||||||
hook->data = data;
|
|
||||||
hook->num = libafl_cmp_hooks_num++;
|
|
||||||
hook->next = libafl_cmp_hooks;
|
|
||||||
libafl_cmp_hooks = hook;
|
|
||||||
|
|
||||||
if (exec1) {
|
|
||||||
memcpy(&hook->helper_info1, &libafl_exec_cmp_hook1_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info1.func = exec1;
|
|
||||||
}
|
|
||||||
if (exec2) {
|
|
||||||
memcpy(&hook->helper_info2, &libafl_exec_cmp_hook2_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info2.func = exec2;
|
|
||||||
}
|
|
||||||
if (exec4) {
|
|
||||||
memcpy(&hook->helper_info4, &libafl_exec_cmp_hook4_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info4.func = exec4;
|
|
||||||
}
|
|
||||||
if (exec8) {
|
|
||||||
memcpy(&hook->helper_info8, &libafl_exec_cmp_hook8_info, sizeof(TCGHelperInfo));
|
|
||||||
hook->helper_info8.func = exec8;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hook->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
GEN_REMOVE_HOOK(cmp)
|
|
||||||
|
|
||||||
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot)
|
|
||||||
{
|
|
||||||
size_t size = 0;
|
|
||||||
switch (ot & MO_SIZE) {
|
|
||||||
case MO_64:
|
|
||||||
size = 8;
|
|
||||||
break;
|
|
||||||
case MO_32:
|
|
||||||
size = 4;
|
|
||||||
break;
|
|
||||||
case MO_16:
|
|
||||||
size = 2;
|
|
||||||
break;
|
|
||||||
case MO_8:
|
|
||||||
size = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_cmp_hook* hook = libafl_cmp_hooks;
|
|
||||||
while (hook) {
|
|
||||||
uint64_t cur_id = 0;
|
|
||||||
if (hook->gen)
|
|
||||||
cur_id = hook->gen(hook->data, pc, size);
|
|
||||||
TCGHelperInfo* info = NULL;
|
|
||||||
if (size == 1 && hook->helper_info1.func) info = &hook->helper_info1;
|
|
||||||
else if (size == 2 && hook->helper_info2.func) info = &hook->helper_info2;
|
|
||||||
else if (size == 4 && hook->helper_info4.func) info = &hook->helper_info4;
|
|
||||||
else if (size == 8 && hook->helper_info8.func) info = &hook->helper_info8;
|
|
||||||
if (cur_id != (uint64_t)-1 && info) {
|
|
||||||
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
|
||||||
TCGv_i64 tmp1 = tcg_constant_i64(cur_id);
|
|
||||||
TCGTemp *tmp2[4] = { tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1),
|
|
||||||
#if TARGET_LONG_BITS == 32
|
|
||||||
tcgv_i32_temp(op0), tcgv_i32_temp(op1) };
|
|
||||||
#else
|
|
||||||
tcgv_i64_temp(op0), tcgv_i64_temp(op1) };
|
|
||||||
#endif
|
|
||||||
tcg_gen_callN(info, NULL, tmp2);
|
|
||||||
tcg_temp_free_i64(tmp0);
|
|
||||||
tcg_temp_free_i64(tmp1);
|
|
||||||
}
|
|
||||||
hook = hook->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct libafl_pre_syscall_hook* libafl_pre_syscall_hooks;
|
|
||||||
struct libafl_post_syscall_hook* libafl_post_syscall_hooks;
|
|
||||||
|
|
||||||
size_t libafl_pre_syscall_hooks_num = 0;
|
|
||||||
size_t libafl_post_syscall_hooks_num = 0;
|
|
||||||
|
|
||||||
size_t libafl_add_pre_syscall_hook(struct syshook_ret (*callback)(
|
|
||||||
uint64_t data, int sys_num, target_ulong arg0,
|
|
||||||
target_ulong arg1, target_ulong arg2,
|
|
||||||
target_ulong arg3, target_ulong arg4,
|
|
||||||
target_ulong arg5, target_ulong arg6,
|
|
||||||
target_ulong arg7),
|
|
||||||
uint64_t data)
|
|
||||||
{
|
|
||||||
struct libafl_pre_syscall_hook* hook = calloc(sizeof(struct libafl_pre_syscall_hook), 1);
|
|
||||||
hook->callback = callback;
|
|
||||||
hook->data = data;
|
|
||||||
hook->num = libafl_pre_syscall_hooks_num++;
|
|
||||||
hook->next = libafl_pre_syscall_hooks;
|
|
||||||
libafl_pre_syscall_hooks = hook;
|
|
||||||
|
|
||||||
return hook->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t libafl_add_post_syscall_hook(target_ulong (*callback)(
|
|
||||||
uint64_t data, target_ulong ret, int sys_num,
|
|
||||||
target_ulong arg0, target_ulong arg1,
|
|
||||||
target_ulong arg2, target_ulong arg3,
|
|
||||||
target_ulong arg4, target_ulong arg5,
|
|
||||||
target_ulong arg6, target_ulong arg7),
|
|
||||||
uint64_t data)
|
|
||||||
{
|
|
||||||
struct libafl_post_syscall_hook* hook = calloc(sizeof(struct libafl_post_syscall_hook), 1);
|
|
||||||
hook->callback = callback;
|
|
||||||
hook->data = data;
|
|
||||||
hook->num = libafl_post_syscall_hooks_num++;
|
|
||||||
hook->next = libafl_post_syscall_hooks;
|
|
||||||
libafl_post_syscall_hooks = hook;
|
|
||||||
|
|
||||||
return hook->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
GEN_REMOVE_HOOK1(pre_syscall)
|
|
||||||
GEN_REMOVE_HOOK1(post_syscall)
|
|
||||||
|
|
||||||
struct libafl_new_thread_hook* libafl_new_thread_hooks;
|
|
||||||
size_t libafl_new_thread_hooks_num = 0;
|
|
||||||
|
|
||||||
size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data, uint32_t tid),
|
|
||||||
uint64_t data) {
|
|
||||||
struct libafl_new_thread_hook* hook = calloc(sizeof(struct libafl_new_thread_hook), 1);
|
|
||||||
hook->callback = callback;
|
|
||||||
hook->data = data;
|
|
||||||
hook->num = libafl_new_thread_hooks_num++;
|
|
||||||
hook->next = libafl_new_thread_hooks;
|
|
||||||
libafl_new_thread_hooks = hook;
|
|
||||||
|
|
||||||
return hook->num;
|
|
||||||
}
|
|
||||||
|
|
||||||
GEN_REMOVE_HOOK1(new_thread)
|
|
||||||
|
|
||||||
#if TARGET_LONG_BITS == 32
|
#if TARGET_LONG_BITS == 32
|
||||||
#define SHADOW_BASE (0x20000000)
|
#define SHADOW_BASE (0x20000000)
|
||||||
#elif TARGET_LONG_BITS == 64
|
#elif TARGET_LONG_BITS == 64
|
||||||
@ -729,15 +53,12 @@ void libafl_tcg_gen_asan(TCGTemp * addr, size_t size)
|
|||||||
* detects an invalid access, we will instead attempt to write the value
|
* detects an invalid access, we will instead attempt to write the value
|
||||||
* at 0x0.
|
* at 0x0.
|
||||||
*/
|
*/
|
||||||
tcg_gen_movcond_tl(TCG_COND_EQ, test_addr,
|
tcg_gen_movcond_tl(TCG_COND_EQ, test_addr, shadow_val, tcg_constant_tl(0),
|
||||||
shadow_val, tcg_constant_tl(0),
|
|
||||||
shadow_addr, tcg_constant_tl(0));
|
shadow_addr, tcg_constant_tl(0));
|
||||||
|
|
||||||
if (size < 8)
|
if (size < 8) {
|
||||||
{
|
tcg_gen_movcond_tl(TCG_COND_GE, test_addr, k, shadow_val, test_addr,
|
||||||
tcg_gen_movcond_tl(TCG_COND_GE, test_addr,
|
shadow_addr);
|
||||||
k, shadow_val,
|
|
||||||
test_addr, shadow_addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tcg_gen_tl_ptr(test_ptr, test_addr);
|
tcg_gen_tl_ptr(test_ptr, test_addr);
|
||||||
|
41
libafl/hooks/cpu_run.c
Normal file
41
libafl/hooks/cpu_run.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "libafl/hooks/cpu_run.h"
|
||||||
|
|
||||||
|
static struct libafl_cpu_run_hook* libafl_cpu_run_hooks = NULL;
|
||||||
|
static size_t libafl_cpu_run_hooks_num = 0;
|
||||||
|
|
||||||
|
GEN_REMOVE_HOOK1(cpu_run)
|
||||||
|
|
||||||
|
size_t libafl_hook_cpu_run_add(libafl_cpu_run_fn pre_cpu_run,
|
||||||
|
libafl_cpu_run_fn post_cpu_run, uint64_t data)
|
||||||
|
{
|
||||||
|
struct libafl_cpu_run_hook* hook =
|
||||||
|
calloc(sizeof(struct libafl_cpu_run_hook), 1);
|
||||||
|
|
||||||
|
hook->pre_cpu_run = pre_cpu_run;
|
||||||
|
hook->post_cpu_run = post_cpu_run;
|
||||||
|
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_cpu_run_hooks_num++;
|
||||||
|
hook->next = libafl_cpu_run_hooks;
|
||||||
|
libafl_cpu_run_hooks = hook;
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_hook_cpu_run_pre_exec(CPUState* cpu)
|
||||||
|
{
|
||||||
|
struct libafl_cpu_run_hook* h = libafl_cpu_run_hooks;
|
||||||
|
while (h) {
|
||||||
|
h->pre_cpu_run(h->data, cpu);
|
||||||
|
h = h->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_hook_cpu_run_post_exec(CPUState* cpu)
|
||||||
|
{
|
||||||
|
struct libafl_cpu_run_hook* h = libafl_cpu_run_hooks;
|
||||||
|
while (h) {
|
||||||
|
h->post_cpu_run(h->data, cpu);
|
||||||
|
h = h->next;
|
||||||
|
}
|
||||||
|
}
|
89
libafl/hooks/syscall.c
Normal file
89
libafl/hooks/syscall.c
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "libafl/hooks/syscall.h"
|
||||||
|
|
||||||
|
struct libafl_pre_syscall_hook* libafl_pre_syscall_hooks;
|
||||||
|
size_t libafl_pre_syscall_hooks_num = 0;
|
||||||
|
|
||||||
|
struct libafl_post_syscall_hook* libafl_post_syscall_hooks;
|
||||||
|
size_t libafl_post_syscall_hooks_num = 0;
|
||||||
|
|
||||||
|
GEN_REMOVE_HOOK1(pre_syscall)
|
||||||
|
GEN_REMOVE_HOOK1(post_syscall)
|
||||||
|
|
||||||
|
size_t libafl_add_pre_syscall_hook(
|
||||||
|
struct syshook_ret (*callback)(uint64_t data, int sys_num,
|
||||||
|
target_ulong arg0, target_ulong arg1,
|
||||||
|
target_ulong arg2, target_ulong arg3,
|
||||||
|
target_ulong arg4, target_ulong arg5,
|
||||||
|
target_ulong arg6, target_ulong arg7),
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
struct libafl_pre_syscall_hook* hook =
|
||||||
|
calloc(sizeof(struct libafl_pre_syscall_hook), 1);
|
||||||
|
hook->callback = callback;
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_pre_syscall_hooks_num++;
|
||||||
|
hook->next = libafl_pre_syscall_hooks;
|
||||||
|
libafl_pre_syscall_hooks = hook;
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t libafl_add_post_syscall_hook(
|
||||||
|
target_ulong (*callback)(uint64_t data, target_ulong ret, int sys_num,
|
||||||
|
target_ulong arg0, target_ulong arg1,
|
||||||
|
target_ulong arg2, target_ulong arg3,
|
||||||
|
target_ulong arg4, target_ulong arg5,
|
||||||
|
target_ulong arg6, target_ulong arg7),
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
struct libafl_post_syscall_hook* hook =
|
||||||
|
calloc(sizeof(struct libafl_post_syscall_hook), 1);
|
||||||
|
hook->callback = callback;
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_post_syscall_hooks_num++;
|
||||||
|
hook->next = libafl_post_syscall_hooks;
|
||||||
|
libafl_post_syscall_hooks = hook;
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libafl_hook_syscall_pre_run(CPUArchState* env, int num, abi_long arg1,
|
||||||
|
abi_long arg2, abi_long arg3, abi_long arg4,
|
||||||
|
abi_long arg5, abi_long arg6, abi_long arg7,
|
||||||
|
abi_long arg8, abi_long* ret)
|
||||||
|
{
|
||||||
|
bool skip_syscall = false;
|
||||||
|
|
||||||
|
struct libafl_pre_syscall_hook* h = libafl_pre_syscall_hooks;
|
||||||
|
while (h) {
|
||||||
|
// no null check
|
||||||
|
struct syshook_ret hook_ret = h->callback(
|
||||||
|
h->data, num, (target_ulong)arg1, (target_ulong)arg2,
|
||||||
|
(target_ulong)arg3, (target_ulong)arg4, (target_ulong)arg5,
|
||||||
|
(target_ulong)arg6, (target_ulong)arg7, (target_ulong)arg8);
|
||||||
|
if (hook_ret.skip_syscall) {
|
||||||
|
skip_syscall = true;
|
||||||
|
*ret = (abi_ulong)hook_ret.retval;
|
||||||
|
}
|
||||||
|
h = h->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return skip_syscall;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_hook_syscall_post_run(int num, abi_long arg1, abi_long arg2,
|
||||||
|
abi_long arg3, abi_long arg4, abi_long arg5,
|
||||||
|
abi_long arg6, abi_long arg7, abi_long arg8,
|
||||||
|
abi_long* ret)
|
||||||
|
{
|
||||||
|
struct libafl_post_syscall_hook* p = libafl_post_syscall_hooks;
|
||||||
|
while (p) {
|
||||||
|
// no null check
|
||||||
|
*ret = (abi_ulong)p->callback(p->data, (target_ulong)*ret, num,
|
||||||
|
(target_ulong)arg1, (target_ulong)arg2,
|
||||||
|
(target_ulong)arg3, (target_ulong)arg4,
|
||||||
|
(target_ulong)arg5, (target_ulong)arg6,
|
||||||
|
(target_ulong)arg7, (target_ulong)arg8);
|
||||||
|
p = p->next;
|
||||||
|
}
|
||||||
|
}
|
47
libafl/hooks/tcg/backdoor.c
Normal file
47
libafl/hooks/tcg/backdoor.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "libafl/hooks/tcg/backdoor.h"
|
||||||
|
|
||||||
|
struct libafl_backdoor_hook* libafl_backdoor_hooks;
|
||||||
|
size_t libafl_backdoor_hooks_num = 0;
|
||||||
|
|
||||||
|
static TCGHelperInfo libafl_exec_backdoor_hook_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_backdoor_hook",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(env, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3)};
|
||||||
|
|
||||||
|
GEN_REMOVE_HOOK(backdoor)
|
||||||
|
|
||||||
|
size_t libafl_add_backdoor_hook(void (*exec)(uint64_t data, CPUArchState* cpu,
|
||||||
|
target_ulong pc),
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
struct libafl_backdoor_hook* hook =
|
||||||
|
calloc(sizeof(struct libafl_backdoor_hook), 1);
|
||||||
|
// hook->exec = exec;
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_backdoor_hooks_num++;
|
||||||
|
hook->next = libafl_backdoor_hooks;
|
||||||
|
libafl_backdoor_hooks = hook;
|
||||||
|
|
||||||
|
memcpy(&hook->helper_info, &libafl_exec_backdoor_hook_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info.func = exec;
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_qemu_hook_backdoor_run(vaddr pc_next)
|
||||||
|
{
|
||||||
|
struct libafl_backdoor_hook* bhk = libafl_backdoor_hooks;
|
||||||
|
while (bhk) {
|
||||||
|
TCGv_i64 tmp0 = tcg_constant_i64(bhk->data);
|
||||||
|
TCGv tmp2 = tcg_constant_tl(pc_next);
|
||||||
|
TCGTemp* args[3] = {tcgv_i64_temp(tmp0), tcgv_ptr_temp(tcg_env),
|
||||||
|
tcgv_tl_temp(tmp2)};
|
||||||
|
|
||||||
|
tcg_gen_callN(&bhk->helper_info, NULL, args);
|
||||||
|
|
||||||
|
bhk = bhk->next;
|
||||||
|
}
|
||||||
|
}
|
89
libafl/hooks/tcg/block.c
Normal file
89
libafl/hooks/tcg/block.c
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "libafl/hooks/tcg/block.h"
|
||||||
|
|
||||||
|
struct libafl_block_hook* libafl_block_hooks;
|
||||||
|
size_t libafl_block_hooks_num = 0;
|
||||||
|
|
||||||
|
static TCGHelperInfo libafl_exec_block_hook_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_block_hook",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask =
|
||||||
|
dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2)};
|
||||||
|
|
||||||
|
GEN_REMOVE_HOOK(block)
|
||||||
|
|
||||||
|
size_t libafl_add_block_hook(uint64_t (*gen)(uint64_t data, target_ulong pc),
|
||||||
|
void (*post_gen)(uint64_t data, target_ulong pc,
|
||||||
|
target_ulong block_length),
|
||||||
|
void (*exec)(uint64_t data, uint64_t id),
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
CPUState* cpu;
|
||||||
|
CPU_FOREACH(cpu) { tb_flush(cpu); }
|
||||||
|
|
||||||
|
struct libafl_block_hook* hook =
|
||||||
|
calloc(sizeof(struct libafl_block_hook), 1);
|
||||||
|
hook->gen = gen;
|
||||||
|
hook->post_gen = post_gen;
|
||||||
|
// hook->exec = exec;
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_block_hooks_num++;
|
||||||
|
hook->next = libafl_block_hooks;
|
||||||
|
libafl_block_hooks = hook;
|
||||||
|
|
||||||
|
if (exec) {
|
||||||
|
memcpy(&hook->helper_info, &libafl_exec_block_hook_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info.func = exec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libafl_qemu_block_hook_set_jit(size_t num,
|
||||||
|
size_t (*jit)(uint64_t data, uint64_t id))
|
||||||
|
{
|
||||||
|
struct libafl_block_hook* hk = libafl_block_hooks;
|
||||||
|
while (hk) {
|
||||||
|
if (hk->num == num) {
|
||||||
|
hk->jit = jit;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
hk = hk->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_qemu_hook_block_post_gen(TranslationBlock* tb, vaddr pc)
|
||||||
|
{
|
||||||
|
struct libafl_block_hook* hook = libafl_block_hooks;
|
||||||
|
while (hook) {
|
||||||
|
if (hook->post_gen)
|
||||||
|
hook->post_gen(hook->data, pc, tb->size);
|
||||||
|
hook = hook->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_qemu_hook_block_run(target_ulong pc)
|
||||||
|
{
|
||||||
|
struct libafl_block_hook* hook = libafl_block_hooks;
|
||||||
|
|
||||||
|
while (hook) {
|
||||||
|
uint64_t cur_id = 0;
|
||||||
|
if (hook->gen)
|
||||||
|
cur_id = hook->gen(hook->data, pc);
|
||||||
|
if (cur_id != (uint64_t)-1 && hook->helper_info.func) {
|
||||||
|
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
||||||
|
TCGv_i64 tmp1 = tcg_constant_i64(cur_id);
|
||||||
|
TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1)};
|
||||||
|
tcg_gen_callN(&hook->helper_info, NULL, tmp2);
|
||||||
|
tcg_temp_free_i64(tmp0);
|
||||||
|
tcg_temp_free_i64(tmp1);
|
||||||
|
}
|
||||||
|
if (cur_id != (uint64_t)-1 && hook->jit) {
|
||||||
|
hook->jit(hook->data, cur_id);
|
||||||
|
}
|
||||||
|
hook = hook->next;
|
||||||
|
}
|
||||||
|
}
|
129
libafl/hooks/tcg/cmp.c
Normal file
129
libafl/hooks/tcg/cmp.c
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include "libafl/hooks/tcg/cmp.h"
|
||||||
|
|
||||||
|
struct libafl_cmp_hook* libafl_cmp_hooks;
|
||||||
|
size_t libafl_cmp_hooks_num = 0;
|
||||||
|
|
||||||
|
static TCGHelperInfo libafl_exec_cmp_hook1_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_cmp_hook1",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4)};
|
||||||
|
static TCGHelperInfo libafl_exec_cmp_hook2_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_cmp_hook2",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4)};
|
||||||
|
static TCGHelperInfo libafl_exec_cmp_hook4_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_cmp_hook4",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(tl, 4)};
|
||||||
|
static TCGHelperInfo libafl_exec_cmp_hook8_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_cmp_hook8",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(i64, 3) |
|
||||||
|
dh_typemask(i64, 4)};
|
||||||
|
|
||||||
|
GEN_REMOVE_HOOK(cmp)
|
||||||
|
|
||||||
|
size_t libafl_add_cmp_hook(
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong pc, size_t size),
|
||||||
|
void (*exec1)(uint64_t data, uint64_t id, uint8_t v0, uint8_t v1),
|
||||||
|
void (*exec2)(uint64_t data, uint64_t id, uint16_t v0, uint16_t v1),
|
||||||
|
void (*exec4)(uint64_t data, uint64_t id, uint32_t v0, uint32_t v1),
|
||||||
|
void (*exec8)(uint64_t data, uint64_t id, uint64_t v0, uint64_t v1),
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
CPUState* cpu;
|
||||||
|
CPU_FOREACH(cpu) { tb_flush(cpu); }
|
||||||
|
|
||||||
|
struct libafl_cmp_hook* hook = calloc(sizeof(struct libafl_cmp_hook), 1);
|
||||||
|
hook->gen = gen;
|
||||||
|
/*hook->exec1 = exec1;
|
||||||
|
hook->exec2 = exec2;
|
||||||
|
hook->exec4 = exec4;
|
||||||
|
hook->exec8 = exec8;*/
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_cmp_hooks_num++;
|
||||||
|
hook->next = libafl_cmp_hooks;
|
||||||
|
libafl_cmp_hooks = hook;
|
||||||
|
|
||||||
|
if (exec1) {
|
||||||
|
memcpy(&hook->helper_info1, &libafl_exec_cmp_hook1_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info1.func = exec1;
|
||||||
|
}
|
||||||
|
if (exec2) {
|
||||||
|
memcpy(&hook->helper_info2, &libafl_exec_cmp_hook2_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info2.func = exec2;
|
||||||
|
}
|
||||||
|
if (exec4) {
|
||||||
|
memcpy(&hook->helper_info4, &libafl_exec_cmp_hook4_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info4.func = exec4;
|
||||||
|
}
|
||||||
|
if (exec8) {
|
||||||
|
memcpy(&hook->helper_info8, &libafl_exec_cmp_hook8_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info8.func = exec8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_gen_cmp(target_ulong pc, TCGv op0, TCGv op1, MemOp ot)
|
||||||
|
{
|
||||||
|
size_t size = 0;
|
||||||
|
switch (ot & MO_SIZE) {
|
||||||
|
case MO_64:
|
||||||
|
size = 8;
|
||||||
|
break;
|
||||||
|
case MO_32:
|
||||||
|
size = 4;
|
||||||
|
break;
|
||||||
|
case MO_16:
|
||||||
|
size = 2;
|
||||||
|
break;
|
||||||
|
case MO_8:
|
||||||
|
size = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct libafl_cmp_hook* hook = libafl_cmp_hooks;
|
||||||
|
while (hook) {
|
||||||
|
uint64_t cur_id = 0;
|
||||||
|
if (hook->gen)
|
||||||
|
cur_id = hook->gen(hook->data, pc, size);
|
||||||
|
TCGHelperInfo* info = NULL;
|
||||||
|
if (size == 1 && hook->helper_info1.func)
|
||||||
|
info = &hook->helper_info1;
|
||||||
|
else if (size == 2 && hook->helper_info2.func)
|
||||||
|
info = &hook->helper_info2;
|
||||||
|
else if (size == 4 && hook->helper_info4.func)
|
||||||
|
info = &hook->helper_info4;
|
||||||
|
else if (size == 8 && hook->helper_info8.func)
|
||||||
|
info = &hook->helper_info8;
|
||||||
|
if (cur_id != (uint64_t)-1 && info) {
|
||||||
|
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
||||||
|
TCGv_i64 tmp1 = tcg_constant_i64(cur_id);
|
||||||
|
TCGTemp* tmp2[4] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1),
|
||||||
|
#if TARGET_LONG_BITS == 32
|
||||||
|
tcgv_i32_temp(op0), tcgv_i32_temp(op1)};
|
||||||
|
#else
|
||||||
|
tcgv_i64_temp(op0), tcgv_i64_temp(op1)};
|
||||||
|
#endif
|
||||||
|
tcg_gen_callN(info, NULL, tmp2);
|
||||||
|
tcg_temp_free_i64(tmp0);
|
||||||
|
tcg_temp_free_i64(tmp1);
|
||||||
|
}
|
||||||
|
hook = hook->next;
|
||||||
|
}
|
||||||
|
}
|
89
libafl/hooks/tcg/edge.c
Normal file
89
libafl/hooks/tcg/edge.c
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#include "libafl/hooks/tcg/edge.h"
|
||||||
|
|
||||||
|
struct libafl_edge_hook* libafl_edge_hooks;
|
||||||
|
size_t libafl_edge_hooks_num = 0;
|
||||||
|
|
||||||
|
static TCGHelperInfo libafl_exec_edge_hook_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_edge_hook",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask =
|
||||||
|
dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(i64, 2)};
|
||||||
|
|
||||||
|
GEN_REMOVE_HOOK(edge)
|
||||||
|
|
||||||
|
size_t libafl_add_edge_hook(uint64_t (*gen)(uint64_t data, target_ulong src,
|
||||||
|
target_ulong dst),
|
||||||
|
void (*exec)(uint64_t data, uint64_t id),
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
CPUState* cpu;
|
||||||
|
CPU_FOREACH(cpu) { tb_flush(cpu); }
|
||||||
|
|
||||||
|
struct libafl_edge_hook* hook = calloc(sizeof(struct libafl_edge_hook), 1);
|
||||||
|
hook->gen = gen;
|
||||||
|
// hook->exec = exec;
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_edge_hooks_num++;
|
||||||
|
hook->next = libafl_edge_hooks;
|
||||||
|
libafl_edge_hooks = hook;
|
||||||
|
|
||||||
|
if (exec) {
|
||||||
|
memcpy(&hook->helper_info, &libafl_exec_edge_hook_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info.func = exec;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libafl_qemu_edge_hook_set_jit(size_t num,
|
||||||
|
size_t (*jit)(uint64_t data, uint64_t id))
|
||||||
|
{
|
||||||
|
struct libafl_edge_hook* hk = libafl_edge_hooks;
|
||||||
|
while (hk) {
|
||||||
|
if (hk->num == num) {
|
||||||
|
hk->jit = jit;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
hk = hk->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libafl_qemu_hook_edge_gen(target_ulong src_block, target_ulong dst_block)
|
||||||
|
{
|
||||||
|
struct libafl_edge_hook* hook = libafl_edge_hooks;
|
||||||
|
bool no_exec_hook = true;
|
||||||
|
while (hook) {
|
||||||
|
hook->cur_id = 0;
|
||||||
|
if (hook->gen)
|
||||||
|
hook->cur_id = hook->gen(hook->data, src_block, dst_block);
|
||||||
|
if (hook->cur_id != (uint64_t)-1 &&
|
||||||
|
(hook->helper_info.func || hook->jit))
|
||||||
|
no_exec_hook = false;
|
||||||
|
hook = hook->next;
|
||||||
|
}
|
||||||
|
return no_exec_hook;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_qemu_hook_edge_run(void)
|
||||||
|
{
|
||||||
|
struct libafl_edge_hook* hook = libafl_edge_hooks;
|
||||||
|
|
||||||
|
while (hook) {
|
||||||
|
if (hook->cur_id != (uint64_t)-1 && hook->helper_info.func) {
|
||||||
|
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
||||||
|
TCGv_i64 tmp1 = tcg_constant_i64(hook->cur_id);
|
||||||
|
TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1)};
|
||||||
|
tcg_gen_callN(&hook->helper_info, NULL, tmp2);
|
||||||
|
tcg_temp_free_i64(tmp0);
|
||||||
|
tcg_temp_free_i64(tmp1);
|
||||||
|
}
|
||||||
|
if (hook->cur_id != (uint64_t)-1 && hook->jit) {
|
||||||
|
hook->jit(hook->data, hook->cur_id);
|
||||||
|
}
|
||||||
|
hook = hook->next;
|
||||||
|
}
|
||||||
|
}
|
133
libafl/hooks/tcg/instruction.c
Normal file
133
libafl/hooks/tcg/instruction.c
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#include "libafl/hooks/tcg/instruction.h"
|
||||||
|
|
||||||
|
target_ulong libafl_gen_cur_pc;
|
||||||
|
struct libafl_instruction_hook*
|
||||||
|
libafl_qemu_instruction_hooks[LIBAFL_TABLES_SIZE];
|
||||||
|
size_t libafl_qemu_hooks_num = 0;
|
||||||
|
|
||||||
|
size_t libafl_qemu_add_instruction_hooks(target_ulong pc,
|
||||||
|
void (*callback)(uint64_t data,
|
||||||
|
target_ulong pc),
|
||||||
|
uint64_t
|
||||||
|
|
||||||
|
data,
|
||||||
|
int invalidate)
|
||||||
|
{
|
||||||
|
CPUState* cpu;
|
||||||
|
|
||||||
|
if (invalidate) {
|
||||||
|
CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, pc); }
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t idx = LIBAFL_TABLES_HASH(pc);
|
||||||
|
|
||||||
|
struct libafl_instruction_hook* hk =
|
||||||
|
calloc(sizeof(struct libafl_instruction_hook), 1);
|
||||||
|
hk->addr = pc;
|
||||||
|
// hk->callback = callback;
|
||||||
|
hk->data = data;
|
||||||
|
hk->helper_info.func = callback;
|
||||||
|
hk->helper_info.name = "libafl_instruction_hook";
|
||||||
|
hk->helper_info.flags = dh_callflag(void);
|
||||||
|
hk->helper_info.typemask =
|
||||||
|
dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(tl, 2);
|
||||||
|
// TODO check for overflow
|
||||||
|
hk->num = libafl_qemu_hooks_num++;
|
||||||
|
hk->next = libafl_qemu_instruction_hooks[idx];
|
||||||
|
libafl_qemu_instruction_hooks[idx] = hk;
|
||||||
|
return hk->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t libafl_qemu_remove_instruction_hooks_at(target_ulong addr,
|
||||||
|
int invalidate)
|
||||||
|
{
|
||||||
|
CPUState* cpu;
|
||||||
|
size_t r = 0;
|
||||||
|
|
||||||
|
size_t idx = LIBAFL_TABLES_HASH(addr);
|
||||||
|
struct libafl_instruction_hook** hk = &libafl_qemu_instruction_hooks[idx];
|
||||||
|
while (*hk) {
|
||||||
|
if ((*hk)->addr == addr) {
|
||||||
|
if (invalidate) {
|
||||||
|
CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, addr); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void* tmp = *hk;
|
||||||
|
*hk = (*hk)->next;
|
||||||
|
free(tmp);
|
||||||
|
r++;
|
||||||
|
} else {
|
||||||
|
hk = &(*hk)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libafl_qemu_remove_instruction_hook(size_t num, int invalidate)
|
||||||
|
{
|
||||||
|
CPUState* cpu;
|
||||||
|
size_t idx;
|
||||||
|
|
||||||
|
for (idx = 0; idx < LIBAFL_TABLES_SIZE; ++idx) {
|
||||||
|
struct libafl_instruction_hook** hk =
|
||||||
|
&libafl_qemu_instruction_hooks[idx];
|
||||||
|
while (*hk) {
|
||||||
|
if ((*hk)->num == num) {
|
||||||
|
if (invalidate) {
|
||||||
|
CPU_FOREACH(cpu)
|
||||||
|
{
|
||||||
|
libafl_breakpoint_invalidate(cpu, (*hk)->addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* tmp = *hk;
|
||||||
|
*hk = (*hk)->next;
|
||||||
|
free(tmp);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
hk = &(*hk)->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct libafl_instruction_hook*
|
||||||
|
libafl_search_instruction_hook(target_ulong addr)
|
||||||
|
{
|
||||||
|
size_t idx = LIBAFL_TABLES_HASH(addr);
|
||||||
|
|
||||||
|
struct libafl_instruction_hook* hk = libafl_qemu_instruction_hooks[idx];
|
||||||
|
while (hk) {
|
||||||
|
if (hk->addr == addr) {
|
||||||
|
return hk;
|
||||||
|
}
|
||||||
|
hk = hk->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_qemu_hook_instruction_run(vaddr pc_next)
|
||||||
|
{
|
||||||
|
struct libafl_instruction_hook* hk =
|
||||||
|
libafl_search_instruction_hook(pc_next);
|
||||||
|
if (hk) {
|
||||||
|
TCGv_i64 tmp0 = tcg_constant_i64(hk->data);
|
||||||
|
#if TARGET_LONG_BITS == 32
|
||||||
|
TCGv_i32 tmp1 = tcg_constant_i32(pc_next);
|
||||||
|
TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i32_temp(tmp1)};
|
||||||
|
#else
|
||||||
|
TCGv_i64 tmp1 = tcg_constant_i64(pc_next);
|
||||||
|
TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1)};
|
||||||
|
#endif
|
||||||
|
// tcg_gen_callN(hk->callback, NULL, 2, tmp2);
|
||||||
|
tcg_gen_callN(&hk->helper_info, NULL, tmp2);
|
||||||
|
#if TARGET_LONG_BITS == 32
|
||||||
|
tcg_temp_free_i32(tmp1);
|
||||||
|
#else
|
||||||
|
tcg_temp_free_i64(tmp1);
|
||||||
|
#endif
|
||||||
|
tcg_temp_free_i64(tmp0);
|
||||||
|
}
|
||||||
|
}
|
240
libafl/hooks/tcg/read_write.c
Normal file
240
libafl/hooks/tcg/read_write.c
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
#include "libafl/hooks/tcg/read_write.h"
|
||||||
|
|
||||||
|
struct libafl_rw_hook* libafl_read_hooks;
|
||||||
|
size_t libafl_read_hooks_num = 0;
|
||||||
|
|
||||||
|
struct libafl_rw_hook* libafl_write_hooks;
|
||||||
|
size_t libafl_write_hooks_num = 0;
|
||||||
|
|
||||||
|
static TCGHelperInfo libafl_exec_read_hook1_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_read_hook1",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3)};
|
||||||
|
static TCGHelperInfo libafl_exec_read_hook2_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_read_hook2",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3)};
|
||||||
|
static TCGHelperInfo libafl_exec_read_hook4_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_read_hook4",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3)};
|
||||||
|
static TCGHelperInfo libafl_exec_read_hook8_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_read_hook8",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3)};
|
||||||
|
static TCGHelperInfo libafl_exec_read_hookN_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_read_hookN",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(i64, 4)};
|
||||||
|
static TCGHelperInfo libafl_exec_write_hook1_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_write_hook1",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3)};
|
||||||
|
static TCGHelperInfo libafl_exec_write_hook2_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_write_hook2",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3)};
|
||||||
|
static TCGHelperInfo libafl_exec_write_hook4_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_write_hook4",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3)};
|
||||||
|
static TCGHelperInfo libafl_exec_write_hook8_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_write_hook8",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3)};
|
||||||
|
static TCGHelperInfo libafl_exec_write_hookN_info = {
|
||||||
|
.func = NULL,
|
||||||
|
.name = "libafl_exec_write_hookN",
|
||||||
|
.flags = dh_callflag(void),
|
||||||
|
.typemask = dh_typemask(void, 0) | dh_typemask(i64, 1) |
|
||||||
|
dh_typemask(i64, 2) | dh_typemask(tl, 3) | dh_typemask(i64, 4)};
|
||||||
|
|
||||||
|
GEN_REMOVE_HOOK(read)
|
||||||
|
|
||||||
|
GEN_REMOVE_HOOK(write)
|
||||||
|
|
||||||
|
size_t libafl_add_read_hook(
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi),
|
||||||
|
void (*exec1)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec2)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec4)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec8)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size),
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
CPUState* cpu;
|
||||||
|
CPU_FOREACH(cpu) { tb_flush(cpu); }
|
||||||
|
|
||||||
|
struct libafl_rw_hook* hook = calloc(sizeof(struct libafl_rw_hook), 1);
|
||||||
|
hook->gen = gen;
|
||||||
|
/*hook->exec1 = exec1;
|
||||||
|
hook->exec2 = exec2;
|
||||||
|
hook->exec4 = exec4;
|
||||||
|
hook->exec8 = exec8;
|
||||||
|
hook->execN = execN;*/
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_read_hooks_num++;
|
||||||
|
hook->next = libafl_read_hooks;
|
||||||
|
libafl_read_hooks = hook;
|
||||||
|
|
||||||
|
if (exec1) {
|
||||||
|
memcpy(&hook->helper_info1, &libafl_exec_read_hook1_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info1.func = exec1;
|
||||||
|
}
|
||||||
|
if (exec2) {
|
||||||
|
memcpy(&hook->helper_info2, &libafl_exec_read_hook2_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info2.func = exec2;
|
||||||
|
}
|
||||||
|
if (exec4) {
|
||||||
|
memcpy(&hook->helper_info4, &libafl_exec_read_hook4_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info4.func = exec4;
|
||||||
|
}
|
||||||
|
if (exec8) {
|
||||||
|
memcpy(&hook->helper_info8, &libafl_exec_read_hook8_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info8.func = exec8;
|
||||||
|
}
|
||||||
|
if (execN) {
|
||||||
|
memcpy(&hook->helper_infoN, &libafl_exec_read_hookN_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_infoN.func = execN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t libafl_add_write_hook(
|
||||||
|
uint64_t (*gen)(uint64_t data, target_ulong pc, TCGTemp* addr, MemOpIdx oi),
|
||||||
|
void (*exec1)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec2)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec4)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*exec8)(uint64_t data, uint64_t id, target_ulong addr),
|
||||||
|
void (*execN)(uint64_t data, uint64_t id, target_ulong addr, size_t size),
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
CPUState* cpu;
|
||||||
|
CPU_FOREACH(cpu) { tb_flush(cpu); }
|
||||||
|
|
||||||
|
struct libafl_rw_hook* hook = calloc(sizeof(struct libafl_rw_hook), 1);
|
||||||
|
hook->gen = gen;
|
||||||
|
/*hook->exec1 = exec1;
|
||||||
|
hook->exec2 = exec2;
|
||||||
|
hook->exec4 = exec4;
|
||||||
|
hook->exec8 = exec8;
|
||||||
|
hook->execN = execN;*/
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_write_hooks_num++;
|
||||||
|
hook->next = libafl_write_hooks;
|
||||||
|
libafl_write_hooks = hook;
|
||||||
|
|
||||||
|
if (exec1) {
|
||||||
|
memcpy(&hook->helper_info1, &libafl_exec_write_hook1_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info1.func = exec1;
|
||||||
|
}
|
||||||
|
if (exec2) {
|
||||||
|
memcpy(&hook->helper_info2, &libafl_exec_write_hook2_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info2.func = exec2;
|
||||||
|
}
|
||||||
|
if (exec4) {
|
||||||
|
memcpy(&hook->helper_info4, &libafl_exec_write_hook4_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info4.func = exec4;
|
||||||
|
}
|
||||||
|
if (exec8) {
|
||||||
|
memcpy(&hook->helper_info8, &libafl_exec_write_hook8_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_info8.func = exec8;
|
||||||
|
}
|
||||||
|
if (execN) {
|
||||||
|
memcpy(&hook->helper_infoN, &libafl_exec_write_hookN_info,
|
||||||
|
sizeof(TCGHelperInfo));
|
||||||
|
hook->helper_infoN.func = execN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void libafl_gen_rw(TCGTemp* addr, MemOpIdx oi,
|
||||||
|
struct libafl_rw_hook* hook)
|
||||||
|
{
|
||||||
|
size_t size = memop_size(get_memop(oi));
|
||||||
|
|
||||||
|
while (hook) {
|
||||||
|
uint64_t cur_id = 0;
|
||||||
|
if (hook->gen)
|
||||||
|
cur_id = hook->gen(hook->data, libafl_gen_cur_pc, addr, oi);
|
||||||
|
TCGHelperInfo* info = NULL;
|
||||||
|
if (size == 1 && hook->helper_info1.func)
|
||||||
|
info = &hook->helper_info1;
|
||||||
|
else if (size == 2 && hook->helper_info2.func)
|
||||||
|
info = &hook->helper_info2;
|
||||||
|
else if (size == 4 && hook->helper_info4.func)
|
||||||
|
info = &hook->helper_info4;
|
||||||
|
else if (size == 8 && hook->helper_info8.func)
|
||||||
|
info = &hook->helper_info8;
|
||||||
|
if (cur_id != (uint64_t)-1) {
|
||||||
|
if (info) {
|
||||||
|
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
||||||
|
TCGv_i64 tmp1 = tcg_constant_i64(cur_id);
|
||||||
|
TCGTemp* tmp2[3] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1),
|
||||||
|
addr};
|
||||||
|
tcg_gen_callN(info, NULL, tmp2);
|
||||||
|
tcg_temp_free_i64(tmp0);
|
||||||
|
tcg_temp_free_i64(tmp1);
|
||||||
|
} else if (hook->helper_infoN.func) {
|
||||||
|
TCGv_i64 tmp0 = tcg_constant_i64(hook->data);
|
||||||
|
TCGv_i64 tmp1 = tcg_constant_i64(cur_id);
|
||||||
|
TCGv tmp2 = tcg_constant_tl(size);
|
||||||
|
TCGTemp* tmp3[4] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1),
|
||||||
|
addr,
|
||||||
|
#if TARGET_LONG_BITS == 32
|
||||||
|
tcgv_i32_temp(tmp2)};
|
||||||
|
#else
|
||||||
|
tcgv_i64_temp(tmp2)};
|
||||||
|
#endif
|
||||||
|
tcg_gen_callN(&hook->helper_infoN, NULL, tmp3);
|
||||||
|
tcg_temp_free_i64(tmp0);
|
||||||
|
tcg_temp_free_i64(tmp1);
|
||||||
|
#if TARGET_LONG_BITS == 32
|
||||||
|
tcg_temp_free_i32(tmp2);
|
||||||
|
#else
|
||||||
|
tcg_temp_free_i64(tmp2);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hook = hook->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_gen_read(TCGTemp* addr, MemOpIdx oi)
|
||||||
|
{
|
||||||
|
libafl_gen_rw(addr, oi, libafl_read_hooks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void libafl_gen_write(TCGTemp* addr, MemOpIdx oi)
|
||||||
|
{
|
||||||
|
libafl_gen_rw(addr, oi, libafl_write_hooks);
|
||||||
|
}
|
47
libafl/hooks/thread.c
Normal file
47
libafl/hooks/thread.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "libafl/hooks/thread.h"
|
||||||
|
|
||||||
|
#include <linux/unistd.h>
|
||||||
|
|
||||||
|
extern __thread CPUArchState* libafl_qemu_env;
|
||||||
|
|
||||||
|
struct libafl_new_thread_hook* libafl_new_thread_hooks;
|
||||||
|
size_t libafl_new_thread_hooks_num = 0;
|
||||||
|
|
||||||
|
GEN_REMOVE_HOOK1(new_thread)
|
||||||
|
|
||||||
|
size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data,
|
||||||
|
CPUArchState* env,
|
||||||
|
uint32_t tid),
|
||||||
|
uint64_t data)
|
||||||
|
{
|
||||||
|
struct libafl_new_thread_hook* hook =
|
||||||
|
calloc(sizeof(struct libafl_new_thread_hook), 1);
|
||||||
|
hook->callback = callback;
|
||||||
|
hook->data = data;
|
||||||
|
hook->num = libafl_new_thread_hooks_num++;
|
||||||
|
hook->next = libafl_new_thread_hooks;
|
||||||
|
libafl_new_thread_hooks = hook;
|
||||||
|
|
||||||
|
return hook->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libafl_hook_new_thread_run(CPUArchState* env)
|
||||||
|
{
|
||||||
|
libafl_qemu_env = env;
|
||||||
|
|
||||||
|
if (libafl_new_thread_hooks) {
|
||||||
|
bool continue_execution = true;
|
||||||
|
int tid = gettid();
|
||||||
|
|
||||||
|
struct libafl_new_thread_hook* h = libafl_new_thread_hooks;
|
||||||
|
while (h) {
|
||||||
|
continue_execution =
|
||||||
|
h->callback(h->data, env, tid) && continue_execution;
|
||||||
|
h = h->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return continue_execution;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
13
libafl/jit.c
13
libafl/jit.c
@ -1,4 +1,5 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "qapi/error.h"
|
#include "qapi/error.h"
|
||||||
|
|
||||||
#include "exec/exec-all.h"
|
#include "exec/exec-all.h"
|
||||||
@ -28,7 +29,8 @@ pub extern "C" fn trace_edge_single(id: u64, _data: u64) {
|
|||||||
uint8_t __afl_area_ptr_local[65536] __attribute__((weak));
|
uint8_t __afl_area_ptr_local[65536] __attribute__((weak));
|
||||||
size_t __afl_map_size __attribute__((weak));
|
size_t __afl_map_size __attribute__((weak));
|
||||||
|
|
||||||
size_t libafl_jit_trace_edge_hitcount(uint64_t data, uint64_t id) {
|
size_t libafl_jit_trace_edge_hitcount(uint64_t data, uint64_t id)
|
||||||
|
{
|
||||||
TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local);
|
TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local);
|
||||||
TCGv_i32 counter = tcg_temp_new_i32();
|
TCGv_i32 counter = tcg_temp_new_i32();
|
||||||
tcg_gen_ld8u_i32(counter, map_ptr, (tcg_target_long)id);
|
tcg_gen_ld8u_i32(counter, map_ptr, (tcg_target_long)id);
|
||||||
@ -37,7 +39,8 @@ size_t libafl_jit_trace_edge_hitcount(uint64_t data, uint64_t id) {
|
|||||||
return 3; // # instructions
|
return 3; // # instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t libafl_jit_trace_edge_single(uint64_t data, uint64_t id) {
|
size_t libafl_jit_trace_edge_single(uint64_t data, uint64_t id)
|
||||||
|
{
|
||||||
TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local);
|
TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local);
|
||||||
TCGv_i32 counter = tcg_temp_new_i32();
|
TCGv_i32 counter = tcg_temp_new_i32();
|
||||||
tcg_gen_movi_i32(counter, 1);
|
tcg_gen_movi_i32(counter, 1);
|
||||||
@ -47,7 +50,8 @@ size_t libafl_jit_trace_edge_single(uint64_t data, uint64_t id) {
|
|||||||
|
|
||||||
uint64_t __prev_loc = 0;
|
uint64_t __prev_loc = 0;
|
||||||
|
|
||||||
size_t libafl_jit_trace_block_hitcount(uint64_t data, uint64_t id) {
|
size_t libafl_jit_trace_block_hitcount(uint64_t data, uint64_t id)
|
||||||
|
{
|
||||||
TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local);
|
TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local);
|
||||||
TCGv_ptr prev_loc_ptr = tcg_constant_ptr(&__prev_loc);
|
TCGv_ptr prev_loc_ptr = tcg_constant_ptr(&__prev_loc);
|
||||||
|
|
||||||
@ -75,7 +79,8 @@ size_t libafl_jit_trace_block_hitcount(uint64_t data, uint64_t id) {
|
|||||||
return 11; // # instructions
|
return 11; // # instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t libafl_jit_trace_block_single(uint64_t data, uint64_t id) {
|
size_t libafl_jit_trace_block_single(uint64_t data, uint64_t id)
|
||||||
|
{
|
||||||
TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local);
|
TCGv_ptr map_ptr = tcg_constant_ptr(__afl_area_ptr_local);
|
||||||
TCGv_ptr prev_loc_ptr = tcg_constant_ptr(&__prev_loc);
|
TCGv_ptr prev_loc_ptr = tcg_constant_ptr(&__prev_loc);
|
||||||
|
|
||||||
|
@ -3,6 +3,17 @@ specific_ss.add(files(
|
|||||||
'hook.c',
|
'hook.c',
|
||||||
'jit.c',
|
'jit.c',
|
||||||
'utils.c',
|
'utils.c',
|
||||||
|
|
||||||
|
# TCG-related hooks
|
||||||
|
'hooks/tcg/backdoor.c',
|
||||||
|
'hooks/tcg/block.c',
|
||||||
|
'hooks/tcg/cmp.c',
|
||||||
|
'hooks/tcg/edge.c',
|
||||||
|
'hooks/tcg/instruction.c',
|
||||||
|
'hooks/tcg/read_write.c',
|
||||||
|
|
||||||
|
# General hooks
|
||||||
|
'hooks/cpu_run.c',
|
||||||
))
|
))
|
||||||
|
|
||||||
specific_ss.add(when : 'CONFIG_SOFTMMU', if_true : [files(
|
specific_ss.add(when : 'CONFIG_SOFTMMU', if_true : [files(
|
||||||
@ -12,3 +23,8 @@ specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files(
|
|||||||
'syx-snapshot/channel-buffer-writeback.c',
|
'syx-snapshot/channel-buffer-writeback.c',
|
||||||
)])
|
)])
|
||||||
|
|
||||||
|
specific_ss.add(when : 'CONFIG_USER_ONLY', if_true : [files(
|
||||||
|
'hooks/syscall.c',
|
||||||
|
'hooks/thread.c',
|
||||||
|
)])
|
||||||
|
|
||||||
|
@ -4,13 +4,18 @@
|
|||||||
#include "libafl/syx-misc.h"
|
#include "libafl/syx-misc.h"
|
||||||
#include "libafl/syx-snapshot/channel-buffer-writeback.h"
|
#include "libafl/syx-snapshot/channel-buffer-writeback.h"
|
||||||
|
|
||||||
QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uint8_t* writeback_buf, size_t writeback_buf_capacity, size_t* writeback_buf_usage) {
|
QIOChannelBufferWriteback*
|
||||||
|
qio_channel_buffer_writeback_new(size_t capacity, uint8_t* writeback_buf,
|
||||||
|
size_t writeback_buf_capacity,
|
||||||
|
size_t* writeback_buf_usage)
|
||||||
|
{
|
||||||
assert(writeback_buf != NULL);
|
assert(writeback_buf != NULL);
|
||||||
assert(writeback_buf_usage != NULL);
|
assert(writeback_buf_usage != NULL);
|
||||||
|
|
||||||
QIOChannelBufferWriteback* ioc;
|
QIOChannelBufferWriteback* ioc;
|
||||||
|
|
||||||
ioc = QIO_CHANNEL_BUFFER_WRITEBACK(object_new(TYPE_QIO_CHANNEL_BUFFER_WRITEBACK));
|
ioc = QIO_CHANNEL_BUFFER_WRITEBACK(
|
||||||
|
object_new(TYPE_QIO_CHANNEL_BUFFER_WRITEBACK));
|
||||||
|
|
||||||
assert(writeback_buf != NULL);
|
assert(writeback_buf != NULL);
|
||||||
|
|
||||||
@ -27,8 +32,10 @@ QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uin
|
|||||||
return ioc;
|
return ioc;
|
||||||
}
|
}
|
||||||
|
|
||||||
QIOChannelBufferWriteback*
|
QIOChannelBufferWriteback* qio_channel_buffer_writeback_new_external(
|
||||||
qio_channel_buffer_writeback_new_external(uint8_t* buf, size_t capacity, size_t usage, uint8_t* writeback_buf, size_t writeback_buf_capacity, size_t* writeback_buf_usage) {
|
uint8_t* buf, size_t capacity, size_t usage, uint8_t* writeback_buf,
|
||||||
|
size_t writeback_buf_capacity, size_t* writeback_buf_usage)
|
||||||
|
{
|
||||||
assert(buf != NULL);
|
assert(buf != NULL);
|
||||||
assert(usage <= capacity);
|
assert(usage <= capacity);
|
||||||
assert(writeback_buf != NULL);
|
assert(writeback_buf != NULL);
|
||||||
@ -36,7 +43,8 @@ qio_channel_buffer_writeback_new_external(uint8_t* buf, size_t capacity, size_t
|
|||||||
|
|
||||||
QIOChannelBufferWriteback* ioc;
|
QIOChannelBufferWriteback* ioc;
|
||||||
|
|
||||||
ioc = QIO_CHANNEL_BUFFER_WRITEBACK(object_new(TYPE_QIO_CHANNEL_BUFFER_WRITEBACK));
|
ioc = QIO_CHANNEL_BUFFER_WRITEBACK(
|
||||||
|
object_new(TYPE_QIO_CHANNEL_BUFFER_WRITEBACK));
|
||||||
|
|
||||||
assert(writeback_buf != NULL);
|
assert(writeback_buf != NULL);
|
||||||
|
|
||||||
@ -52,8 +60,8 @@ qio_channel_buffer_writeback_new_external(uint8_t* buf, size_t capacity, size_t
|
|||||||
return ioc;
|
return ioc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qio_channel_buffer_writeback_finalize(Object* obj)
|
||||||
static void qio_channel_buffer_writeback_finalize(Object *obj) {
|
{
|
||||||
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(obj);
|
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(obj);
|
||||||
|
|
||||||
assert(bwioc->writeback_buf_capacity >= bwioc->usage);
|
assert(bwioc->writeback_buf_capacity >= bwioc->usage);
|
||||||
@ -70,13 +78,10 @@ static void qio_channel_buffer_writeback_finalize(Object *obj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ssize_t qio_channel_buffer_writeback_readv(QIOChannel* ioc,
|
static ssize_t qio_channel_buffer_writeback_readv(QIOChannel* ioc,
|
||||||
const struct iovec* iov,
|
const struct iovec* iov,
|
||||||
size_t niov,
|
size_t niov, int** fds,
|
||||||
int **fds,
|
size_t* nfds, int flags,
|
||||||
size_t *nfds,
|
|
||||||
int flags,
|
|
||||||
Error** errp)
|
Error** errp)
|
||||||
{
|
{
|
||||||
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||||
@ -104,10 +109,8 @@ static ssize_t qio_channel_buffer_writeback_readv(QIOChannel *ioc,
|
|||||||
|
|
||||||
static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc,
|
static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc,
|
||||||
const struct iovec* iov,
|
const struct iovec* iov,
|
||||||
size_t niov,
|
size_t niov, int* fds,
|
||||||
int *fds,
|
size_t nfds, int flags,
|
||||||
size_t nfds,
|
|
||||||
int flags,
|
|
||||||
Error** errp)
|
Error** errp)
|
||||||
{
|
{
|
||||||
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||||
@ -123,9 +126,7 @@ static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc,
|
|||||||
assert(bwioc->offset <= bwioc->usage);
|
assert(bwioc->offset <= bwioc->usage);
|
||||||
|
|
||||||
for (i = 0; i < niov; i++) {
|
for (i = 0; i < niov; i++) {
|
||||||
memcpy(bwioc->data + bwioc->offset,
|
memcpy(bwioc->data + bwioc->offset, iov[i].iov_base, iov[i].iov_len);
|
||||||
iov[i].iov_base,
|
|
||||||
iov[i].iov_len);
|
|
||||||
bwioc->offset += iov[i].iov_len;
|
bwioc->offset += iov[i].iov_len;
|
||||||
bwioc->usage += iov[i].iov_len;
|
bwioc->usage += iov[i].iov_len;
|
||||||
ret += iov[i].iov_len;
|
ret += iov[i].iov_len;
|
||||||
@ -134,17 +135,16 @@ static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qio_channel_buffer_writeback_set_blocking(QIOChannel *ioc G_GNUC_UNUSED,
|
static int
|
||||||
|
qio_channel_buffer_writeback_set_blocking(QIOChannel* ioc G_GNUC_UNUSED,
|
||||||
bool enabled G_GNUC_UNUSED,
|
bool enabled G_GNUC_UNUSED,
|
||||||
Error** errp G_GNUC_UNUSED)
|
Error** errp G_GNUC_UNUSED)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static off_t qio_channel_buffer_writeback_seek(QIOChannel *ioc,
|
static off_t qio_channel_buffer_writeback_seek(QIOChannel* ioc, off_t offset,
|
||||||
off_t offset,
|
int whence, Error** errp)
|
||||||
int whence,
|
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||||
off_t new_pos;
|
off_t new_pos;
|
||||||
@ -170,8 +170,7 @@ static off_t qio_channel_buffer_writeback_seek(QIOChannel *ioc,
|
|||||||
return new_pos;
|
return new_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qio_channel_buffer_writeback_close(QIOChannel *ioc,
|
static int qio_channel_buffer_writeback_close(QIOChannel* ioc, Error** errp)
|
||||||
Error **errp)
|
|
||||||
{
|
{
|
||||||
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||||
|
|
||||||
@ -198,42 +197,40 @@ struct QIOChannelBufferWritebackSource {
|
|||||||
GIOCondition condition;
|
GIOCondition condition;
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean
|
static gboolean qio_channel_buffer_writeback_source_prepare(GSource* source,
|
||||||
qio_channel_buffer_writeback_source_prepare(GSource *source,
|
|
||||||
gint* timeout)
|
gint* timeout)
|
||||||
{
|
{
|
||||||
QIOChannelBufferWritebackSource *bsource = (QIOChannelBufferWritebackSource *)source;
|
QIOChannelBufferWritebackSource* bsource =
|
||||||
|
(QIOChannelBufferWritebackSource*)source;
|
||||||
|
|
||||||
*timeout = -1;
|
*timeout = -1;
|
||||||
|
|
||||||
return (G_IO_IN | G_IO_OUT) & bsource->condition;
|
return (G_IO_IN | G_IO_OUT) & bsource->condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean qio_channel_buffer_writeback_source_check(GSource* source)
|
||||||
qio_channel_buffer_writeback_source_check(GSource *source)
|
|
||||||
{
|
{
|
||||||
QIOChannelBufferWritebackSource *bsource = (QIOChannelBufferWritebackSource *)source;
|
QIOChannelBufferWritebackSource* bsource =
|
||||||
|
(QIOChannelBufferWritebackSource*)source;
|
||||||
|
|
||||||
return (G_IO_IN | G_IO_OUT) & bsource->condition;
|
return (G_IO_IN | G_IO_OUT) & bsource->condition;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean qio_channel_buffer_writeback_source_dispatch(
|
||||||
qio_channel_buffer_writeback_source_dispatch(GSource *source,
|
GSource* source, GSourceFunc callback, gpointer user_data)
|
||||||
GSourceFunc callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
{
|
||||||
QIOChannelFunc func = (QIOChannelFunc)callback;
|
QIOChannelFunc func = (QIOChannelFunc)callback;
|
||||||
QIOChannelBufferWritebackSource *bsource = (QIOChannelBufferWritebackSource *)source;
|
QIOChannelBufferWritebackSource* bsource =
|
||||||
|
(QIOChannelBufferWritebackSource*)source;
|
||||||
|
|
||||||
return (*func)(QIO_CHANNEL(bsource->bioc),
|
return (*func)(QIO_CHANNEL(bsource->bioc),
|
||||||
((G_IO_IN | G_IO_OUT) & bsource->condition),
|
((G_IO_IN | G_IO_OUT) & bsource->condition), user_data);
|
||||||
user_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void qio_channel_buffer_writeback_source_finalize(GSource* source)
|
||||||
qio_channel_buffer_writeback_source_finalize(GSource *source)
|
|
||||||
{
|
{
|
||||||
QIOChannelBufferWritebackSource *ssource = (QIOChannelBufferWritebackSource *)source;
|
QIOChannelBufferWritebackSource* ssource =
|
||||||
|
(QIOChannelBufferWritebackSource*)source;
|
||||||
|
|
||||||
object_unref(OBJECT(ssource->bioc));
|
object_unref(OBJECT(ssource->bioc));
|
||||||
}
|
}
|
||||||
@ -242,10 +239,10 @@ GSourceFuncs qio_channel_buffer_writeback_source_funcs = {
|
|||||||
qio_channel_buffer_writeback_source_prepare,
|
qio_channel_buffer_writeback_source_prepare,
|
||||||
qio_channel_buffer_writeback_source_check,
|
qio_channel_buffer_writeback_source_check,
|
||||||
qio_channel_buffer_writeback_source_dispatch,
|
qio_channel_buffer_writeback_source_dispatch,
|
||||||
qio_channel_buffer_writeback_source_finalize
|
qio_channel_buffer_writeback_source_finalize};
|
||||||
};
|
|
||||||
|
|
||||||
static GSource *qio_channel_buffer_writeback_create_watch(QIOChannel *ioc,
|
static GSource*
|
||||||
|
qio_channel_buffer_writeback_create_watch(QIOChannel* ioc,
|
||||||
GIOCondition condition)
|
GIOCondition condition)
|
||||||
{
|
{
|
||||||
QIOChannelBufferWriteback* bioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
QIOChannelBufferWriteback* bioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||||
@ -264,7 +261,8 @@ static GSource *qio_channel_buffer_writeback_create_watch(QIOChannel *ioc,
|
|||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void qio_channel_buffer_writeback_class_init(ObjectClass *klass,
|
static void
|
||||||
|
qio_channel_buffer_writeback_class_init(ObjectClass* klass,
|
||||||
void* class_data G_GNUC_UNUSED)
|
void* class_data G_GNUC_UNUSED)
|
||||||
{
|
{
|
||||||
QIOChannelClass* ioc_klass = QIO_CHANNEL_CLASS(klass);
|
QIOChannelClass* ioc_klass = QIO_CHANNEL_CLASS(klass);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "migration/qemu-file.h"
|
#include "migration/qemu-file.h"
|
||||||
#include "io/channel-buffer.h"
|
#include "io/channel-buffer.h"
|
||||||
#include "migration/vmstate.h"
|
#include "migration/vmstate.h"
|
||||||
@ -17,11 +18,13 @@ extern SaveState savevm_state;
|
|||||||
extern int vmstate_save(QEMUFile* f, SaveStateEntry* se, JSONWriter* vmdesc);
|
extern int vmstate_save(QEMUFile* f, SaveStateEntry* se, JSONWriter* vmdesc);
|
||||||
|
|
||||||
// iothread must be locked
|
// iothread must be locked
|
||||||
DeviceSaveState* device_save_all(void) {
|
DeviceSaveState* device_save_all(void)
|
||||||
|
{
|
||||||
return device_save_kind(DEVICE_SNAPSHOT_ALL, NULL);
|
return device_save_kind(DEVICE_SNAPSHOT_ALL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_in_list(char* str, char** list) {
|
static int is_in_list(char* str, char** list)
|
||||||
|
{
|
||||||
while (*list) {
|
while (*list) {
|
||||||
if (!strcmp(str, *list)) {
|
if (!strcmp(str, *list)) {
|
||||||
return 1;
|
return 1;
|
||||||
@ -31,19 +34,23 @@ static int is_in_list(char* str, char** list) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names) {
|
DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names)
|
||||||
|
{
|
||||||
DeviceSaveState* dss = g_new0(DeviceSaveState, 1);
|
DeviceSaveState* dss = g_new0(DeviceSaveState, 1);
|
||||||
SaveStateEntry* se;
|
SaveStateEntry* se;
|
||||||
|
|
||||||
dss->kind = DEVICE_SAVE_KIND_FULL;
|
dss->kind = DEVICE_SAVE_KIND_FULL;
|
||||||
dss->save_buffer = g_new(uint8_t, QEMU_FILE_RAM_LIMIT);
|
dss->save_buffer = g_new(uint8_t, QEMU_FILE_RAM_LIMIT);
|
||||||
|
|
||||||
QIOChannelBufferWriteback* wbioc = qio_channel_buffer_writeback_new(QEMU_FILE_RAM_LIMIT, dss->save_buffer, QEMU_FILE_RAM_LIMIT, &dss->save_buffer_size);
|
QIOChannelBufferWriteback* wbioc = qio_channel_buffer_writeback_new(
|
||||||
|
QEMU_FILE_RAM_LIMIT, dss->save_buffer, QEMU_FILE_RAM_LIMIT,
|
||||||
|
&dss->save_buffer_size);
|
||||||
QIOChannel* ioc = QIO_CHANNEL(wbioc);
|
QIOChannel* ioc = QIO_CHANNEL(wbioc);
|
||||||
|
|
||||||
QEMUFile* f = qemu_file_new_output(ioc);
|
QEMUFile* f = qemu_file_new_output(ioc);
|
||||||
|
|
||||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
|
QTAILQ_FOREACH(se, &savevm_state.handlers, entry)
|
||||||
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (se->is_ram) {
|
if (se->is_ram) {
|
||||||
@ -84,10 +91,12 @@ DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names) {
|
|||||||
return dss;
|
return dss;
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_restore_all(DeviceSaveState* dss) {
|
void device_restore_all(DeviceSaveState* dss)
|
||||||
|
{
|
||||||
assert(dss->save_buffer != NULL);
|
assert(dss->save_buffer != NULL);
|
||||||
|
|
||||||
QIOChannelBuffer* bioc = qio_channel_buffer_new_external(dss->save_buffer, QEMU_FILE_RAM_LIMIT, dss->save_buffer_size);
|
QIOChannelBuffer* bioc = qio_channel_buffer_new_external(
|
||||||
|
dss->save_buffer, QEMU_FILE_RAM_LIMIT, dss->save_buffer_size);
|
||||||
QIOChannel* ioc = QIO_CHANNEL(bioc);
|
QIOChannel* ioc = QIO_CHANNEL(bioc);
|
||||||
|
|
||||||
QEMUFile* f = qemu_file_new_input(ioc);
|
QEMUFile* f = qemu_file_new_input(ioc);
|
||||||
@ -103,21 +112,19 @@ void device_restore_all(DeviceSaveState* dss) {
|
|||||||
qemu_fclose(f);
|
qemu_fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_free_all(DeviceSaveState* dss) {
|
void device_free_all(DeviceSaveState* dss) { g_free(dss->save_buffer); }
|
||||||
g_free(dss->save_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
char** device_list_all(void) {
|
char** device_list_all(void)
|
||||||
|
{
|
||||||
SaveStateEntry* se;
|
SaveStateEntry* se;
|
||||||
|
|
||||||
size_t size = 1;
|
size_t size = 1;
|
||||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
|
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { size++; }
|
||||||
size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
char** list = malloc(size * sizeof(char*));
|
char** list = malloc(size * sizeof(char*));
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
|
QTAILQ_FOREACH(se, &savevm_state.handlers, entry)
|
||||||
|
{
|
||||||
if (se->is_ram) {
|
if (se->is_ram) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,13 @@ static gchar* g_array_element_ptr(GArray* array, guint position)
|
|||||||
return array->data + position * g_array_get_element_size(array);
|
return array->data + position * g_array_get_element_size(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_cow_cache_push_layer(SyxCowCache* scc, uint64_t chunk_size, uint64_t max_size)
|
void syx_cow_cache_push_layer(SyxCowCache* scc, uint64_t chunk_size,
|
||||||
|
uint64_t max_size)
|
||||||
{
|
{
|
||||||
SyxCowCacheLayer* new_layer = g_new0(SyxCowCacheLayer, 1);
|
SyxCowCacheLayer* new_layer = g_new0(SyxCowCacheLayer, 1);
|
||||||
|
|
||||||
new_layer->cow_cache_devices = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
|
new_layer->cow_cache_devices =
|
||||||
|
g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
|
||||||
new_layer->chunk_size = chunk_size;
|
new_layer->chunk_size = chunk_size;
|
||||||
new_layer->max_nb_chunks = max_size;
|
new_layer->max_nb_chunks = max_size;
|
||||||
|
|
||||||
@ -38,7 +40,8 @@ void syx_cow_cache_pop_layer(SyxCowCache* scc)
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flush_device_layer(gpointer _blk_name_hash, gpointer cache_device, gpointer _user_data)
|
static void flush_device_layer(gpointer _blk_name_hash, gpointer cache_device,
|
||||||
|
gpointer _user_data)
|
||||||
{
|
{
|
||||||
SyxCowCacheDevice* sccd = (SyxCowCacheDevice*)cache_device;
|
SyxCowCacheDevice* sccd = (SyxCowCacheDevice*)cache_device;
|
||||||
|
|
||||||
@ -51,7 +54,8 @@ void syx_cow_cache_flush_highest_layer(SyxCowCache* scc)
|
|||||||
SyxCowCacheLayer* highest_layer = QTAILQ_FIRST(&scc->layers);
|
SyxCowCacheLayer* highest_layer = QTAILQ_FIRST(&scc->layers);
|
||||||
|
|
||||||
// highest_layer->cow_cache_devices
|
// highest_layer->cow_cache_devices
|
||||||
g_hash_table_foreach(highest_layer->cow_cache_devices, flush_device_layer, NULL);
|
g_hash_table_foreach(highest_layer->cow_cache_devices, flush_device_layer,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_cow_cache_move(SyxCowCache* lhs, SyxCowCache** rhs)
|
void syx_cow_cache_move(SyxCowCache* lhs, SyxCowCache** rhs)
|
||||||
@ -61,22 +65,30 @@ void syx_cow_cache_move(SyxCowCache* lhs, SyxCowCache** rhs)
|
|||||||
*rhs = NULL;
|
*rhs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_chunk_from_cache_layer_device(SyxCowCacheDevice* sccd, QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset)
|
static bool read_chunk_from_cache_layer_device(SyxCowCacheDevice* sccd,
|
||||||
|
QEMUIOVector* qiov,
|
||||||
|
size_t qiov_offset,
|
||||||
|
uint64_t blk_offset)
|
||||||
{
|
{
|
||||||
gpointer data_position = NULL;
|
gpointer data_position = NULL;
|
||||||
bool found = g_hash_table_lookup_extended(sccd->positions, GUINT_TO_POINTER(blk_offset), NULL, &data_position);
|
bool found = g_hash_table_lookup_extended(
|
||||||
|
sccd->positions, GUINT_TO_POINTER(blk_offset), NULL, &data_position);
|
||||||
|
|
||||||
// cache hit
|
// cache hit
|
||||||
if (found) {
|
if (found) {
|
||||||
void* data_position_ptr = g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position));
|
void* data_position_ptr =
|
||||||
assert(qemu_iovec_from_buf(qiov, qiov_offset, data_position_ptr, g_array_get_element_size(sccd->data)) == g_array_get_element_size(sccd->data));
|
g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position));
|
||||||
|
assert(qemu_iovec_from_buf(qiov, qiov_offset, data_position_ptr,
|
||||||
|
g_array_get_element_size(sccd->data)) ==
|
||||||
|
g_array_get_element_size(sccd->data));
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
// len must be smaller than nb bytes to next aligned to chunk of blk_offset.
|
// len must be smaller than nb bytes to next aligned to chunk of blk_offset.
|
||||||
// static void write_to_cache_layer_device_unaligned(SyxCowCacheDevice* sccd, QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset, uint64_t len)
|
// static void write_to_cache_layer_device_unaligned(SyxCowCacheDevice* sccd,
|
||||||
|
// QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset, uint64_t len)
|
||||||
// {
|
// {
|
||||||
// const uint64_t chunk_size = g_array_get_element_size(sccd->data);
|
// const uint64_t chunk_size = g_array_get_element_size(sccd->data);
|
||||||
//
|
//
|
||||||
@ -86,45 +98,58 @@ static bool read_chunk_from_cache_layer_device(SyxCowCacheDevice* sccd, QEMUIOVe
|
|||||||
// uint64_t blk_offset_aligned = ROUND_DOWN(blk_offset, chunk_size);
|
// uint64_t blk_offset_aligned = ROUND_DOWN(blk_offset, chunk_size);
|
||||||
//
|
//
|
||||||
// gpointer data_position = NULL;
|
// gpointer data_position = NULL;
|
||||||
// bool found = g_hash_table_lookup_extended(sccd->positions, GUINT_TO_POINTER(blk_offset_aligned), NULL, &data_position);
|
// bool found = g_hash_table_lookup_extended(sccd->positions,
|
||||||
|
// GUINT_TO_POINTER(blk_offset_aligned), NULL, &data_position);
|
||||||
//
|
//
|
||||||
// if (!found) {
|
// if (!found) {
|
||||||
// data_position = GUINT_TO_POINTER(sccd->data->len);
|
// data_position = GUINT_TO_POINTER(sccd->data->len);
|
||||||
// sccd->data = g_array_set_size(sccd->data, sccd->data->len + 1);
|
// sccd->data = g_array_set_size(sccd->data, sccd->data->len + 1);
|
||||||
// g_hash_table_insert(sccd->positions, GUINT_TO_POINTER(blk_offset), data_position);
|
// g_hash_table_insert(sccd->positions, GUINT_TO_POINTER(blk_offset),
|
||||||
|
// data_position);
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// void* data_position_ptr = g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position));
|
// void* data_position_ptr = g_array_element_ptr(sccd->data,
|
||||||
|
// GPOINTER_TO_UINT(data_position));
|
||||||
//
|
//
|
||||||
// assert(qemu_iovec_to_buf(qiov, qiov_offset, data_position_ptr, g_array_get_element_size(sccd->data)) ==
|
// assert(qemu_iovec_to_buf(qiov, qiov_offset, data_position_ptr,
|
||||||
|
// g_array_get_element_size(sccd->data)) ==
|
||||||
// g_array_get_element_size(sccd->data));
|
// g_array_get_element_size(sccd->data));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// cache layer is allocated and all the basic checks are already done.
|
// cache layer is allocated and all the basic checks are already done.
|
||||||
static void write_chunk_to_cache_layer_device(SyxCowCacheDevice* sccd, QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset)
|
static void write_chunk_to_cache_layer_device(SyxCowCacheDevice* sccd,
|
||||||
|
QEMUIOVector* qiov,
|
||||||
|
size_t qiov_offset,
|
||||||
|
uint64_t blk_offset)
|
||||||
{
|
{
|
||||||
const uint64_t chunk_size = g_array_get_element_size(sccd->data);
|
const uint64_t chunk_size = g_array_get_element_size(sccd->data);
|
||||||
|
|
||||||
gpointer data_position = NULL;
|
gpointer data_position = NULL;
|
||||||
bool found = g_hash_table_lookup_extended(sccd->positions, GUINT_TO_POINTER(blk_offset), NULL, &data_position);
|
bool found = g_hash_table_lookup_extended(
|
||||||
|
sccd->positions, GUINT_TO_POINTER(blk_offset), NULL, &data_position);
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
data_position = GUINT_TO_POINTER(sccd->data->len);
|
data_position = GUINT_TO_POINTER(sccd->data->len);
|
||||||
sccd->data = g_array_set_size(sccd->data, sccd->data->len + 1);
|
sccd->data = g_array_set_size(sccd->data, sccd->data->len + 1);
|
||||||
g_hash_table_insert(sccd->positions, GUINT_TO_POINTER(blk_offset), data_position);
|
g_hash_table_insert(sccd->positions, GUINT_TO_POINTER(blk_offset),
|
||||||
|
data_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* data_position_ptr = g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position));
|
void* data_position_ptr =
|
||||||
|
g_array_element_ptr(sccd->data, GPOINTER_TO_UINT(data_position));
|
||||||
|
|
||||||
assert(qemu_iovec_to_buf(qiov, qiov_offset, data_position_ptr, chunk_size) ==
|
assert(qemu_iovec_to_buf(qiov, qiov_offset, data_position_ptr,
|
||||||
chunk_size);
|
chunk_size) == chunk_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_chunk_from_cache_layer(SyxCowCacheLayer* sccl, BlockBackend* blk, QEMUIOVector* qiov, size_t qiov_offset, uint64_t blk_offset)
|
static bool read_chunk_from_cache_layer(SyxCowCacheLayer* sccl,
|
||||||
|
BlockBackend* blk, QEMUIOVector* qiov,
|
||||||
|
size_t qiov_offset, uint64_t blk_offset)
|
||||||
{
|
{
|
||||||
assert(!(qiov->size % sccl->chunk_size));
|
assert(!(qiov->size % sccl->chunk_size));
|
||||||
|
|
||||||
SyxCowCacheDevice* cache_entry = g_hash_table_lookup(sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk)));
|
SyxCowCacheDevice* cache_entry = g_hash_table_lookup(
|
||||||
|
sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk)));
|
||||||
|
|
||||||
// return early if nothing is registered
|
// return early if nothing is registered
|
||||||
if (!cache_entry) {
|
if (!cache_entry) {
|
||||||
@ -134,62 +159,79 @@ static bool read_chunk_from_cache_layer(SyxCowCacheLayer* sccl, BlockBackend* bl
|
|||||||
assert(cache_entry && cache_entry->data);
|
assert(cache_entry && cache_entry->data);
|
||||||
|
|
||||||
// try to read cached pages in current layer if something is registered.
|
// try to read cached pages in current layer if something is registered.
|
||||||
return read_chunk_from_cache_layer_device(cache_entry, qiov, qiov_offset, blk_offset);
|
return read_chunk_from_cache_layer_device(cache_entry, qiov, qiov_offset,
|
||||||
|
blk_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns false if could not write to current layer.
|
// Returns false if could not write to current layer.
|
||||||
static bool write_to_cache_layer(SyxCowCacheLayer* sccl, BlockBackend* blk, int64_t offset, int64_t bytes, QEMUIOVector* qiov)
|
static bool write_to_cache_layer(SyxCowCacheLayer* sccl, BlockBackend* blk,
|
||||||
|
int64_t offset, int64_t bytes,
|
||||||
|
QEMUIOVector* qiov)
|
||||||
{
|
{
|
||||||
if (qiov->size % sccl->chunk_size) {
|
if (qiov->size % sccl->chunk_size) {
|
||||||
// todo: determine if it is worth developing an unaligned access version.
|
// todo: determine if it is worth developing an unaligned access
|
||||||
printf("error: 0x%zx %% 0x%lx == 0x%lx\n", qiov->size, sccl->chunk_size, qiov->size % sccl->chunk_size);
|
// version.
|
||||||
|
printf("error: 0x%zx %% 0x%lx == 0x%lx\n", qiov->size, sccl->chunk_size,
|
||||||
|
qiov->size % sccl->chunk_size);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
SyxCowCacheDevice* cache_entry = g_hash_table_lookup(sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk)));
|
SyxCowCacheDevice* cache_entry = g_hash_table_lookup(
|
||||||
|
sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk)));
|
||||||
|
|
||||||
if (unlikely(!cache_entry)) {
|
if (unlikely(!cache_entry)) {
|
||||||
cache_entry = g_new0(SyxCowCacheDevice, 1);
|
cache_entry = g_new0(SyxCowCacheDevice, 1);
|
||||||
cache_entry->data = g_array_sized_new(false, false, sccl->chunk_size, INITIAL_NB_CHUNKS_PER_DEVICE);
|
cache_entry->data = g_array_sized_new(false, false, sccl->chunk_size,
|
||||||
cache_entry->positions = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
|
INITIAL_NB_CHUNKS_PER_DEVICE);
|
||||||
g_hash_table_insert(sccl->cow_cache_devices, GINT_TO_POINTER(blk_name_hash(blk)), cache_entry);
|
cache_entry->positions =
|
||||||
|
g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL);
|
||||||
|
g_hash_table_insert(sccl->cow_cache_devices,
|
||||||
|
GINT_TO_POINTER(blk_name_hash(blk)), cache_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(cache_entry && cache_entry->data);
|
assert(cache_entry && cache_entry->data);
|
||||||
|
|
||||||
if (cache_entry->data->len + (qiov->size / sccl->chunk_size) > sccl->max_nb_chunks) {
|
if (cache_entry->data->len + (qiov->size / sccl->chunk_size) >
|
||||||
|
sccl->max_nb_chunks) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write cached page
|
// write cached page
|
||||||
uint64_t blk_offset = offset;
|
uint64_t blk_offset = offset;
|
||||||
size_t qiov_offset = 0;
|
size_t qiov_offset = 0;
|
||||||
for (; qiov_offset < qiov->size; blk_offset += sccl->chunk_size, qiov_offset += sccl->chunk_size) {
|
for (; qiov_offset < qiov->size;
|
||||||
write_chunk_to_cache_layer_device(cache_entry, qiov, qiov_offset, blk_offset);
|
blk_offset += sccl->chunk_size, qiov_offset += sccl->chunk_size) {
|
||||||
|
write_chunk_to_cache_layer_device(cache_entry, qiov, qiov_offset,
|
||||||
|
blk_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t _qiov_offset,
|
void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend* blk,
|
||||||
BdrvRequestFlags flags)
|
int64_t offset, int64_t bytes, QEMUIOVector* qiov,
|
||||||
|
size_t _qiov_offset, BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
SyxCowCacheLayer* layer;
|
SyxCowCacheLayer* layer;
|
||||||
uint64_t blk_offset = offset;
|
uint64_t blk_offset = offset;
|
||||||
size_t qiov_offset = 0;
|
size_t qiov_offset = 0;
|
||||||
uint64_t chunk_size = 0;
|
uint64_t chunk_size = 0;
|
||||||
|
|
||||||
// printf("[%s] Read 0x%zx bytes @addr %lx\n", blk_name(blk), qiov->size, offset);
|
// printf("[%s] Read 0x%zx bytes @addr %lx\n", blk_name(blk), qiov->size,
|
||||||
|
// offset);
|
||||||
|
|
||||||
// First read the backing block device normally.
|
// First read the backing block device normally.
|
||||||
assert(blk_co_preadv(blk, offset, bytes, qiov, flags) >= 0);
|
assert(blk_co_preadv(blk, offset, bytes, qiov, flags) >= 0);
|
||||||
|
|
||||||
// Then fix the chunks that have been read from before.
|
// Then fix the chunks that have been read from before.
|
||||||
if (!QTAILQ_EMPTY(&scc->layers)) {
|
if (!QTAILQ_EMPTY(&scc->layers)) {
|
||||||
for (;qiov_offset < qiov->size; blk_offset += chunk_size, qiov_offset += chunk_size) {
|
for (; qiov_offset < qiov->size;
|
||||||
QTAILQ_FOREACH(layer, &scc->layers, next) {
|
blk_offset += chunk_size, qiov_offset += chunk_size) {
|
||||||
|
QTAILQ_FOREACH(layer, &scc->layers, next)
|
||||||
|
{
|
||||||
chunk_size = layer->chunk_size;
|
chunk_size = layer->chunk_size;
|
||||||
if (read_chunk_from_cache_layer(layer, blk, qiov, qiov_offset, blk_offset)) {
|
if (read_chunk_from_cache_layer(layer, blk, qiov, qiov_offset,
|
||||||
|
blk_offset)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,12 +239,15 @@ void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offse
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool syx_cow_cache_write_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset,
|
bool syx_cow_cache_write_entry(SyxCowCache* scc, BlockBackend* blk,
|
||||||
|
int64_t offset, int64_t bytes,
|
||||||
|
QEMUIOVector* qiov, size_t qiov_offset,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
SyxCowCacheLayer* layer;
|
SyxCowCacheLayer* layer;
|
||||||
|
|
||||||
// printf("[%s] Write 0x%zx bytes @addr %lx\n", blk_name(blk), qiov->size, offset);
|
// printf("[%s] Write 0x%zx bytes @addr %lx\n", blk_name(blk), qiov->size,
|
||||||
|
// offset);
|
||||||
|
|
||||||
layer = QTAILQ_FIRST(&scc->layers);
|
layer = QTAILQ_FIRST(&scc->layers);
|
||||||
if (layer) {
|
if (layer) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "migration/vmstate.h"
|
#include "migration/vmstate.h"
|
||||||
@ -58,29 +59,50 @@ typedef struct SyxSnapshotIncrement {
|
|||||||
GHashTable* rbs_dirty_pages; // hash map: H(rb) -> SyxSnapshotDirtyPageList
|
GHashTable* rbs_dirty_pages; // hash map: H(rb) -> SyxSnapshotDirtyPageList
|
||||||
} SyxSnapshotIncrement;
|
} SyxSnapshotIncrement;
|
||||||
|
|
||||||
|
|
||||||
SyxSnapshotState syx_snapshot_state = {0};
|
SyxSnapshotState syx_snapshot_state = {0};
|
||||||
static MemoryRegion* mr_to_enable = NULL;
|
static MemoryRegion* mr_to_enable = NULL;
|
||||||
|
|
||||||
static void destroy_ramblock_snapshot(gpointer root_snapshot);
|
static void destroy_ramblock_snapshot(gpointer root_snapshot);
|
||||||
|
|
||||||
static void syx_snapshot_dirty_list_flush(SyxSnapshot* snapshot);
|
static void syx_snapshot_dirty_list_flush(SyxSnapshot* snapshot);
|
||||||
|
|
||||||
static void rb_save_dirty_addr_to_table(gpointer offset_within_rb, gpointer unused, gpointer rb_dirty_list_to_page_args_ptr);
|
static void
|
||||||
static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr, gpointer rbs_dirty_pages_ptr);
|
rb_save_dirty_addr_to_table(gpointer offset_within_rb, gpointer unused,
|
||||||
static inline void syx_snapshot_dirty_list_add_internal(RAMBlock* rb, ram_addr_t offset);
|
gpointer rb_dirty_list_to_page_args_ptr);
|
||||||
static void empty_rb_dirty_list(gpointer rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr, gpointer user_data);
|
|
||||||
static void destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_ptr);
|
|
||||||
|
|
||||||
static void root_restore_rb_page(gpointer offset_within_rb, gpointer unused, gpointer root_restore_args_ptr);
|
static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash,
|
||||||
static void root_restore_rb(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr, gpointer snapshot_ptr);
|
gpointer rb_dirty_list_hash_table_ptr,
|
||||||
static void root_restore_check_memory_rb(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr, gpointer snapshot_ptr);
|
gpointer rbs_dirty_pages_ptr);
|
||||||
|
|
||||||
static SyxSnapshotIncrement* syx_snapshot_increment_free(SyxSnapshotIncrement* increment);
|
static inline void syx_snapshot_dirty_list_add_internal(RAMBlock* rb,
|
||||||
|
ram_addr_t offset);
|
||||||
|
|
||||||
|
static void empty_rb_dirty_list(gpointer rb_idstr_hash,
|
||||||
|
gpointer rb_dirty_list_hash_table_ptr,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_ptr);
|
||||||
|
|
||||||
|
static void root_restore_rb_page(gpointer offset_within_rb, gpointer unused,
|
||||||
|
gpointer root_restore_args_ptr);
|
||||||
|
|
||||||
|
static void root_restore_rb(gpointer rb_idstr_hash,
|
||||||
|
gpointer rb_dirty_pages_hash_table_ptr,
|
||||||
|
gpointer snapshot_ptr);
|
||||||
|
|
||||||
|
static void root_restore_check_memory_rb(gpointer rb_idstr_hash,
|
||||||
|
gpointer rb_dirty_pages_hash_table_ptr,
|
||||||
|
gpointer snapshot_ptr);
|
||||||
|
|
||||||
|
static SyxSnapshotIncrement*
|
||||||
|
syx_snapshot_increment_free(SyxSnapshotIncrement* increment);
|
||||||
|
|
||||||
static RAMBlock* ramblock_lookup(gpointer rb_idstr_hash)
|
static RAMBlock* ramblock_lookup(gpointer rb_idstr_hash)
|
||||||
{
|
{
|
||||||
RAMBlock* block;
|
RAMBlock* block;
|
||||||
RAMBLOCK_FOREACH(block) {
|
RAMBLOCK_FOREACH(block)
|
||||||
|
{
|
||||||
if (rb_idstr_hash == GINT_TO_POINTER(block->idstr_hash)) {
|
if (rb_idstr_hash == GINT_TO_POINTER(block->idstr_hash)) {
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
@ -90,7 +112,9 @@ static RAMBlock* ramblock_lookup(gpointer rb_idstr_hash)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Root snapshot API
|
// Root snapshot API
|
||||||
static SyxSnapshotRoot* syx_snapshot_root_new(DeviceSnapshotKind kind, char** devices);
|
static SyxSnapshotRoot* syx_snapshot_root_new(DeviceSnapshotKind kind,
|
||||||
|
char** devices);
|
||||||
|
|
||||||
static void syx_snapshot_root_free(SyxSnapshotRoot* root);
|
static void syx_snapshot_root_free(SyxSnapshotRoot* root);
|
||||||
|
|
||||||
struct rb_dirty_list_to_page_args {
|
struct rb_dirty_list_to_page_args {
|
||||||
@ -120,7 +144,8 @@ struct rb_check_memory_args {
|
|||||||
uint64_t nb_inconsistent_pages; // OUT
|
uint64_t nb_inconsistent_pages; // OUT
|
||||||
};
|
};
|
||||||
|
|
||||||
void syx_snapshot_init(bool cached_bdrvs) {
|
void syx_snapshot_init(bool cached_bdrvs)
|
||||||
|
{
|
||||||
uint64_t page_size = TARGET_PAGE_SIZE;
|
uint64_t page_size = TARGET_PAGE_SIZE;
|
||||||
|
|
||||||
syx_snapshot_state.page_size = page_size;
|
syx_snapshot_state.page_size = page_size;
|
||||||
@ -130,38 +155,40 @@ void syx_snapshot_init(bool cached_bdrvs) {
|
|||||||
|
|
||||||
if (cached_bdrvs) {
|
if (cached_bdrvs) {
|
||||||
syx_snapshot_state.before_fuzz_cache = syx_cow_cache_new();
|
syx_snapshot_state.before_fuzz_cache = syx_cow_cache_new();
|
||||||
syx_cow_cache_push_layer(syx_snapshot_state.before_fuzz_cache, SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE, SYX_SNAPSHOT_COW_CACHE_DEFAULT_MAX_BLOCKS);
|
syx_cow_cache_push_layer(syx_snapshot_state.before_fuzz_cache,
|
||||||
|
SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE,
|
||||||
|
SYX_SNAPSHOT_COW_CACHE_DEFAULT_MAX_BLOCKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
syx_snapshot_state.is_enabled = false;
|
syx_snapshot_state.is_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SyxSnapshot *syx_snapshot_new(bool track, bool is_active_bdrv_cache, DeviceSnapshotKind kind, char **devices) {
|
SyxSnapshot* syx_snapshot_new(bool track, bool is_active_bdrv_cache,
|
||||||
|
DeviceSnapshotKind kind, char** devices)
|
||||||
|
{
|
||||||
SyxSnapshot* snapshot = g_new0(SyxSnapshot, 1);
|
SyxSnapshot* snapshot = g_new0(SyxSnapshot, 1);
|
||||||
|
|
||||||
snapshot->root_snapshot = syx_snapshot_root_new(kind, devices);
|
snapshot->root_snapshot = syx_snapshot_root_new(kind, devices);
|
||||||
snapshot->last_incremental_snapshot = NULL;
|
snapshot->last_incremental_snapshot = NULL;
|
||||||
snapshot->rbs_dirty_list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
|
snapshot->rbs_dirty_list =
|
||||||
|
g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
|
||||||
(GDestroyNotify)g_hash_table_remove_all);
|
(GDestroyNotify)g_hash_table_remove_all);
|
||||||
snapshot->bdrvs_cow_cache = syx_cow_cache_new();
|
snapshot->bdrvs_cow_cache = syx_cow_cache_new();
|
||||||
|
|
||||||
if (is_active_bdrv_cache) {
|
if (is_active_bdrv_cache) {
|
||||||
syx_cow_cache_move(snapshot->bdrvs_cow_cache, &syx_snapshot_state.before_fuzz_cache);
|
syx_cow_cache_move(snapshot->bdrvs_cow_cache,
|
||||||
|
&syx_snapshot_state.before_fuzz_cache);
|
||||||
syx_snapshot_state.active_bdrv_cache_snapshot = snapshot;
|
syx_snapshot_state.active_bdrv_cache_snapshot = snapshot;
|
||||||
} else {
|
} else {
|
||||||
syx_cow_cache_push_layer(snapshot->bdrvs_cow_cache, SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE, SYX_SNAPSHOT_COW_CACHE_DEFAULT_MAX_BLOCKS);
|
syx_cow_cache_push_layer(snapshot->bdrvs_cow_cache,
|
||||||
|
SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE,
|
||||||
|
SYX_SNAPSHOT_COW_CACHE_DEFAULT_MAX_BLOCKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (track) {
|
if (track) {
|
||||||
syx_snapshot_track(&syx_snapshot_state.tracked_snapshots, snapshot);
|
syx_snapshot_track(&syx_snapshot_state.tracked_snapshots, snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_TCG
|
|
||||||
SYX_PRINTF("[Snapshot Creation] Checking snapshot memory consistency\n");
|
|
||||||
g_hash_table_foreach(snapshot->rbs_dirty_list, root_restore_check_memory_rb, snapshot);
|
|
||||||
SYX_PRINTF("[Snapshot Creation] Memory is consistent.\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
syx_snapshot_state.is_enabled = true;
|
syx_snapshot_state.is_enabled = true;
|
||||||
|
|
||||||
return snapshot;
|
return snapshot;
|
||||||
@ -190,20 +217,27 @@ static void destroy_ramblock_snapshot(gpointer root_snapshot)
|
|||||||
g_free(snapshot_rb);
|
g_free(snapshot_rb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SyxSnapshotRoot* syx_snapshot_root_new(DeviceSnapshotKind kind, char **devices) {
|
static SyxSnapshotRoot* syx_snapshot_root_new(DeviceSnapshotKind kind,
|
||||||
|
char** devices)
|
||||||
|
{
|
||||||
SyxSnapshotRoot* root = g_new0(SyxSnapshotRoot, 1);
|
SyxSnapshotRoot* root = g_new0(SyxSnapshotRoot, 1);
|
||||||
|
|
||||||
RAMBlock* block;
|
RAMBlock* block;
|
||||||
RAMBlock* inner_block;
|
RAMBlock* inner_block;
|
||||||
DeviceSaveState* dss = device_save_kind(kind, devices);
|
DeviceSaveState* dss = device_save_kind(kind, devices);
|
||||||
|
|
||||||
root->rbs_snapshot = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, destroy_ramblock_snapshot);
|
root->rbs_snapshot = g_hash_table_new_full(g_direct_hash, g_direct_equal,
|
||||||
|
NULL, destroy_ramblock_snapshot);
|
||||||
root->dss = dss;
|
root->dss = dss;
|
||||||
|
|
||||||
RAMBLOCK_FOREACH(block) {
|
RAMBLOCK_FOREACH(block)
|
||||||
RAMBLOCK_FOREACH(inner_block) {
|
{
|
||||||
if (block != inner_block && inner_block->idstr_hash == block->idstr_hash) {
|
RAMBLOCK_FOREACH(inner_block)
|
||||||
SYX_ERROR("Hash collision detected on RAMBlocks %s and %s, snapshotting will not work correctly.",
|
{
|
||||||
|
if (block != inner_block &&
|
||||||
|
inner_block->idstr_hash == block->idstr_hash) {
|
||||||
|
SYX_ERROR("Hash collision detected on RAMBlocks %s and %s, "
|
||||||
|
"snapshotting will not work correctly.",
|
||||||
inner_block->idstr, block->idstr);
|
inner_block->idstr, block->idstr);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@ -214,31 +248,36 @@ static SyxSnapshotRoot* syx_snapshot_root_new(DeviceSnapshotKind kind, char **de
|
|||||||
snapshot_rb->ram = g_new(uint8_t, block->used_length);
|
snapshot_rb->ram = g_new(uint8_t, block->used_length);
|
||||||
memcpy(snapshot_rb->ram, block->host, block->used_length);
|
memcpy(snapshot_rb->ram, block->host, block->used_length);
|
||||||
|
|
||||||
g_hash_table_insert(root->rbs_snapshot, GINT_TO_POINTER(block->idstr_hash), snapshot_rb);
|
g_hash_table_insert(root->rbs_snapshot,
|
||||||
|
GINT_TO_POINTER(block->idstr_hash), snapshot_rb);
|
||||||
}
|
}
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syx_snapshot_root_free(SyxSnapshotRoot *root) {
|
static void syx_snapshot_root_free(SyxSnapshotRoot* root)
|
||||||
|
{
|
||||||
g_hash_table_destroy(root->rbs_snapshot);
|
g_hash_table_destroy(root->rbs_snapshot);
|
||||||
g_free(root);
|
g_free(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
SyxSnapshotTracker syx_snapshot_tracker_init(void) {
|
SyxSnapshotTracker syx_snapshot_tracker_init(void)
|
||||||
|
{
|
||||||
SyxSnapshotTracker tracker = {
|
SyxSnapshotTracker tracker = {
|
||||||
.length = 0,
|
.length = 0,
|
||||||
.capacity = SYX_SNAPSHOT_LIST_INIT_SIZE,
|
.capacity = SYX_SNAPSHOT_LIST_INIT_SIZE,
|
||||||
.tracked_snapshots = g_new(SyxSnapshot*, SYX_SNAPSHOT_LIST_INIT_SIZE)
|
.tracked_snapshots = g_new(SyxSnapshot*, SYX_SNAPSHOT_LIST_INIT_SIZE)};
|
||||||
};
|
|
||||||
|
|
||||||
return tracker;
|
return tracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_snapshot_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) {
|
void syx_snapshot_track(SyxSnapshotTracker* tracker, SyxSnapshot* snapshot)
|
||||||
|
{
|
||||||
if (tracker->length == tracker->capacity) {
|
if (tracker->length == tracker->capacity) {
|
||||||
tracker->capacity *= SYX_SNAPSHOT_LIST_GROW_FACTOR;
|
tracker->capacity *= SYX_SNAPSHOT_LIST_GROW_FACTOR;
|
||||||
tracker->tracked_snapshots = g_realloc(tracker->tracked_snapshots, tracker->capacity * sizeof(SyxSnapshot *));
|
tracker->tracked_snapshots =
|
||||||
|
g_realloc(tracker->tracked_snapshots,
|
||||||
|
tracker->capacity * sizeof(SyxSnapshot*));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(tracker->length < tracker->capacity);
|
assert(tracker->length < tracker->capacity);
|
||||||
@ -247,11 +286,13 @@ void syx_snapshot_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) {
|
|||||||
tracker->length++;
|
tracker->length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) {
|
void syx_snapshot_stop_track(SyxSnapshotTracker* tracker, SyxSnapshot* snapshot)
|
||||||
|
{
|
||||||
for (uint64_t i = 0; i < tracker->length; ++i) {
|
for (uint64_t i = 0; i < tracker->length; ++i) {
|
||||||
if (tracker->tracked_snapshots[i] == snapshot) {
|
if (tracker->tracked_snapshots[i] == snapshot) {
|
||||||
for (uint64_t j = i + i; j < tracker->length; ++j) {
|
for (uint64_t j = i + i; j < tracker->length; ++j) {
|
||||||
tracker->tracked_snapshots[j - 1] = tracker->tracked_snapshots[j];
|
tracker->tracked_snapshots[j - 1] =
|
||||||
|
tracker->tracked_snapshots[j];
|
||||||
}
|
}
|
||||||
tracker->length--;
|
tracker->length--;
|
||||||
return;
|
return;
|
||||||
@ -262,39 +303,45 @@ void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void rb_save_dirty_addr_to_table(gpointer offset_within_rb,
|
||||||
rb_save_dirty_addr_to_table(gpointer offset_within_rb, gpointer unused, gpointer rb_dirty_list_to_page_args_ptr) {
|
gpointer unused,
|
||||||
|
gpointer rb_dirty_list_to_page_args_ptr)
|
||||||
|
{
|
||||||
struct rb_dirty_list_to_page_args* args = rb_dirty_list_to_page_args_ptr;
|
struct rb_dirty_list_to_page_args* args = rb_dirty_list_to_page_args_ptr;
|
||||||
RAMBlock* rb = args->rb;
|
RAMBlock* rb = args->rb;
|
||||||
SyxSnapshotDirtyPage *dirty_page = &args->dirty_page_list->dirty_pages[*args->table_idx];
|
SyxSnapshotDirtyPage* dirty_page =
|
||||||
|
&args->dirty_page_list->dirty_pages[*args->table_idx];
|
||||||
dirty_page->offset_within_rb = (ram_addr_t)offset_within_rb;
|
dirty_page->offset_within_rb = (ram_addr_t)offset_within_rb;
|
||||||
|
|
||||||
memcpy((gpointer) dirty_page->data, rb->host + (ram_addr_t) offset_within_rb, syx_snapshot_state.page_size);
|
memcpy((gpointer)dirty_page->data, rb->host + (ram_addr_t)offset_within_rb,
|
||||||
|
syx_snapshot_state.page_size);
|
||||||
|
|
||||||
*args->table_idx += 1;
|
*args->table_idx += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr,
|
static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash,
|
||||||
gpointer rbs_dirty_pages_ptr) {
|
gpointer rb_dirty_list_hash_table_ptr,
|
||||||
|
gpointer rbs_dirty_pages_ptr)
|
||||||
|
{
|
||||||
GHashTable* rbs_dirty_pages = rbs_dirty_pages_ptr;
|
GHashTable* rbs_dirty_pages = rbs_dirty_pages_ptr;
|
||||||
GHashTable* rb_dirty_list = rb_dirty_list_hash_table_ptr;
|
GHashTable* rb_dirty_list = rb_dirty_list_hash_table_ptr;
|
||||||
|
|
||||||
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
||||||
|
|
||||||
if (rb) {
|
if (rb) {
|
||||||
SyxSnapshotDirtyPageList *dirty_page_list = g_new(SyxSnapshotDirtyPageList, 1);
|
SyxSnapshotDirtyPageList* dirty_page_list =
|
||||||
|
g_new(SyxSnapshotDirtyPageList, 1);
|
||||||
dirty_page_list->length = g_hash_table_size(rb_dirty_list);
|
dirty_page_list->length = g_hash_table_size(rb_dirty_list);
|
||||||
dirty_page_list->dirty_pages = g_new(SyxSnapshotDirtyPage, dirty_page_list->length);
|
dirty_page_list->dirty_pages =
|
||||||
|
g_new(SyxSnapshotDirtyPage, dirty_page_list->length);
|
||||||
|
|
||||||
uint64_t* ctr = g_new0(uint64_t, 1);
|
uint64_t* ctr = g_new0(uint64_t, 1);
|
||||||
|
|
||||||
struct rb_dirty_list_to_page_args dirty_list_to_page_args = {
|
struct rb_dirty_list_to_page_args dirty_list_to_page_args = {
|
||||||
.rb = rb,
|
.rb = rb, .table_idx = ctr, .dirty_page_list = dirty_page_list};
|
||||||
.table_idx = ctr,
|
|
||||||
.dirty_page_list = dirty_page_list
|
|
||||||
};
|
|
||||||
|
|
||||||
g_hash_table_foreach(rbs_dirty_pages, rb_save_dirty_addr_to_table, &dirty_list_to_page_args);
|
g_hash_table_foreach(rbs_dirty_pages, rb_save_dirty_addr_to_table,
|
||||||
|
&dirty_list_to_page_args);
|
||||||
|
|
||||||
g_free(dirty_list_to_page_args.table_idx);
|
g_free(dirty_list_to_page_args.table_idx);
|
||||||
} else {
|
} else {
|
||||||
@ -302,8 +349,11 @@ static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, gpointer rb_dir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_ptr) {
|
static void
|
||||||
SyxSnapshotDirtyPageList *snapshot_dirty_page_list = snapshot_dirty_page_list_ptr;
|
destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_ptr)
|
||||||
|
{
|
||||||
|
SyxSnapshotDirtyPageList* snapshot_dirty_page_list =
|
||||||
|
snapshot_dirty_page_list_ptr;
|
||||||
|
|
||||||
for (uint64_t i = 0; i < snapshot_dirty_page_list->length; ++i) {
|
for (uint64_t i = 0; i < snapshot_dirty_page_list->length; ++i) {
|
||||||
g_free(snapshot_dirty_page_list->dirty_pages[i].data);
|
g_free(snapshot_dirty_page_list->dirty_pages[i].data);
|
||||||
@ -313,26 +363,32 @@ static void destroy_snapshot_dirty_page_list(gpointer snapshot_dirty_page_list_p
|
|||||||
g_free(snapshot_dirty_page_list);
|
g_free(snapshot_dirty_page_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_snapshot_increment_push(SyxSnapshot *snapshot, DeviceSnapshotKind kind, char **devices) {
|
void syx_snapshot_increment_push(SyxSnapshot* snapshot, DeviceSnapshotKind kind,
|
||||||
|
char** devices)
|
||||||
|
{
|
||||||
SyxSnapshotIncrement* increment = g_new0(SyxSnapshotIncrement, 1);
|
SyxSnapshotIncrement* increment = g_new0(SyxSnapshotIncrement, 1);
|
||||||
increment->parent = snapshot->last_incremental_snapshot;
|
increment->parent = snapshot->last_incremental_snapshot;
|
||||||
snapshot->last_incremental_snapshot = increment;
|
snapshot->last_incremental_snapshot = increment;
|
||||||
|
|
||||||
increment->rbs_dirty_pages = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
|
increment->rbs_dirty_pages = g_hash_table_new_full(
|
||||||
destroy_snapshot_dirty_page_list);
|
g_direct_hash, g_direct_equal, NULL, destroy_snapshot_dirty_page_list);
|
||||||
g_hash_table_foreach(snapshot->rbs_dirty_list, rb_dirty_list_to_dirty_pages, increment->rbs_dirty_pages);
|
g_hash_table_foreach(snapshot->rbs_dirty_list, rb_dirty_list_to_dirty_pages,
|
||||||
|
increment->rbs_dirty_pages);
|
||||||
increment->dss = device_save_kind(kind, devices);
|
increment->dss = device_save_kind(kind, devices);
|
||||||
|
|
||||||
g_hash_table_remove_all(snapshot->rbs_dirty_list);
|
g_hash_table_remove_all(snapshot->rbs_dirty_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SyxSnapshotDirtyPage*
|
static SyxSnapshotDirtyPage*
|
||||||
get_dirty_page_from_addr_rec(SyxSnapshotIncrement *increment, RAMBlock *rb, ram_addr_t offset_within_rb) {
|
get_dirty_page_from_addr_rec(SyxSnapshotIncrement* increment, RAMBlock* rb,
|
||||||
|
ram_addr_t offset_within_rb)
|
||||||
|
{
|
||||||
if (increment == NULL) {
|
if (increment == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SyxSnapshotDirtyPageList *dpl = g_hash_table_lookup(increment->rbs_dirty_pages, GINT_TO_POINTER(rb->idstr_hash));
|
SyxSnapshotDirtyPageList* dpl = g_hash_table_lookup(
|
||||||
|
increment->rbs_dirty_pages, GINT_TO_POINTER(rb->idstr_hash));
|
||||||
|
|
||||||
if (dpl) {
|
if (dpl) {
|
||||||
for (uint64_t i = 0; i < dpl->length; ++i) {
|
for (uint64_t i = 0; i < dpl->length; ++i) {
|
||||||
@ -342,23 +398,27 @@ get_dirty_page_from_addr_rec(SyxSnapshotIncrement *increment, RAMBlock *rb, ram_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_dirty_page_from_addr_rec(increment->parent, rb, offset_within_rb);
|
return get_dirty_page_from_addr_rec(increment->parent, rb,
|
||||||
|
offset_within_rb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void restore_dirty_page_to_increment(gpointer offset_within_rb,
|
||||||
static void restore_dirty_page_to_increment(gpointer offset_within_rb, gpointer _unused, gpointer args_ptr) {
|
gpointer _unused, gpointer args_ptr)
|
||||||
|
{
|
||||||
struct rb_page_increment_restore_args* args = args_ptr;
|
struct rb_page_increment_restore_args* args = args_ptr;
|
||||||
RAMBlock* rb = args->rb;
|
RAMBlock* rb = args->rb;
|
||||||
SyxSnapshot* snapshot = args->snapshot;
|
SyxSnapshot* snapshot = args->snapshot;
|
||||||
SyxSnapshotIncrement* increment = args->increment;
|
SyxSnapshotIncrement* increment = args->increment;
|
||||||
ram_addr_t offset = (ram_addr_t)offset_within_rb;
|
ram_addr_t offset = (ram_addr_t)offset_within_rb;
|
||||||
|
|
||||||
SyxSnapshotDirtyPage *dp = get_dirty_page_from_addr_rec(increment, rb, offset);
|
SyxSnapshotDirtyPage* dp =
|
||||||
|
get_dirty_page_from_addr_rec(increment, rb, offset);
|
||||||
|
|
||||||
if (dp) {
|
if (dp) {
|
||||||
memcpy(rb->host + offset, dp->data, syx_snapshot_state.page_size);
|
memcpy(rb->host + offset, dp->data, syx_snapshot_state.page_size);
|
||||||
} else {
|
} else {
|
||||||
SyxSnapshotRAMBlock *rrb = g_hash_table_lookup(snapshot->root_snapshot->rbs_snapshot,
|
SyxSnapshotRAMBlock* rrb =
|
||||||
|
g_hash_table_lookup(snapshot->root_snapshot->rbs_snapshot,
|
||||||
GINT_TO_POINTER(rb->idstr_hash));
|
GINT_TO_POINTER(rb->idstr_hash));
|
||||||
assert(rrb);
|
assert(rrb);
|
||||||
|
|
||||||
@ -366,30 +426,33 @@ static void restore_dirty_page_to_increment(gpointer offset_within_rb, gpointer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restore_rb_to_increment(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr, gpointer args_ptr) {
|
static void restore_rb_to_increment(gpointer rb_idstr_hash,
|
||||||
|
gpointer rb_dirty_pages_hash_table_ptr,
|
||||||
|
gpointer args_ptr)
|
||||||
|
{
|
||||||
struct rb_increment_restore_args* args = args_ptr;
|
struct rb_increment_restore_args* args = args_ptr;
|
||||||
GHashTable* rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr;
|
GHashTable* rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr;
|
||||||
|
|
||||||
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
||||||
struct rb_page_increment_restore_args page_args = {
|
struct rb_page_increment_restore_args page_args = {
|
||||||
.snapshot = args->snapshot,
|
.snapshot = args->snapshot, .increment = args->increment, .rb = rb};
|
||||||
.increment = args->increment,
|
|
||||||
.rb = rb
|
|
||||||
};
|
|
||||||
|
|
||||||
g_hash_table_foreach(rb_dirty_pages_hash_table, restore_dirty_page_to_increment, &page_args);
|
g_hash_table_foreach(rb_dirty_pages_hash_table,
|
||||||
|
restore_dirty_page_to_increment, &page_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restore_to_increment(SyxSnapshot *snapshot, SyxSnapshotIncrement *increment) {
|
static void restore_to_increment(SyxSnapshot* snapshot,
|
||||||
struct rb_increment_restore_args args = {
|
SyxSnapshotIncrement* increment)
|
||||||
.snapshot = snapshot,
|
{
|
||||||
.increment = increment
|
struct rb_increment_restore_args args = {.snapshot = snapshot,
|
||||||
};
|
.increment = increment};
|
||||||
|
|
||||||
g_hash_table_foreach(snapshot->rbs_dirty_list, restore_rb_to_increment, &args);
|
g_hash_table_foreach(snapshot->rbs_dirty_list, restore_rb_to_increment,
|
||||||
|
&args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_snapshot_increment_pop(SyxSnapshot *snapshot) {
|
void syx_snapshot_increment_pop(SyxSnapshot* snapshot)
|
||||||
|
{
|
||||||
SyxSnapshotIncrement* last_increment = snapshot->last_incremental_snapshot;
|
SyxSnapshotIncrement* last_increment = snapshot->last_incremental_snapshot;
|
||||||
|
|
||||||
device_restore_all(last_increment->dss);
|
device_restore_all(last_increment->dss);
|
||||||
@ -401,7 +464,8 @@ void syx_snapshot_increment_pop(SyxSnapshot *snapshot) {
|
|||||||
syx_snapshot_dirty_list_flush(snapshot);
|
syx_snapshot_dirty_list_flush(snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot) {
|
void syx_snapshot_increment_restore_last(SyxSnapshot* snapshot)
|
||||||
|
{
|
||||||
SyxSnapshotIncrement* last_increment = snapshot->last_incremental_snapshot;
|
SyxSnapshotIncrement* last_increment = snapshot->last_incremental_snapshot;
|
||||||
|
|
||||||
device_restore_all(last_increment->dss);
|
device_restore_all(last_increment->dss);
|
||||||
@ -410,7 +474,9 @@ void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot) {
|
|||||||
syx_snapshot_dirty_list_flush(snapshot);
|
syx_snapshot_dirty_list_flush(snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SyxSnapshotIncrement *syx_snapshot_increment_free(SyxSnapshotIncrement *increment) {
|
static SyxSnapshotIncrement*
|
||||||
|
syx_snapshot_increment_free(SyxSnapshotIncrement* increment)
|
||||||
|
{
|
||||||
SyxSnapshotIncrement* parent_increment = increment->parent;
|
SyxSnapshotIncrement* parent_increment = increment->parent;
|
||||||
g_hash_table_destroy(increment->rbs_dirty_pages);
|
g_hash_table_destroy(increment->rbs_dirty_pages);
|
||||||
device_free_all(increment->dss);
|
device_free_all(increment->dss);
|
||||||
@ -418,43 +484,52 @@ static SyxSnapshotIncrement *syx_snapshot_increment_free(SyxSnapshotIncrement *i
|
|||||||
return parent_increment;
|
return parent_increment;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syx_snapshot_dirty_list_flush(SyxSnapshot *snapshot) {
|
static void syx_snapshot_dirty_list_flush(SyxSnapshot* snapshot)
|
||||||
g_hash_table_foreach(snapshot->rbs_dirty_list, empty_rb_dirty_list, (gpointer) snapshot);
|
{
|
||||||
|
g_hash_table_foreach(snapshot->rbs_dirty_list, empty_rb_dirty_list,
|
||||||
|
(gpointer)snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void syx_snapshot_dirty_list_add_internal(RAMBlock *rb, ram_addr_t offset) {
|
static inline void syx_snapshot_dirty_list_add_internal(RAMBlock* rb,
|
||||||
assert((offset & syx_snapshot_state.page_mask) == offset); // offsets should always be page-aligned.
|
ram_addr_t offset)
|
||||||
|
{
|
||||||
|
assert((offset & syx_snapshot_state.page_mask) ==
|
||||||
|
offset); // offsets should always be page-aligned.
|
||||||
|
|
||||||
for (uint64_t i = 0; i < syx_snapshot_state.tracked_snapshots.length; ++i) {
|
for (uint64_t i = 0; i < syx_snapshot_state.tracked_snapshots.length; ++i) {
|
||||||
SyxSnapshot *snapshot = syx_snapshot_state.tracked_snapshots.tracked_snapshots[i];
|
SyxSnapshot* snapshot =
|
||||||
|
syx_snapshot_state.tracked_snapshots.tracked_snapshots[i];
|
||||||
|
|
||||||
GHashTable *rb_dirty_list = g_hash_table_lookup(snapshot->rbs_dirty_list, GINT_TO_POINTER(rb->idstr_hash));
|
GHashTable* rb_dirty_list = g_hash_table_lookup(
|
||||||
|
snapshot->rbs_dirty_list, GINT_TO_POINTER(rb->idstr_hash));
|
||||||
|
|
||||||
if (unlikely(!rb_dirty_list)) {
|
if (unlikely(!rb_dirty_list)) {
|
||||||
#ifdef SYX_SNAPSHOT_DEBUG
|
#ifdef SYX_SNAPSHOT_DEBUG
|
||||||
printf("rb_dirty_list did not exit, creating...\n");
|
printf("rb_dirty_list did not exit, creating...\n");
|
||||||
#endif
|
#endif
|
||||||
rb_dirty_list = g_hash_table_new(g_direct_hash, g_direct_equal);
|
rb_dirty_list = g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||||
g_hash_table_insert(snapshot->rbs_dirty_list, GINT_TO_POINTER(rb->idstr_hash), rb_dirty_list);
|
g_hash_table_insert(snapshot->rbs_dirty_list,
|
||||||
|
GINT_TO_POINTER(rb->idstr_hash), rb_dirty_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_hash_table_add(rb_dirty_list, GINT_TO_POINTER(offset))) {
|
if (g_hash_table_add(rb_dirty_list, GINT_TO_POINTER(offset))) {
|
||||||
#ifdef SYX_SNAPSHOT_DEBUG
|
#ifdef SYX_SNAPSHOT_DEBUG
|
||||||
SYX_PRINTF("[%s] Marking offset 0x%lx as dirty\n", rb->idstr, offset);
|
SYX_PRINTF("[%s] Marking offset 0x%lx as dirty\n", rb->idstr,
|
||||||
|
offset);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool syx_snapshot_is_enabled(void) {
|
bool syx_snapshot_is_enabled(void) { return syx_snapshot_state.is_enabled; }
|
||||||
return syx_snapshot_state.is_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// TODO: Check if using this method is better for performances.
|
// TODO: Check if using this method is better for performances.
|
||||||
// The implementation is pretty bad, it would be nice to store host addr directly for
|
// The implementation is pretty bad, it would be nice to store host addr
|
||||||
|
directly for
|
||||||
// the memcopy happening later on.
|
// the memcopy happening later on.
|
||||||
__attribute__((target("no-3dnow,no-sse,no-mmx"),no_caller_saved_registers)) void syx_snapshot_dirty_list_add_tcg_target(uint64_t dummy, void* host_addr) {
|
__attribute__((target("no-3dnow,no-sse,no-mmx"),no_caller_saved_registers)) void
|
||||||
|
syx_snapshot_dirty_list_add_tcg_target(uint64_t dummy, void* host_addr) {
|
||||||
// early check to know whether we should log the page access or not
|
// early check to know whether we should log the page access or not
|
||||||
if (!syx_snapshot_is_enabled()) {
|
if (!syx_snapshot_is_enabled()) {
|
||||||
return;
|
return;
|
||||||
@ -472,7 +547,8 @@ __attribute__((target("no-3dnow,no-sse,no-mmx"),no_caller_saved_registers)) void
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// host_addr should be page-aligned.
|
// host_addr should be page-aligned.
|
||||||
void syx_snapshot_dirty_list_add_hostaddr(void *host_addr) {
|
void syx_snapshot_dirty_list_add_hostaddr(void* host_addr)
|
||||||
|
{
|
||||||
// early check to know whether we should log the page access or not
|
// early check to know whether we should log the page access or not
|
||||||
if (!syx_snapshot_is_enabled()) {
|
if (!syx_snapshot_is_enabled()) {
|
||||||
return;
|
return;
|
||||||
@ -492,7 +568,8 @@ void syx_snapshot_dirty_list_add_hostaddr(void *host_addr) {
|
|||||||
syx_snapshot_dirty_list_add_internal(rb, offset);
|
syx_snapshot_dirty_list_add_internal(rb, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_snapshot_dirty_list_add_hostaddr_range(void *host_addr, uint64_t len) {
|
void syx_snapshot_dirty_list_add_hostaddr_range(void* host_addr, uint64_t len)
|
||||||
|
{
|
||||||
// early check to know whether we should log the page access or not
|
// early check to know whether we should log the page access or not
|
||||||
if (!syx_snapshot_is_enabled()) {
|
if (!syx_snapshot_is_enabled()) {
|
||||||
return;
|
return;
|
||||||
@ -501,7 +578,8 @@ void syx_snapshot_dirty_list_add_hostaddr_range(void *host_addr, uint64_t len) {
|
|||||||
assert(len < INT64_MAX);
|
assert(len < INT64_MAX);
|
||||||
int64_t len_signed = (int64_t)len;
|
int64_t len_signed = (int64_t)len;
|
||||||
|
|
||||||
syx_snapshot_dirty_list_add_hostaddr(QEMU_ALIGN_PTR_DOWN(host_addr, syx_snapshot_state.page_size));
|
syx_snapshot_dirty_list_add_hostaddr(
|
||||||
|
QEMU_ALIGN_PTR_DOWN(host_addr, syx_snapshot_state.page_size));
|
||||||
void* next_page_addr = TARGET_NEXT_PAGE_ADDR(host_addr);
|
void* next_page_addr = TARGET_NEXT_PAGE_ADDR(host_addr);
|
||||||
assert(next_page_addr > host_addr);
|
assert(next_page_addr > host_addr);
|
||||||
assert(QEMU_PTR_IS_ALIGNED(next_page_addr, TARGET_PAGE_SIZE));
|
assert(QEMU_PTR_IS_ALIGNED(next_page_addr, TARGET_PAGE_SIZE));
|
||||||
@ -519,73 +597,79 @@ void syx_snapshot_dirty_list_add_hostaddr_range(void *host_addr, uint64_t len) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void empty_rb_dirty_list(gpointer _rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr, gpointer _user_data) {
|
static void empty_rb_dirty_list(gpointer _rb_idstr_hash,
|
||||||
|
gpointer rb_dirty_list_hash_table_ptr,
|
||||||
|
gpointer _user_data)
|
||||||
|
{
|
||||||
GHashTable* rb_dirty_hash_table = rb_dirty_list_hash_table_ptr;
|
GHashTable* rb_dirty_hash_table = rb_dirty_list_hash_table_ptr;
|
||||||
g_hash_table_remove_all(rb_dirty_hash_table);
|
g_hash_table_remove_all(rb_dirty_hash_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void root_restore_rb_page(gpointer offset_within_rb, gpointer _unused, gpointer root_restore_args_ptr) {
|
static void root_restore_rb_page(gpointer offset_within_rb, gpointer _unused,
|
||||||
|
gpointer root_restore_args_ptr)
|
||||||
|
{
|
||||||
struct rb_page_root_restore_args* args = root_restore_args_ptr;
|
struct rb_page_root_restore_args* args = root_restore_args_ptr;
|
||||||
RAMBlock* rb = args->rb;
|
RAMBlock* rb = args->rb;
|
||||||
SyxSnapshotRAMBlock* snapshot_rb = args->snapshot_rb;
|
SyxSnapshotRAMBlock* snapshot_rb = args->snapshot_rb;
|
||||||
|
|
||||||
|
|
||||||
// safe cast because ram_addr_t is also an alias to void*
|
// safe cast because ram_addr_t is also an alias to void*
|
||||||
void* host_rb_restore = rb->host + (ram_addr_t)offset_within_rb;
|
void* host_rb_restore = rb->host + (ram_addr_t)offset_within_rb;
|
||||||
void *host_snapshot_rb_restore = (gpointer) snapshot_rb->ram + (ram_addr_t) offset_within_rb;
|
void* host_snapshot_rb_restore =
|
||||||
|
(gpointer)snapshot_rb->ram + (ram_addr_t)offset_within_rb;
|
||||||
|
|
||||||
#ifdef SYX_SNAPSHOT_DEBUG
|
#ifdef SYX_SNAPSHOT_DEBUG
|
||||||
SYX_PRINTF("\t[%s] Restore at offset 0x%lx of size %lu...\n", rb->idstr, (uint64_t) offset_within_rb, syx_snapshot_state.page_size);
|
SYX_PRINTF("\t[%s] Restore at offset 0x%lx of size %lu...\n", rb->idstr,
|
||||||
|
(uint64_t)offset_within_rb, syx_snapshot_state.page_size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
memcpy(host_rb_restore, host_snapshot_rb_restore, syx_snapshot_state.page_size);
|
memcpy(host_rb_restore, host_snapshot_rb_restore,
|
||||||
|
syx_snapshot_state.page_size);
|
||||||
// TODO: manage special case of TSEG.
|
// TODO: manage special case of TSEG.
|
||||||
}
|
}
|
||||||
|
|
||||||
static void root_restore_rb(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr, gpointer snapshot_ptr) {
|
static void root_restore_rb(gpointer rb_idstr_hash,
|
||||||
|
gpointer rb_dirty_pages_hash_table_ptr,
|
||||||
|
gpointer snapshot_ptr)
|
||||||
|
{
|
||||||
SyxSnapshot* snapshot = snapshot_ptr;
|
SyxSnapshot* snapshot = snapshot_ptr;
|
||||||
GHashTable* rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr;
|
GHashTable* rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr;
|
||||||
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
||||||
|
|
||||||
if (rb) {
|
if (rb) {
|
||||||
SyxSnapshotRAMBlock *snapshot_ramblock = g_hash_table_lookup(snapshot->root_snapshot->rbs_snapshot,
|
SyxSnapshotRAMBlock* snapshot_ramblock = g_hash_table_lookup(
|
||||||
rb_idstr_hash);
|
snapshot->root_snapshot->rbs_snapshot, rb_idstr_hash);
|
||||||
|
|
||||||
struct rb_page_root_restore_args root_restore_args = {
|
struct rb_page_root_restore_args root_restore_args = {
|
||||||
.rb = rb,
|
.rb = rb, .snapshot_rb = snapshot_ramblock};
|
||||||
.snapshot_rb = snapshot_ramblock
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_TCG
|
g_hash_table_foreach(rb_dirty_pages_hash_table, root_restore_rb_page,
|
||||||
SYX_PRINTF("Restoring RB %s...\n", rb->idstr);
|
&root_restore_args);
|
||||||
#endif
|
|
||||||
|
|
||||||
g_hash_table_foreach(rb_dirty_pages_hash_table, root_restore_rb_page, &root_restore_args);
|
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_TCG
|
|
||||||
SYX_PRINTF("Finished to restore RB %s\n", rb->idstr);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
SYX_ERROR("Saved RAMBlock not found.");
|
SYX_ERROR("Saved RAMBlock not found.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void root_restore_check_memory_rb(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr,
|
static void root_restore_check_memory_rb(gpointer rb_idstr_hash,
|
||||||
gpointer check_memory_args_ptr) {
|
gpointer rb_dirty_pages_hash_table_ptr,
|
||||||
|
gpointer check_memory_args_ptr)
|
||||||
|
{
|
||||||
struct rb_check_memory_args* args = check_memory_args_ptr;
|
struct rb_check_memory_args* args = check_memory_args_ptr;
|
||||||
SyxSnapshot* snapshot = args->snapshot;
|
SyxSnapshot* snapshot = args->snapshot;
|
||||||
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
||||||
|
|
||||||
if (rb) {
|
if (rb) {
|
||||||
SYX_PRINTF("Checking memory consistency of %s... ", rb->idstr);
|
SYX_PRINTF("Checking memory consistency of %s... ", rb->idstr);
|
||||||
SyxSnapshotRAMBlock *rb_snapshot = g_hash_table_lookup(snapshot->root_snapshot->rbs_snapshot, rb_idstr_hash);
|
SyxSnapshotRAMBlock* rb_snapshot = g_hash_table_lookup(
|
||||||
|
snapshot->root_snapshot->rbs_snapshot, rb_idstr_hash);
|
||||||
assert(rb_snapshot);
|
assert(rb_snapshot);
|
||||||
|
|
||||||
assert(rb->used_length == rb_snapshot->used_length);
|
assert(rb->used_length == rb_snapshot->used_length);
|
||||||
|
|
||||||
for (uint64_t i = 0; i < rb->used_length; i += syx_snapshot_state.page_size) {
|
for (uint64_t i = 0; i < rb->used_length;
|
||||||
if (memcmp(rb->host + i, rb_snapshot->ram + i, syx_snapshot_state.page_size) != 0) {
|
i += syx_snapshot_state.page_size) {
|
||||||
|
if (memcmp(rb->host + i, rb_snapshot->ram + i,
|
||||||
|
syx_snapshot_state.page_size) != 0) {
|
||||||
SYX_ERROR("\nFound incorrect page at offset 0x%lx\n", i);
|
SYX_ERROR("\nFound incorrect page at offset 0x%lx\n", i);
|
||||||
for (uint64_t j = 0; j < syx_snapshot_state.page_size; j++) {
|
for (uint64_t j = 0; j < syx_snapshot_state.page_size; j++) {
|
||||||
if (*(rb->host + i + j) != *(rb_snapshot->ram + i + j)) {
|
if (*(rb->host + i + j) != *(rb_snapshot->ram + i + j)) {
|
||||||
@ -594,12 +678,13 @@ static void root_restore_check_memory_rb(gpointer rb_idstr_hash, gpointer rb_dir
|
|||||||
}
|
}
|
||||||
args->nb_inconsistent_pages++;
|
args->nb_inconsistent_pages++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args->nb_inconsistent_pages > 0) {
|
if (args->nb_inconsistent_pages > 0) {
|
||||||
SYX_ERROR("[%s] Found %lu page %s.\n", rb->idstr, args->nb_inconsistent_pages,
|
SYX_ERROR("[%s] Found %lu page %s.\n", rb->idstr,
|
||||||
args->nb_inconsistent_pages > 1 ? "inconsistencies" : "inconsistency");
|
args->nb_inconsistent_pages,
|
||||||
|
args->nb_inconsistent_pages > 1 ? "inconsistencies"
|
||||||
|
: "inconsistency");
|
||||||
} else {
|
} else {
|
||||||
SYX_PRINTF("OK.\n");
|
SYX_PRINTF("OK.\n");
|
||||||
}
|
}
|
||||||
@ -609,27 +694,27 @@ static void root_restore_check_memory_rb(gpointer rb_idstr_hash, gpointer rb_dir
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SyxSnapshotCheckResult syx_snapshot_check(SyxSnapshot* ref_snapshot) {
|
SyxSnapshotCheckResult syx_snapshot_check(SyxSnapshot* ref_snapshot)
|
||||||
|
{
|
||||||
struct rb_check_memory_args args = {
|
struct rb_check_memory_args args = {
|
||||||
.snapshot = ref_snapshot,
|
.snapshot = ref_snapshot,
|
||||||
.nb_inconsistent_pages = 0,
|
.nb_inconsistent_pages = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
g_hash_table_foreach(ref_snapshot->rbs_dirty_list, root_restore_check_memory_rb, &args);
|
g_hash_table_foreach(ref_snapshot->rbs_dirty_list,
|
||||||
|
root_restore_check_memory_rb, &args);
|
||||||
|
|
||||||
struct SyxSnapshotCheckResult res = {
|
struct SyxSnapshotCheckResult res = {.nb_inconsistencies =
|
||||||
.nb_inconsistencies = args.nb_inconsistent_pages
|
args.nb_inconsistent_pages};
|
||||||
};
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void syx_snapshot_root_restore(SyxSnapshot *snapshot) {
|
void syx_snapshot_root_restore(SyxSnapshot* snapshot)
|
||||||
|
{
|
||||||
// health check.
|
// health check.
|
||||||
CPUState* cpu;
|
CPUState* cpu;
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) { assert(cpu->stopped); }
|
||||||
assert(cpu->stopped);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool must_unlock_bql = false;
|
bool must_unlock_bql = false;
|
||||||
|
|
||||||
@ -638,7 +723,8 @@ void syx_snapshot_root_restore(SyxSnapshot *snapshot) {
|
|||||||
must_unlock_bql = true;
|
must_unlock_bql = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In case, we first restore devices if there is a modification of memory layout
|
// In case, we first restore devices if there is a modification of memory
|
||||||
|
// layout
|
||||||
device_restore_all(snapshot->root_snapshot->dss);
|
device_restore_all(snapshot->root_snapshot->dss);
|
||||||
|
|
||||||
g_hash_table_foreach(snapshot->rbs_dirty_list, root_restore_rb, snapshot);
|
g_hash_table_foreach(snapshot->rbs_dirty_list, root_restore_rb, snapshot);
|
||||||
@ -656,34 +742,46 @@ void syx_snapshot_root_restore(SyxSnapshot *snapshot) {
|
|||||||
bql_unlock();
|
bql_unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool syx_snapshot_cow_cache_read_entry(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset,
|
|
||||||
|
bool syx_snapshot_cow_cache_read_entry(BlockBackend* blk, int64_t offset,
|
||||||
|
int64_t bytes, QEMUIOVector* qiov,
|
||||||
|
size_t qiov_offset,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
if (!syx_snapshot_state.active_bdrv_cache_snapshot) {
|
if (!syx_snapshot_state.active_bdrv_cache_snapshot) {
|
||||||
if (syx_snapshot_state.before_fuzz_cache) {
|
if (syx_snapshot_state.before_fuzz_cache) {
|
||||||
syx_cow_cache_read_entry(syx_snapshot_state.before_fuzz_cache, blk, offset, bytes, qiov, qiov_offset, flags);
|
syx_cow_cache_read_entry(syx_snapshot_state.before_fuzz_cache, blk,
|
||||||
|
offset, bytes, qiov, qiov_offset, flags);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
syx_cow_cache_read_entry(syx_snapshot_state.active_bdrv_cache_snapshot->bdrvs_cow_cache, blk, offset, bytes, qiov, qiov_offset, flags);
|
syx_cow_cache_read_entry(
|
||||||
|
syx_snapshot_state.active_bdrv_cache_snapshot->bdrvs_cow_cache, blk,
|
||||||
|
offset, bytes, qiov, qiov_offset, flags);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool syx_snapshot_cow_cache_write_entry(BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset,
|
bool syx_snapshot_cow_cache_write_entry(BlockBackend* blk, int64_t offset,
|
||||||
|
int64_t bytes, QEMUIOVector* qiov,
|
||||||
|
size_t qiov_offset,
|
||||||
BdrvRequestFlags flags)
|
BdrvRequestFlags flags)
|
||||||
{
|
{
|
||||||
if (!syx_snapshot_state.active_bdrv_cache_snapshot) {
|
if (!syx_snapshot_state.active_bdrv_cache_snapshot) {
|
||||||
if (syx_snapshot_state.before_fuzz_cache) {
|
if (syx_snapshot_state.before_fuzz_cache) {
|
||||||
assert(syx_cow_cache_write_entry(syx_snapshot_state.before_fuzz_cache, blk, offset, bytes, qiov, qiov_offset, flags));
|
assert(syx_cow_cache_write_entry(
|
||||||
|
syx_snapshot_state.before_fuzz_cache, blk, offset, bytes, qiov,
|
||||||
|
qiov_offset, flags));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
assert(syx_cow_cache_write_entry(syx_snapshot_state.active_bdrv_cache_snapshot->bdrvs_cow_cache, blk, offset, bytes, qiov, qiov_offset, flags));
|
assert(syx_cow_cache_write_entry(
|
||||||
|
syx_snapshot_state.active_bdrv_cache_snapshot->bdrvs_cow_cache, blk,
|
||||||
|
offset, bytes, qiov, qiov_offset, flags));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ uintptr_t libafl_qemu_host_page_size(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
|
||||||
uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write)
|
uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write)
|
||||||
{
|
{
|
||||||
if (addr == -1) {
|
if (addr == -1) {
|
||||||
@ -15,10 +16,13 @@ uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write)
|
|||||||
|
|
||||||
hwaddr xlat;
|
hwaddr xlat;
|
||||||
MemoryRegion* mr;
|
MemoryRegion* mr;
|
||||||
WITH_RCU_READ_LOCK_GUARD() {
|
WITH_RCU_READ_LOCK_GUARD()
|
||||||
mr = address_space_translate(cpu->as, addr, &xlat, NULL, is_write, MEMTXATTRS_UNSPECIFIED);
|
{
|
||||||
|
mr = address_space_translate(cpu->as, addr, &xlat, NULL, is_write,
|
||||||
|
MEMTXATTRS_UNSPECIFIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
return qemu_map_ram_ptr(mr->ram_block, xlat);
|
return qemu_map_ram_ptr(mr->ram_block, xlat);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -977,7 +977,6 @@ static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info,
|
|||||||
|
|
||||||
// int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info,
|
// int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info,
|
||||||
// host_sigcontext *uc);
|
// host_sigcontext *uc);
|
||||||
void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc);
|
|
||||||
|
|
||||||
/* int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info,
|
/* int libafl_qemu_is_tb_protected_write(int host_sig, siginfo_t *info,
|
||||||
host_sigcontext *uc)
|
host_sigcontext *uc)
|
||||||
@ -998,6 +997,8 @@ void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc);
|
|||||||
pc, guest_addr);
|
pc, guest_addr);
|
||||||
} */
|
} */
|
||||||
|
|
||||||
|
#include "libafl/user.h"
|
||||||
|
|
||||||
void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc) {
|
void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc) {
|
||||||
host_signal_handler(host_sig, info, puc);
|
host_signal_handler(host_sig, info, puc);
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,11 @@
|
|||||||
#include <sys/sysinfo.h>
|
#include <sys/sysinfo.h>
|
||||||
#include <sys/signalfd.h>
|
#include <sys/signalfd.h>
|
||||||
//#include <sys/user.h>
|
//#include <sys/user.h>
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
|
#include "libafl/hooks/syscall.h"
|
||||||
|
|
||||||
|
//// --- End LibAFL code ---
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <netinet/ip.h>
|
#include <netinet/ip.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
@ -6529,9 +6534,7 @@ typedef struct {
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
#include "libafl/hook.h"
|
#include "libafl/hooks/thread.h"
|
||||||
|
|
||||||
extern __thread CPUArchState *libafl_qemu_env;
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
@ -6567,17 +6570,7 @@ static void *clone_func(void *arg)
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
libafl_qemu_env = env;
|
if (libafl_hook_new_thread_run(env)) {
|
||||||
if (libafl_new_thread_hooks) {
|
|
||||||
bool continue_execution = true;
|
|
||||||
int tid = sys_gettid();
|
|
||||||
struct libafl_new_thread_hook* h = libafl_new_thread_hooks;
|
|
||||||
while (h) {
|
|
||||||
continue_execution = h->callback(h->data, tid) && continue_execution;
|
|
||||||
h = h->next;
|
|
||||||
}
|
|
||||||
if (continue_execution) cpu_loop(env);
|
|
||||||
} else {
|
|
||||||
cpu_loop(env);
|
cpu_loop(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13886,25 +13879,7 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||||||
|
|
||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
bool skip_syscall = false;
|
bool skip_syscall = libafl_hook_syscall_pre_run(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, &ret);
|
||||||
struct libafl_pre_syscall_hook* h = libafl_pre_syscall_hooks;
|
|
||||||
while (h) {
|
|
||||||
// no null check
|
|
||||||
struct syshook_ret hook_ret = h->callback(h->data, num,
|
|
||||||
(target_ulong)arg1,
|
|
||||||
(target_ulong)arg2,
|
|
||||||
(target_ulong)arg3,
|
|
||||||
(target_ulong)arg4,
|
|
||||||
(target_ulong)arg5,
|
|
||||||
(target_ulong)arg6,
|
|
||||||
(target_ulong)arg7,
|
|
||||||
(target_ulong)arg8);
|
|
||||||
if (hook_ret.skip_syscall) {
|
|
||||||
skip_syscall = true;
|
|
||||||
ret = (abi_ulong)hook_ret.retval;
|
|
||||||
}
|
|
||||||
h = h->next;
|
|
||||||
}
|
|
||||||
if (skip_syscall) goto after_syscall;
|
if (skip_syscall) goto after_syscall;
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
@ -13915,21 +13890,8 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1,
|
|||||||
//// --- Begin LibAFL code ---
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
after_syscall:;
|
after_syscall:;
|
||||||
struct libafl_post_syscall_hook* p = libafl_post_syscall_hooks;
|
libafl_hook_syscall_post_run(num, arg1, arg2, arg3, arg4,
|
||||||
while (p) {
|
arg5, arg6, arg7, arg8, &ret);
|
||||||
// no null check
|
|
||||||
ret = (abi_ulong)p->callback(p->data, (target_ulong)ret, num,
|
|
||||||
(target_ulong)arg1,
|
|
||||||
(target_ulong)arg2,
|
|
||||||
(target_ulong)arg3,
|
|
||||||
(target_ulong)arg4,
|
|
||||||
(target_ulong)arg5,
|
|
||||||
(target_ulong)arg6,
|
|
||||||
(target_ulong)arg7,
|
|
||||||
(target_ulong)arg8);
|
|
||||||
p = p->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
//// --- End LibAFL code ---
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
|
if (unlikely(qemu_loglevel_mask(LOG_STRACE))) {
|
||||||
|
15
scripts/libafl-format.sh
Executable file
15
scripts/libafl-format.sh
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
ROOT_DIR="$SCRIPT_DIR/.."
|
||||||
|
|
||||||
|
if [ "$1" = "check" ]; then
|
||||||
|
CHECK="--dry-run --Werror"
|
||||||
|
elif [ "$1" != "" ]; then
|
||||||
|
echo "Unknown option: $1. Type 'check' to check without modifying any file; do not provide any argument to format automatically."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$SCRIPT_DIR" || exit 1
|
||||||
|
find "$ROOT_DIR/libafl" -name "*.c" -exec clang-format $CHECK -style="file:$ROOT_DIR/libafl/.clang-format" -i {} \;
|
||||||
|
find "$ROOT_DIR/include/libafl" -name "*.h" -exec clang-format $CHECK -style=file:"$ROOT_DIR/libafl/.clang-format" -i {} \;
|
@ -647,6 +647,12 @@ const AccelOpsClass *cpus_get_accel(void)
|
|||||||
return cpus_accel;
|
return cpus_accel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
|
// #include "libafl/hooks/thread.h"
|
||||||
|
|
||||||
|
//// --- End LibAFL code ---
|
||||||
|
|
||||||
void qemu_init_vcpu(CPUState *cpu)
|
void qemu_init_vcpu(CPUState *cpu)
|
||||||
{
|
{
|
||||||
MachineState *ms = MACHINE(qdev_get_machine());
|
MachineState *ms = MACHINE(qdev_get_machine());
|
||||||
@ -671,6 +677,23 @@ void qemu_init_vcpu(CPUState *cpu)
|
|||||||
while (!cpu->created) {
|
while (!cpu->created) {
|
||||||
qemu_cond_wait(&qemu_cpu_cond, &bql);
|
qemu_cond_wait(&qemu_cpu_cond, &bql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//// --- Begin LibAFL code ---
|
||||||
|
|
||||||
|
// if (libafl_new_thread_hooks) {
|
||||||
|
// bool continue_execution = true;
|
||||||
|
// struct libafl_new_thread_hook* h = libafl_new_thread_hooks;
|
||||||
|
// while (h) {
|
||||||
|
// continue_execution &= h->callback(h->data, cpu, 0); // TODO: should we keep TID in systemmode? could be useful for identification
|
||||||
|
// h = h->next;
|
||||||
|
// }
|
||||||
|
// if (!continue_execution) {
|
||||||
|
// // TODO: check if this is correct
|
||||||
|
// qemu_cpu_stop(cpu, true);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
//// --- End LibAFL code ---
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_stop_current(void)
|
void cpu_stop_current(void)
|
||||||
|
@ -741,10 +741,14 @@ static int cpu_pre_save(void *opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len;
|
cpu->cpreg_vmstate_array_len = cpu->cpreg_array_len;
|
||||||
|
|
||||||
|
// Some ARM cpus like Cortex M do not have coprocessors
|
||||||
|
if (cpu->cpreg_array_len > 0) {
|
||||||
memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes,
|
memcpy(cpu->cpreg_vmstate_indexes, cpu->cpreg_indexes,
|
||||||
cpu->cpreg_array_len * sizeof(uint64_t));
|
cpu->cpreg_array_len * sizeof(uint64_t));
|
||||||
memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values,
|
memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values,
|
||||||
cpu->cpreg_array_len * sizeof(uint64_t));
|
cpu->cpreg_array_len * sizeof(uint64_t));
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user