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 "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 */
|
||||
#ifdef CONFIG_EVENTFD
|
||||
#include <sys/eventfd.h>
|
||||
@ -2866,10 +2872,22 @@ int kvm_cpu_exec(CPUState *cpu)
|
||||
*/
|
||||
smp_rmb();
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
libafl_hook_cpu_run_pre_exec(cpu);
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);
|
||||
|
||||
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
|
||||
if (unlikely(have_sigbus_pending)) {
|
||||
bql_lock();
|
||||
|
@ -68,7 +68,8 @@
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
#include "libafl/hook.h"
|
||||
#include "libafl/hooks/tcg/block.h"
|
||||
#include "libafl/hooks/tcg/edge.h"
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
@ -284,24 +285,7 @@ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb,
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
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;
|
||||
}
|
||||
libafl_qemu_hook_block_run(pc);
|
||||
|
||||
//// --- 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
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
// run edge hooks
|
||||
libafl_qemu_hook_edge_run();
|
||||
|
||||
tcg_gen_goto_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);
|
||||
|
||||
// edge hooks generation callbacks
|
||||
struct libafl_edge_hook* hook = libafl_edge_hooks;
|
||||
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;
|
||||
}
|
||||
bool no_exec_hook = libafl_qemu_hook_edge_gen(src_block, dst_block);
|
||||
if (no_exec_hook)
|
||||
return NULL;
|
||||
|
||||
@ -749,13 +712,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
tb->tc.size = gen_code_size;
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
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;
|
||||
}
|
||||
|
||||
libafl_qemu_hook_block_post_gen(tb, pc);
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
/*
|
||||
|
@ -104,6 +104,9 @@ static void gen_tb_end(const TranslationBlock *tb, uint32_t cflags,
|
||||
#include "libafl/exit.h"
|
||||
#include "libafl/hook.h"
|
||||
|
||||
#include "libafl/hooks/tcg/instruction.h"
|
||||
#include "libafl/hooks/tcg/backdoor.h"
|
||||
|
||||
#ifndef TARGET_LONG_BITS
|
||||
#error "TARGET_LONG_BITS not defined"
|
||||
#endif
|
||||
@ -168,37 +171,10 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
struct libafl_hook* hk = libafl_search_instruction_hook(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_qemu_hook_instruction_run(db->pc_next);
|
||||
|
||||
libafl_gen_cur_pc = db->pc_next;
|
||||
libafl_qemu_breakpoint_run(libafl_gen_cur_pc);
|
||||
|
||||
// 0x0f, 0x3a, 0xf2, 0x44
|
||||
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) {
|
||||
backdoor = translator_ldub(cpu_env(cpu), db, db->pc_next +3);
|
||||
if (backdoor == 0x44) {
|
||||
struct libafl_backdoor_hook* bhk = libafl_backdoor_hooks;
|
||||
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;
|
||||
}
|
||||
libafl_qemu_hook_backdoor_run(db->pc_next);
|
||||
|
||||
db->pc_next += 4;
|
||||
goto post_translate_insn;
|
||||
|
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "exec/cpu-defs.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#define EXCP_LIBAFL_EXIT 0xf4775747
|
||||
|
||||
@ -10,14 +12,13 @@ struct libafl_breakpoint {
|
||||
struct libafl_breakpoint* next;
|
||||
};
|
||||
|
||||
extern struct libafl_breakpoint* libafl_qemu_breakpoints;
|
||||
|
||||
// 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_remove_breakpoint(target_ulong pc);
|
||||
void libafl_qemu_trigger_breakpoint(CPUState* cpu);
|
||||
void libafl_qemu_breakpoint_run(vaddr pc_next);
|
||||
|
||||
enum libafl_exit_reason_kind {
|
||||
INTERNAL = 0,
|
||||
@ -31,7 +32,8 @@ struct libafl_exit_reason_breakpoint {
|
||||
};
|
||||
|
||||
// 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.
|
||||
struct libafl_exit_reason_internal {
|
||||
@ -58,7 +60,8 @@ void libafl_exit_signal_vm_start(void);
|
||||
bool libafl_exit_asap(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_breakpoint(CPUState* cpu, target_ulong pc);
|
||||
struct libafl_exit_reason* libafl_get_exit_reason(void);
|
||||
|
@ -7,221 +7,55 @@
|
||||
#include "tcg/tcg-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
|
||||
|
||||
void tcg_gen_callN(TCGHelperInfo *info, TCGTemp *ret, TCGTemp **args);
|
||||
#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; \
|
||||
}
|
||||
|
||||
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);
|
||||
#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;
|
||||
|
||||
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);
|
||||
void tcg_gen_callN(TCGHelperInfo* info, TCGTemp* ret, TCGTemp** args);
|
||||
|
||||
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"
|
||||
|
||||
#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
|
||||
#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
|
||||
#define SYX_DEBUG(format, ...)
|
||||
#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
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "migration/qemu-file.h"
|
||||
|
||||
#include "migration/qemu-file.h"
|
||||
#include "io/channel.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define QEMU_FILE_RAM_LIMIT (32 * 1024 * 1024)
|
||||
|
||||
#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 {
|
||||
QIOChannel parent;
|
||||
@ -26,7 +27,10 @@ struct QIOChannelBufferWriteback {
|
||||
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:
|
||||
@ -34,5 +38,6 @@ QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uin
|
||||
* @capacity: the total capacity of the underlying buffer
|
||||
* @usage: The size actually used by the buffer
|
||||
*/
|
||||
QIOChannelBufferWriteback*
|
||||
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);
|
||||
QIOChannelBufferWriteback* 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);
|
||||
|
@ -1,8 +1,10 @@
|
||||
#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/iov.h"
|
||||
#include "block/block.h"
|
||||
|
||||
@ -16,7 +18,7 @@ typedef struct SyxCowCacheDevice {
|
||||
typedef struct SyxCowCacheLayer SyxCowCacheLayer;
|
||||
|
||||
typedef struct SyxCowCacheLayer {
|
||||
GHashTable *cow_cache_devices; // H(device) -> SyxCowCacheDevice
|
||||
GHashTable* cow_cache_devices; // H(device) -> SyxCowCacheDevice
|
||||
uint64_t chunk_size;
|
||||
uint64_t max_nb_chunks;
|
||||
|
||||
@ -33,13 +35,17 @@ SyxCowCache* syx_cow_cache_new(void);
|
||||
// rhs is freed and nulled.
|
||||
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_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,
|
||||
BdrvRequestFlags flags);
|
||||
void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend* blk,
|
||||
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);
|
||||
|
@ -9,11 +9,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "qom/object.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
#include "device-save.h"
|
||||
#include "syx-cow-cache.h"
|
||||
|
||||
#include "libafl/syx-misc.h"
|
||||
|
||||
#define SYX_SNAPSHOT_COW_CACHE_DEFAULT_CHUNK_SIZE 64
|
||||
@ -31,7 +33,9 @@ typedef struct SyxSnapshot {
|
||||
SyxSnapshotIncrement* last_incremental_snapshot;
|
||||
|
||||
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;
|
||||
|
||||
typedef struct SyxSnapshotTracker {
|
||||
@ -69,22 +73,24 @@ void syx_snapshot_init(bool cached_bdrvs);
|
||||
// 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);
|
||||
|
||||
void syx_snapshot_root_restore(SyxSnapshot *snapshot);
|
||||
void syx_snapshot_root_restore(SyxSnapshot* snapshot);
|
||||
|
||||
SyxSnapshotCheckResult syx_snapshot_check(SyxSnapshot* ref_snapshot);
|
||||
|
||||
// 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.
|
||||
void syx_snapshot_increment_pop(SyxSnapshot *snapshot);
|
||||
|
||||
void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot);
|
||||
// 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_restore_last(SyxSnapshot* snapshot);
|
||||
|
||||
//
|
||||
// Snapshot tracker API
|
||||
@ -92,10 +98,10 @@ void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot);
|
||||
|
||||
SyxSnapshotTracker syx_snapshot_tracker_init(void);
|
||||
|
||||
void syx_snapshot_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot);
|
||||
|
||||
void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot);
|
||||
void syx_snapshot_track(SyxSnapshotTracker* tracker, SyxSnapshot* snapshot);
|
||||
|
||||
void syx_snapshot_stop_track(SyxSnapshotTracker* tracker,
|
||||
SyxSnapshot* snapshot);
|
||||
|
||||
//
|
||||
// Misc functions
|
||||
@ -103,14 +109,13 @@ void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot)
|
||||
|
||||
bool syx_snapshot_is_enabled(void);
|
||||
|
||||
|
||||
//
|
||||
// Dirty list API
|
||||
//
|
||||
|
||||
void syx_snapshot_dirty_list_add_hostaddr(void *host_addr);
|
||||
void syx_snapshot_dirty_list_add_hostaddr(void* host_addr);
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Same as syx_snapshot_dirty_list_add. The difference
|
||||
@ -124,10 +129,14 @@ void syx_snapshot_dirty_list_add_hostaddr_range(void *host_addr, uint64_t len);
|
||||
* tcg-target.inc.c specific environment.
|
||||
* @param host_addr The host address where the dirty page is located.
|
||||
*/
|
||||
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);
|
||||
|
||||
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);
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
struct libafl_mapinfo {
|
||||
target_ulong start;
|
||||
@ -13,5 +13,9 @@ struct libafl_mapinfo {
|
||||
bool is_valid;
|
||||
};
|
||||
|
||||
IntervalTreeNode * libafl_maps_first(IntervalTreeRoot * map_info);
|
||||
IntervalTreeNode * libafl_maps_next(IntervalTreeNode *pageflags_maps_node, IntervalTreeRoot *proc_maps_node, struct libafl_mapinfo* ret);
|
||||
void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc);
|
||||
|
||||
IntervalTreeNode* libafl_maps_first(IntervalTreeRoot* map_info);
|
||||
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 "tcg/tcg.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "tcg/tcg-temp-internal.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
@ -13,11 +18,9 @@ struct libafl_breakpoint* libafl_qemu_breakpoints = NULL;
|
||||
|
||||
int libafl_qemu_set_breakpoint(target_ulong pc)
|
||||
{
|
||||
CPUState *cpu;
|
||||
CPUState* cpu;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
libafl_breakpoint_invalidate(cpu, pc);
|
||||
}
|
||||
CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, pc); }
|
||||
|
||||
struct libafl_breakpoint* bp = calloc(sizeof(struct libafl_breakpoint), 1);
|
||||
bp->addr = pc;
|
||||
@ -28,15 +31,13 @@ int libafl_qemu_set_breakpoint(target_ulong pc)
|
||||
|
||||
int libafl_qemu_remove_breakpoint(target_ulong pc)
|
||||
{
|
||||
CPUState *cpu;
|
||||
CPUState* cpu;
|
||||
int r = 0;
|
||||
|
||||
struct libafl_breakpoint** bp = &libafl_qemu_breakpoints;
|
||||
while (*bp) {
|
||||
if ((*bp)->addr == pc) {
|
||||
CPU_FOREACH(cpu) {
|
||||
libafl_breakpoint_invalidate(cpu, pc);
|
||||
}
|
||||
CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, pc); }
|
||||
|
||||
*bp = (*bp)->next;
|
||||
r = 1;
|
||||
@ -61,15 +62,13 @@ void libafl_sync_exit_cpu(void)
|
||||
{
|
||||
if (last_exit_reason.next_pc) {
|
||||
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;
|
||||
}
|
||||
|
||||
bool libafl_exit_asap(void)
|
||||
{
|
||||
return expected_exit;
|
||||
}
|
||||
bool libafl_exit_asap(void) { return expected_exit; }
|
||||
|
||||
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();
|
||||
cpu->stopped = true; // TODO check if still needed
|
||||
#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) {
|
||||
cpu->exception_index = EXCP_LIBAFL_EXIT;
|
||||
cpu_loop_exit(cpu);
|
||||
@ -97,7 +97,8 @@ CPUState* libafl_last_exit_cpu(void)
|
||||
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.data.internal.cause = cause;
|
||||
@ -143,3 +144,16 @@ struct libafl_exit_reason* libafl_get_exit_reason(void)
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
691
libafl/hook.c
691
libafl/hook.c
@ -1,4 +1,5 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "qapi/error.h"
|
||||
|
||||
#include "exec/exec-all.h"
|
||||
@ -11,683 +12,6 @@
|
||||
#error "TARGET_LONG_BITS not defined"
|
||||
#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
|
||||
#define SHADOW_BASE (0x20000000)
|
||||
#elif TARGET_LONG_BITS == 64
|
||||
@ -696,7 +20,7 @@ GEN_REMOVE_HOOK1(new_thread)
|
||||
#error Unhandled TARGET_LONG_BITS value
|
||||
#endif
|
||||
|
||||
void libafl_tcg_gen_asan(TCGTemp * addr, size_t size)
|
||||
void libafl_tcg_gen_asan(TCGTemp* addr, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
@ -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
|
||||
* at 0x0.
|
||||
*/
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, test_addr,
|
||||
shadow_val, tcg_constant_tl(0),
|
||||
tcg_gen_movcond_tl(TCG_COND_EQ, test_addr, shadow_val, tcg_constant_tl(0),
|
||||
shadow_addr, tcg_constant_tl(0));
|
||||
|
||||
if (size < 8)
|
||||
{
|
||||
tcg_gen_movcond_tl(TCG_COND_GE, test_addr,
|
||||
k, shadow_val,
|
||||
test_addr, shadow_addr);
|
||||
if (size < 8) {
|
||||
tcg_gen_movcond_tl(TCG_COND_GE, test_addr, k, shadow_val, test_addr,
|
||||
shadow_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;
|
||||
}
|
25
libafl/jit.c
25
libafl/jit.c
@ -1,4 +1,5 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "qapi/error.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));
|
||||
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_i32 counter = tcg_temp_new_i32();
|
||||
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
|
||||
}
|
||||
|
||||
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_i32 counter = tcg_temp_new_i32();
|
||||
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;
|
||||
|
||||
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 prev_loc_ptr = tcg_constant_ptr(&__prev_loc);
|
||||
|
||||
@ -58,8 +62,8 @@ size_t libafl_jit_trace_block_hitcount(uint64_t data, uint64_t id) {
|
||||
|
||||
// Compute location => 5 insn
|
||||
tcg_gen_ld_i64(prev_loc, prev_loc_ptr, 0);
|
||||
tcg_gen_xori_i64(prev_loc, prev_loc, (int64_t) id);
|
||||
tcg_gen_andi_i64(prev_loc, prev_loc, (int64_t) (__afl_map_size - 1));
|
||||
tcg_gen_xori_i64(prev_loc, prev_loc, (int64_t)id);
|
||||
tcg_gen_andi_i64(prev_loc, prev_loc, (int64_t)(__afl_map_size - 1));
|
||||
tcg_gen_trunc_i64_ptr(prev_loc2, prev_loc);
|
||||
tcg_gen_add_ptr(prev_loc2, map_ptr, prev_loc2);
|
||||
|
||||
@ -69,13 +73,14 @@ size_t libafl_jit_trace_block_hitcount(uint64_t data, uint64_t id) {
|
||||
tcg_gen_st8_i32(counter, prev_loc2, 0);
|
||||
|
||||
// Update prev_loc => 3 insn
|
||||
tcg_gen_movi_i64(id_r, (int64_t) id);
|
||||
tcg_gen_movi_i64(id_r, (int64_t)id);
|
||||
tcg_gen_shri_i64(id_r, id_r, 1);
|
||||
tcg_gen_st_i64(id_r, prev_loc_ptr, 0);
|
||||
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 prev_loc_ptr = tcg_constant_ptr(&__prev_loc);
|
||||
|
||||
@ -86,8 +91,8 @@ size_t libafl_jit_trace_block_single(uint64_t data, uint64_t id) {
|
||||
|
||||
// Compute location => 5 insn
|
||||
tcg_gen_ld_i64(prev_loc, prev_loc_ptr, 0);
|
||||
tcg_gen_xori_i64(prev_loc, prev_loc, (int64_t) id);
|
||||
tcg_gen_andi_i64(prev_loc, prev_loc, (int64_t) (__afl_map_size - 1));
|
||||
tcg_gen_xori_i64(prev_loc, prev_loc, (int64_t)id);
|
||||
tcg_gen_andi_i64(prev_loc, prev_loc, (int64_t)(__afl_map_size - 1));
|
||||
tcg_gen_trunc_i64_ptr(prev_loc2, prev_loc);
|
||||
tcg_gen_add_ptr(map_ptr, map_ptr, prev_loc2);
|
||||
|
||||
@ -96,7 +101,7 @@ size_t libafl_jit_trace_block_single(uint64_t data, uint64_t id) {
|
||||
tcg_gen_st8_i32(counter, map_ptr, 0);
|
||||
|
||||
// Update prev_loc => 3 insn
|
||||
tcg_gen_movi_i64(id_r, (int64_t) id);
|
||||
tcg_gen_movi_i64(id_r, (int64_t)id);
|
||||
tcg_gen_shri_i64(id_r, id_r, 1);
|
||||
tcg_gen_st_i64(id_r, prev_loc_ptr, 0);
|
||||
return 10; // # instructions
|
||||
|
@ -3,12 +3,28 @@ specific_ss.add(files(
|
||||
'hook.c',
|
||||
'jit.c',
|
||||
'utils.c',
|
||||
))
|
||||
|
||||
specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: [files(
|
||||
# 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(
|
||||
'syx-snapshot/device-save.c',
|
||||
'syx-snapshot/syx-snapshot.c',
|
||||
'syx-snapshot/syx-cow-cache.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-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_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);
|
||||
|
||||
@ -27,16 +32,19 @@ QIOChannelBufferWriteback* qio_channel_buffer_writeback_new(size_t capacity, uin
|
||||
return ioc;
|
||||
}
|
||||
|
||||
QIOChannelBufferWriteback*
|
||||
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) {
|
||||
QIOChannelBufferWriteback* 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)
|
||||
{
|
||||
assert(buf != NULL);
|
||||
assert(usage <= capacity);
|
||||
assert(writeback_buf != 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);
|
||||
|
||||
@ -52,8 +60,8 @@ qio_channel_buffer_writeback_new_external(uint8_t* buf, size_t capacity, size_t
|
||||
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);
|
||||
|
||||
assert(bwioc->writeback_buf_capacity >= bwioc->usage);
|
||||
@ -70,14 +78,11 @@ static void qio_channel_buffer_writeback_finalize(Object *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ssize_t qio_channel_buffer_writeback_readv(QIOChannel *ioc,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
int **fds,
|
||||
size_t *nfds,
|
||||
int flags,
|
||||
Error **errp)
|
||||
static ssize_t qio_channel_buffer_writeback_readv(QIOChannel* ioc,
|
||||
const struct iovec* iov,
|
||||
size_t niov, int** fds,
|
||||
size_t* nfds, int flags,
|
||||
Error** errp)
|
||||
{
|
||||
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||
ssize_t ret = 0;
|
||||
@ -103,12 +108,10 @@ static ssize_t qio_channel_buffer_writeback_readv(QIOChannel *ioc,
|
||||
}
|
||||
|
||||
static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc,
|
||||
const struct iovec *iov,
|
||||
size_t niov,
|
||||
int *fds,
|
||||
size_t nfds,
|
||||
int flags,
|
||||
Error **errp)
|
||||
const struct iovec* iov,
|
||||
size_t niov, int* fds,
|
||||
size_t nfds, int flags,
|
||||
Error** errp)
|
||||
{
|
||||
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||
ssize_t ret = 0;
|
||||
@ -123,9 +126,7 @@ static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc,
|
||||
assert(bwioc->offset <= bwioc->usage);
|
||||
|
||||
for (i = 0; i < niov; i++) {
|
||||
memcpy(bwioc->data + bwioc->offset,
|
||||
iov[i].iov_base,
|
||||
iov[i].iov_len);
|
||||
memcpy(bwioc->data + bwioc->offset, iov[i].iov_base, iov[i].iov_len);
|
||||
bwioc->offset += iov[i].iov_len;
|
||||
bwioc->usage += iov[i].iov_len;
|
||||
ret += iov[i].iov_len;
|
||||
@ -134,30 +135,29 @@ static ssize_t qio_channel_buffer_writeback_writev(QIOChannel* ioc,
|
||||
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,
|
||||
Error **errp G_GNUC_UNUSED)
|
||||
Error** errp G_GNUC_UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static off_t qio_channel_buffer_writeback_seek(QIOChannel *ioc,
|
||||
off_t offset,
|
||||
int whence,
|
||||
Error **errp)
|
||||
static off_t qio_channel_buffer_writeback_seek(QIOChannel* ioc, off_t offset,
|
||||
int whence, Error** errp)
|
||||
{
|
||||
QIOChannelBufferWriteback *bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||
off_t new_pos;
|
||||
|
||||
switch(whence) {
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
new_pos = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
new_pos = (off_t) bwioc->offset + offset;
|
||||
new_pos = (off_t)bwioc->offset + offset;
|
||||
break;
|
||||
case SEEK_END:
|
||||
new_pos = (off_t) bwioc->usage + offset;
|
||||
new_pos = (off_t)bwioc->usage + offset;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
@ -170,8 +170,7 @@ static off_t qio_channel_buffer_writeback_seek(QIOChannel *ioc,
|
||||
return new_pos;
|
||||
}
|
||||
|
||||
static int qio_channel_buffer_writeback_close(QIOChannel *ioc,
|
||||
Error **errp)
|
||||
static int qio_channel_buffer_writeback_close(QIOChannel* ioc, Error** errp)
|
||||
{
|
||||
QIOChannelBufferWriteback* bwioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||
|
||||
@ -194,46 +193,44 @@ static int qio_channel_buffer_writeback_close(QIOChannel *ioc,
|
||||
typedef struct QIOChannelBufferWritebackSource QIOChannelBufferWritebackSource;
|
||||
struct QIOChannelBufferWritebackSource {
|
||||
GSource parent;
|
||||
QIOChannelBufferWriteback *bioc;
|
||||
QIOChannelBufferWriteback* bioc;
|
||||
GIOCondition condition;
|
||||
};
|
||||
|
||||
static gboolean
|
||||
qio_channel_buffer_writeback_source_prepare(GSource *source,
|
||||
gint *timeout)
|
||||
static gboolean qio_channel_buffer_writeback_source_prepare(GSource* source,
|
||||
gint* timeout)
|
||||
{
|
||||
QIOChannelBufferWritebackSource *bsource = (QIOChannelBufferWritebackSource *)source;
|
||||
QIOChannelBufferWritebackSource* bsource =
|
||||
(QIOChannelBufferWritebackSource*)source;
|
||||
|
||||
*timeout = -1;
|
||||
|
||||
return (G_IO_IN | G_IO_OUT) & bsource->condition;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
qio_channel_buffer_writeback_source_check(GSource *source)
|
||||
static gboolean 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;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
qio_channel_buffer_writeback_source_dispatch(GSource *source,
|
||||
GSourceFunc callback,
|
||||
gpointer user_data)
|
||||
static gboolean qio_channel_buffer_writeback_source_dispatch(
|
||||
GSource* source, GSourceFunc callback, gpointer user_data)
|
||||
{
|
||||
QIOChannelFunc func = (QIOChannelFunc)callback;
|
||||
QIOChannelBufferWritebackSource *bsource = (QIOChannelBufferWritebackSource *)source;
|
||||
QIOChannelBufferWritebackSource* bsource =
|
||||
(QIOChannelBufferWritebackSource*)source;
|
||||
|
||||
return (*func)(QIO_CHANNEL(bsource->bioc),
|
||||
((G_IO_IN | G_IO_OUT) & bsource->condition),
|
||||
user_data);
|
||||
((G_IO_IN | G_IO_OUT) & bsource->condition), user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
qio_channel_buffer_writeback_source_finalize(GSource *source)
|
||||
static void qio_channel_buffer_writeback_source_finalize(GSource* source)
|
||||
{
|
||||
QIOChannelBufferWritebackSource *ssource = (QIOChannelBufferWritebackSource *)source;
|
||||
QIOChannelBufferWritebackSource* ssource =
|
||||
(QIOChannelBufferWritebackSource*)source;
|
||||
|
||||
object_unref(OBJECT(ssource->bioc));
|
||||
}
|
||||
@ -242,19 +239,19 @@ GSourceFuncs qio_channel_buffer_writeback_source_funcs = {
|
||||
qio_channel_buffer_writeback_source_prepare,
|
||||
qio_channel_buffer_writeback_source_check,
|
||||
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)
|
||||
{
|
||||
QIOChannelBufferWriteback *bioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||
QIOChannelBufferWritebackSource *ssource;
|
||||
GSource *source;
|
||||
QIOChannelBufferWriteback* bioc = QIO_CHANNEL_BUFFER_WRITEBACK(ioc);
|
||||
QIOChannelBufferWritebackSource* ssource;
|
||||
GSource* source;
|
||||
|
||||
source = g_source_new(&qio_channel_buffer_writeback_source_funcs,
|
||||
sizeof(QIOChannelBufferWritebackSource));
|
||||
ssource = (QIOChannelBufferWritebackSource *)source;
|
||||
ssource = (QIOChannelBufferWritebackSource*)source;
|
||||
|
||||
ssource->bioc = bioc;
|
||||
object_ref(OBJECT(bioc));
|
||||
@ -264,10 +261,11 @@ static GSource *qio_channel_buffer_writeback_create_watch(QIOChannel *ioc,
|
||||
return source;
|
||||
}
|
||||
|
||||
static void qio_channel_buffer_writeback_class_init(ObjectClass *klass,
|
||||
void *class_data G_GNUC_UNUSED)
|
||||
static void
|
||||
qio_channel_buffer_writeback_class_init(ObjectClass* klass,
|
||||
void* class_data G_GNUC_UNUSED)
|
||||
{
|
||||
QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
|
||||
QIOChannelClass* ioc_klass = QIO_CHANNEL_CLASS(klass);
|
||||
|
||||
ioc_klass->io_writev = qio_channel_buffer_writeback_writev;
|
||||
ioc_klass->io_readv = qio_channel_buffer_writeback_readv;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "migration/qemu-file.h"
|
||||
#include "io/channel-buffer.h"
|
||||
#include "migration/vmstate.h"
|
||||
@ -14,14 +15,16 @@ int libafl_restoring_devices;
|
||||
|
||||
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
|
||||
DeviceSaveState* device_save_all(void) {
|
||||
DeviceSaveState* device_save_all(void)
|
||||
{
|
||||
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) {
|
||||
if (!strcmp(str, *list)) {
|
||||
return 1;
|
||||
@ -31,19 +34,23 @@ static int is_in_list(char* str, char** list) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names) {
|
||||
DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names)
|
||||
{
|
||||
DeviceSaveState* dss = g_new0(DeviceSaveState, 1);
|
||||
SaveStateEntry *se;
|
||||
SaveStateEntry* se;
|
||||
|
||||
dss->kind = DEVICE_SAVE_KIND_FULL;
|
||||
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);
|
||||
|
||||
QEMUFile* f = qemu_file_new_output(ioc);
|
||||
|
||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
|
||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (se->is_ram) {
|
||||
@ -84,10 +91,12 @@ DeviceSaveState* device_save_kind(DeviceSnapshotKind kind, char** names) {
|
||||
return dss;
|
||||
}
|
||||
|
||||
void device_restore_all(DeviceSaveState* dss) {
|
||||
void device_restore_all(DeviceSaveState* dss)
|
||||
{
|
||||
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);
|
||||
|
||||
QEMUFile* f = qemu_file_new_input(ioc);
|
||||
@ -103,21 +112,19 @@ void device_restore_all(DeviceSaveState* dss) {
|
||||
qemu_fclose(f);
|
||||
}
|
||||
|
||||
void device_free_all(DeviceSaveState* dss) {
|
||||
g_free(dss->save_buffer);
|
||||
}
|
||||
void device_free_all(DeviceSaveState* dss) { g_free(dss->save_buffer); }
|
||||
|
||||
char** device_list_all(void) {
|
||||
SaveStateEntry *se;
|
||||
char** device_list_all(void)
|
||||
{
|
||||
SaveStateEntry* se;
|
||||
|
||||
size_t size = 1;
|
||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
|
||||
size++;
|
||||
}
|
||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { size++; }
|
||||
|
||||
char** list = malloc(size * sizeof(char*));
|
||||
size_t i = 0;
|
||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
|
||||
QTAILQ_FOREACH(se, &savevm_state.handlers, entry)
|
||||
{
|
||||
if (se->is_ram) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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->max_nb_chunks = max_size;
|
||||
|
||||
@ -38,9 +40,10 @@ void syx_cow_cache_pop_layer(SyxCowCache* scc)
|
||||
// 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;
|
||||
|
||||
g_hash_table_remove_all(sccd->positions);
|
||||
g_array_set_size(sccd->data, 0);
|
||||
@ -51,7 +54,8 @@ void syx_cow_cache_flush_highest_layer(SyxCowCache* scc)
|
||||
SyxCowCacheLayer* highest_layer = QTAILQ_FIRST(&scc->layers);
|
||||
|
||||
// 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)
|
||||
@ -61,22 +65,30 @@ void syx_cow_cache_move(SyxCowCache* lhs, SyxCowCache** rhs)
|
||||
*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;
|
||||
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
|
||||
if (found) {
|
||||
void* data_position_ptr = 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));
|
||||
void* data_position_ptr =
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
//
|
||||
@ -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);
|
||||
//
|
||||
// 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) {
|
||||
// data_position = GUINT_TO_POINTER(sccd->data->len);
|
||||
// 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));
|
||||
// }
|
||||
|
||||
// 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);
|
||||
|
||||
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) {
|
||||
data_position = GUINT_TO_POINTER(sccd->data->len);
|
||||
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) ==
|
||||
chunk_size);
|
||||
assert(qemu_iovec_to_buf(qiov, qiov_offset, data_position_ptr,
|
||||
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));
|
||||
|
||||
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
|
||||
if (!cache_entry) {
|
||||
@ -134,62 +159,79 @@ static bool read_chunk_from_cache_layer(SyxCowCacheLayer* sccl, BlockBackend* bl
|
||||
assert(cache_entry && cache_entry->data);
|
||||
|
||||
// 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.
|
||||
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) {
|
||||
// todo: determine if it is worth developing an unaligned access version.
|
||||
printf("error: 0x%zx %% 0x%lx == 0x%lx\n", qiov->size, sccl->chunk_size, qiov->size % sccl->chunk_size);
|
||||
// todo: determine if it is worth developing an unaligned access
|
||||
// version.
|
||||
printf("error: 0x%zx %% 0x%lx == 0x%lx\n", qiov->size, sccl->chunk_size,
|
||||
qiov->size % sccl->chunk_size);
|
||||
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)) {
|
||||
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->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);
|
||||
cache_entry->data = g_array_sized_new(false, false, sccl->chunk_size,
|
||||
INITIAL_NB_CHUNKS_PER_DEVICE);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// write cached page
|
||||
uint64_t blk_offset = offset;
|
||||
size_t qiov_offset = 0;
|
||||
for (; qiov_offset < qiov->size; blk_offset += sccl->chunk_size, qiov_offset += sccl->chunk_size) {
|
||||
write_chunk_to_cache_layer_device(cache_entry, qiov, qiov_offset, blk_offset);
|
||||
for (; qiov_offset < qiov->size;
|
||||
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;
|
||||
}
|
||||
|
||||
void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend *blk, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t _qiov_offset,
|
||||
BdrvRequestFlags flags)
|
||||
void syx_cow_cache_read_entry(SyxCowCache* scc, BlockBackend* blk,
|
||||
int64_t offset, int64_t bytes, QEMUIOVector* qiov,
|
||||
size_t _qiov_offset, BdrvRequestFlags flags)
|
||||
{
|
||||
SyxCowCacheLayer* layer;
|
||||
uint64_t blk_offset = offset;
|
||||
size_t qiov_offset = 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.
|
||||
assert(blk_co_preadv(blk, offset, bytes, qiov, flags) >= 0);
|
||||
|
||||
// Then fix the chunks that have been read from before.
|
||||
if (!QTAILQ_EMPTY(&scc->layers)) {
|
||||
for (;qiov_offset < qiov->size; blk_offset += chunk_size, qiov_offset += chunk_size) {
|
||||
QTAILQ_FOREACH(layer, &scc->layers, next) {
|
||||
for (; qiov_offset < qiov->size;
|
||||
blk_offset += chunk_size, qiov_offset += chunk_size) {
|
||||
QTAILQ_FOREACH(layer, &scc->layers, next)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
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);
|
||||
if (layer) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "qemu/main-loop.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "migration/vmstate.h"
|
||||
@ -14,13 +15,13 @@
|
||||
#define SYX_SNAPSHOT_LIST_INIT_SIZE 4096
|
||||
#define SYX_SNAPSHOT_LIST_GROW_FACTOR 2
|
||||
#define TARGET_NEXT_PAGE_ADDR(p) \
|
||||
((typeof(p))(((uintptr_t) p + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK))
|
||||
((typeof(p))(((uintptr_t)p + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK))
|
||||
|
||||
/**
|
||||
* Saved ramblock
|
||||
*/
|
||||
typedef struct SyxSnapshotRAMBlock {
|
||||
uint8_t *ram; // RAM block
|
||||
uint8_t* ram; // RAM block
|
||||
uint64_t used_length; // Length of the ram block
|
||||
} SyxSnapshotRAMBlock;
|
||||
|
||||
@ -37,11 +38,11 @@ typedef struct SyxSnapshotRoot {
|
||||
*/
|
||||
typedef struct SyxSnapshotDirtyPage {
|
||||
ram_addr_t offset_within_rb;
|
||||
uint8_t *data;
|
||||
uint8_t* data;
|
||||
} SyxSnapshotDirtyPage;
|
||||
|
||||
typedef struct SyxSnapshotDirtyPageList {
|
||||
SyxSnapshotDirtyPage *dirty_pages;
|
||||
SyxSnapshotDirtyPage* dirty_pages;
|
||||
uint64_t length;
|
||||
} SyxSnapshotDirtyPageList;
|
||||
|
||||
@ -51,36 +52,57 @@ typedef struct SyxSnapshotDirtyPageList {
|
||||
*/
|
||||
typedef struct SyxSnapshotIncrement {
|
||||
// Back to root snapshot if NULL
|
||||
struct SyxSnapshotIncrement *parent;
|
||||
struct SyxSnapshotIncrement* parent;
|
||||
|
||||
DeviceSaveState *dss;
|
||||
DeviceSaveState* dss;
|
||||
|
||||
GHashTable *rbs_dirty_pages; // hash map: H(rb) -> SyxSnapshotDirtyPageList
|
||||
GHashTable* rbs_dirty_pages; // hash map: H(rb) -> SyxSnapshotDirtyPageList
|
||||
} SyxSnapshotIncrement;
|
||||
|
||||
|
||||
SyxSnapshotState syx_snapshot_state = {0};
|
||||
static MemoryRegion* mr_to_enable = NULL;
|
||||
|
||||
static void destroy_ramblock_snapshot(gpointer root_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 rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr, gpointer rbs_dirty_pages_ptr);
|
||||
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
|
||||
rb_save_dirty_addr_to_table(gpointer offset_within_rb, gpointer unused,
|
||||
gpointer rb_dirty_list_to_page_args_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 void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash,
|
||||
gpointer rb_dirty_list_hash_table_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)
|
||||
{
|
||||
RAMBlock* block;
|
||||
RAMBLOCK_FOREACH(block) {
|
||||
RAMBLOCK_FOREACH(block)
|
||||
{
|
||||
if (rb_idstr_hash == GINT_TO_POINTER(block->idstr_hash)) {
|
||||
return block;
|
||||
}
|
||||
@ -90,7 +112,9 @@ static RAMBlock* ramblock_lookup(gpointer rb_idstr_hash)
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
struct rb_dirty_list_to_page_args {
|
||||
@ -120,48 +144,51 @@ struct rb_check_memory_args {
|
||||
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;
|
||||
|
||||
syx_snapshot_state.page_size = page_size;
|
||||
syx_snapshot_state.page_mask = ((uint64_t) -1) << __builtin_ctz(page_size);
|
||||
syx_snapshot_state.page_mask = ((uint64_t)-1) << __builtin_ctz(page_size);
|
||||
|
||||
syx_snapshot_state.tracked_snapshots = syx_snapshot_tracker_init();
|
||||
|
||||
if (cached_bdrvs) {
|
||||
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;
|
||||
}
|
||||
|
||||
SyxSnapshot *syx_snapshot_new(bool track, bool is_active_bdrv_cache, DeviceSnapshotKind kind, char **devices) {
|
||||
SyxSnapshot *snapshot = g_new0(SyxSnapshot, 1);
|
||||
SyxSnapshot* syx_snapshot_new(bool track, bool is_active_bdrv_cache,
|
||||
DeviceSnapshotKind kind, char** devices)
|
||||
{
|
||||
SyxSnapshot* snapshot = g_new0(SyxSnapshot, 1);
|
||||
|
||||
snapshot->root_snapshot = syx_snapshot_root_new(kind, devices);
|
||||
snapshot->last_incremental_snapshot = NULL;
|
||||
snapshot->rbs_dirty_list = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
|
||||
(GDestroyNotify) g_hash_table_remove_all);
|
||||
snapshot->rbs_dirty_list =
|
||||
g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
|
||||
(GDestroyNotify)g_hash_table_remove_all);
|
||||
snapshot->bdrvs_cow_cache = syx_cow_cache_new();
|
||||
|
||||
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;
|
||||
} 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) {
|
||||
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;
|
||||
|
||||
return snapshot;
|
||||
@ -190,55 +217,67 @@ static void destroy_ramblock_snapshot(gpointer root_snapshot)
|
||||
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);
|
||||
|
||||
RAMBlock *block;
|
||||
RAMBlock *inner_block;
|
||||
DeviceSaveState *dss = device_save_kind(kind, devices);
|
||||
RAMBlock* block;
|
||||
RAMBlock* inner_block;
|
||||
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;
|
||||
|
||||
RAMBLOCK_FOREACH(block) {
|
||||
RAMBLOCK_FOREACH(inner_block) {
|
||||
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.",
|
||||
RAMBLOCK_FOREACH(block)
|
||||
{
|
||||
RAMBLOCK_FOREACH(inner_block)
|
||||
{
|
||||
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);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
SyxSnapshotRAMBlock *snapshot_rb = g_new(SyxSnapshotRAMBlock, 1);
|
||||
SyxSnapshotRAMBlock* snapshot_rb = g_new(SyxSnapshotRAMBlock, 1);
|
||||
snapshot_rb->used_length = block->used_length;
|
||||
snapshot_rb->ram = g_new(uint8_t, 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;
|
||||
}
|
||||
|
||||
static void syx_snapshot_root_free(SyxSnapshotRoot *root) {
|
||||
static void syx_snapshot_root_free(SyxSnapshotRoot* root)
|
||||
{
|
||||
g_hash_table_destroy(root->rbs_snapshot);
|
||||
g_free(root);
|
||||
}
|
||||
|
||||
SyxSnapshotTracker syx_snapshot_tracker_init(void) {
|
||||
SyxSnapshotTracker syx_snapshot_tracker_init(void)
|
||||
{
|
||||
SyxSnapshotTracker tracker = {
|
||||
.length = 0,
|
||||
.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;
|
||||
}
|
||||
|
||||
void syx_snapshot_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) {
|
||||
void syx_snapshot_track(SyxSnapshotTracker* tracker, SyxSnapshot* snapshot)
|
||||
{
|
||||
if (tracker->length == tracker->capacity) {
|
||||
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);
|
||||
@ -247,11 +286,13 @@ void syx_snapshot_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot) {
|
||||
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) {
|
||||
if (tracker->tracked_snapshots[i] == snapshot) {
|
||||
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--;
|
||||
return;
|
||||
@ -262,39 +303,45 @@ void syx_snapshot_stop_track(SyxSnapshotTracker *tracker, SyxSnapshot *snapshot)
|
||||
abort();
|
||||
}
|
||||
|
||||
static void
|
||||
rb_save_dirty_addr_to_table(gpointer offset_within_rb, 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;
|
||||
RAMBlock *rb = args->rb;
|
||||
SyxSnapshotDirtyPage *dirty_page = &args->dirty_page_list->dirty_pages[*args->table_idx];
|
||||
dirty_page->offset_within_rb = (ram_addr_t) offset_within_rb;
|
||||
static void rb_save_dirty_addr_to_table(gpointer offset_within_rb,
|
||||
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;
|
||||
RAMBlock* rb = args->rb;
|
||||
SyxSnapshotDirtyPage* dirty_page =
|
||||
&args->dirty_page_list->dirty_pages[*args->table_idx];
|
||||
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;
|
||||
}
|
||||
|
||||
static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash, gpointer rb_dirty_list_hash_table_ptr,
|
||||
gpointer rbs_dirty_pages_ptr) {
|
||||
GHashTable *rbs_dirty_pages = rbs_dirty_pages_ptr;
|
||||
GHashTable *rb_dirty_list = rb_dirty_list_hash_table_ptr;
|
||||
static void rb_dirty_list_to_dirty_pages(gpointer rb_idstr_hash,
|
||||
gpointer rb_dirty_list_hash_table_ptr,
|
||||
gpointer rbs_dirty_pages_ptr)
|
||||
{
|
||||
GHashTable* rbs_dirty_pages = rbs_dirty_pages_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) {
|
||||
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->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 = {
|
||||
.rb = rb,
|
||||
.table_idx = ctr,
|
||||
.dirty_page_list = dirty_page_list
|
||||
};
|
||||
.rb = rb, .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);
|
||||
} 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) {
|
||||
SyxSnapshotDirtyPageList *snapshot_dirty_page_list = snapshot_dirty_page_list_ptr;
|
||||
static void
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
void syx_snapshot_increment_push(SyxSnapshot *snapshot, DeviceSnapshotKind kind, char **devices) {
|
||||
SyxSnapshotIncrement *increment = g_new0(SyxSnapshotIncrement, 1);
|
||||
void syx_snapshot_increment_push(SyxSnapshot* snapshot, DeviceSnapshotKind kind,
|
||||
char** devices)
|
||||
{
|
||||
SyxSnapshotIncrement* increment = g_new0(SyxSnapshotIncrement, 1);
|
||||
increment->parent = snapshot->last_incremental_snapshot;
|
||||
snapshot->last_incremental_snapshot = increment;
|
||||
|
||||
increment->rbs_dirty_pages = g_hash_table_new_full(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);
|
||||
increment->rbs_dirty_pages = g_hash_table_new_full(
|
||||
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);
|
||||
increment->dss = device_save_kind(kind, devices);
|
||||
|
||||
g_hash_table_remove_all(snapshot->rbs_dirty_list);
|
||||
}
|
||||
|
||||
static SyxSnapshotDirtyPage *
|
||||
get_dirty_page_from_addr_rec(SyxSnapshotIncrement *increment, RAMBlock *rb, ram_addr_t offset_within_rb) {
|
||||
static SyxSnapshotDirtyPage*
|
||||
get_dirty_page_from_addr_rec(SyxSnapshotIncrement* increment, RAMBlock* rb,
|
||||
ram_addr_t offset_within_rb)
|
||||
{
|
||||
if (increment == 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) {
|
||||
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,
|
||||
gpointer _unused, gpointer args_ptr)
|
||||
{
|
||||
struct rb_page_increment_restore_args* args = args_ptr;
|
||||
RAMBlock* rb = args->rb;
|
||||
SyxSnapshot* snapshot = args->snapshot;
|
||||
SyxSnapshotIncrement* increment = args->increment;
|
||||
ram_addr_t offset = (ram_addr_t)offset_within_rb;
|
||||
|
||||
static void restore_dirty_page_to_increment(gpointer offset_within_rb, gpointer _unused, gpointer args_ptr) {
|
||||
struct rb_page_increment_restore_args *args = args_ptr;
|
||||
RAMBlock *rb = args->rb;
|
||||
SyxSnapshot *snapshot = args->snapshot;
|
||||
SyxSnapshotIncrement *increment = args->increment;
|
||||
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) {
|
||||
memcpy(rb->host + offset, dp->data, syx_snapshot_state.page_size);
|
||||
} 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));
|
||||
assert(rrb);
|
||||
|
||||
@ -366,31 +426,34 @@ 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) {
|
||||
struct rb_increment_restore_args *args = args_ptr;
|
||||
GHashTable *rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_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;
|
||||
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 = {
|
||||
.snapshot = args->snapshot,
|
||||
.increment = args->increment,
|
||||
.rb = rb
|
||||
};
|
||||
.snapshot = args->snapshot, .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) {
|
||||
struct rb_increment_restore_args args = {
|
||||
.snapshot = snapshot,
|
||||
.increment = increment
|
||||
};
|
||||
static void restore_to_increment(SyxSnapshot* snapshot,
|
||||
SyxSnapshotIncrement* 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) {
|
||||
SyxSnapshotIncrement *last_increment = snapshot->last_incremental_snapshot;
|
||||
void syx_snapshot_increment_pop(SyxSnapshot* snapshot)
|
||||
{
|
||||
SyxSnapshotIncrement* last_increment = snapshot->last_incremental_snapshot;
|
||||
|
||||
device_restore_all(last_increment->dss);
|
||||
restore_to_increment(snapshot, last_increment);
|
||||
@ -401,8 +464,9 @@ void syx_snapshot_increment_pop(SyxSnapshot *snapshot) {
|
||||
syx_snapshot_dirty_list_flush(snapshot);
|
||||
}
|
||||
|
||||
void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot) {
|
||||
SyxSnapshotIncrement *last_increment = snapshot->last_incremental_snapshot;
|
||||
void syx_snapshot_increment_restore_last(SyxSnapshot* snapshot)
|
||||
{
|
||||
SyxSnapshotIncrement* last_increment = snapshot->last_incremental_snapshot;
|
||||
|
||||
device_restore_all(last_increment->dss);
|
||||
restore_to_increment(snapshot, last_increment);
|
||||
@ -410,51 +474,62 @@ void syx_snapshot_increment_restore_last(SyxSnapshot *snapshot) {
|
||||
syx_snapshot_dirty_list_flush(snapshot);
|
||||
}
|
||||
|
||||
static SyxSnapshotIncrement *syx_snapshot_increment_free(SyxSnapshotIncrement *increment) {
|
||||
SyxSnapshotIncrement *parent_increment = increment->parent;
|
||||
static SyxSnapshotIncrement*
|
||||
syx_snapshot_increment_free(SyxSnapshotIncrement* increment)
|
||||
{
|
||||
SyxSnapshotIncrement* parent_increment = increment->parent;
|
||||
g_hash_table_destroy(increment->rbs_dirty_pages);
|
||||
device_free_all(increment->dss);
|
||||
g_free(increment);
|
||||
return parent_increment;
|
||||
}
|
||||
|
||||
static void syx_snapshot_dirty_list_flush(SyxSnapshot *snapshot) {
|
||||
g_hash_table_foreach(snapshot->rbs_dirty_list, empty_rb_dirty_list, (gpointer) snapshot);
|
||||
static void syx_snapshot_dirty_list_flush(SyxSnapshot* 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) {
|
||||
assert((offset & syx_snapshot_state.page_mask) == offset); // offsets should always be page-aligned.
|
||||
static inline void syx_snapshot_dirty_list_add_internal(RAMBlock* rb,
|
||||
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) {
|
||||
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)) {
|
||||
#ifdef SYX_SNAPSHOT_DEBUG
|
||||
printf("rb_dirty_list did not exit, creating...\n");
|
||||
#endif
|
||||
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))) {
|
||||
#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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool syx_snapshot_is_enabled(void) {
|
||||
return syx_snapshot_state.is_enabled;
|
||||
}
|
||||
bool syx_snapshot_is_enabled(void) { return syx_snapshot_state.is_enabled; }
|
||||
|
||||
/*
|
||||
// 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.
|
||||
__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
|
||||
if (!syx_snapshot_is_enabled()) {
|
||||
return;
|
||||
@ -472,14 +547,15 @@ __attribute__((target("no-3dnow,no-sse,no-mmx"),no_caller_saved_registers)) void
|
||||
*/
|
||||
|
||||
// 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
|
||||
if (!syx_snapshot_is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ram_addr_t offset;
|
||||
RAMBlock *rb = qemu_ram_block_from_host((void *) host_addr, true, &offset);
|
||||
RAMBlock* rb = qemu_ram_block_from_host((void*)host_addr, true, &offset);
|
||||
|
||||
#ifdef SYX_SNAPSHOT_DEBUG
|
||||
SYX_PRINTF("Should mark offset 0x%lx as dirty\n", offset);
|
||||
@ -492,17 +568,19 @@ void syx_snapshot_dirty_list_add_hostaddr(void *host_addr) {
|
||||
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
|
||||
if (!syx_snapshot_is_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
void *next_page_addr = TARGET_NEXT_PAGE_ADDR(host_addr);
|
||||
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);
|
||||
assert(next_page_addr > host_addr);
|
||||
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) {
|
||||
GHashTable *rb_dirty_hash_table = rb_dirty_list_hash_table_ptr;
|
||||
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;
|
||||
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) {
|
||||
struct rb_page_root_restore_args *args = root_restore_args_ptr;
|
||||
RAMBlock *rb = args->rb;
|
||||
SyxSnapshotRAMBlock *snapshot_rb = args->snapshot_rb;
|
||||
|
||||
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;
|
||||
RAMBlock* rb = args->rb;
|
||||
SyxSnapshotRAMBlock* snapshot_rb = args->snapshot_rb;
|
||||
|
||||
// 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_snapshot_rb_restore = (gpointer) snapshot_rb->ram + (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;
|
||||
|
||||
#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
|
||||
|
||||
memcpy(host_rb_restore, host_snapshot_rb_restore, syx_snapshot_state.page_size);
|
||||
//TODO: manage special case of TSEG.
|
||||
memcpy(host_rb_restore, host_snapshot_rb_restore,
|
||||
syx_snapshot_state.page_size);
|
||||
// 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) {
|
||||
SyxSnapshot *snapshot = snapshot_ptr;
|
||||
GHashTable *rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr;
|
||||
RAMBlock *rb = ramblock_lookup(rb_idstr_hash);
|
||||
static void root_restore_rb(gpointer rb_idstr_hash,
|
||||
gpointer rb_dirty_pages_hash_table_ptr,
|
||||
gpointer snapshot_ptr)
|
||||
{
|
||||
SyxSnapshot* snapshot = snapshot_ptr;
|
||||
GHashTable* rb_dirty_pages_hash_table = rb_dirty_pages_hash_table_ptr;
|
||||
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
||||
|
||||
if (rb) {
|
||||
SyxSnapshotRAMBlock *snapshot_ramblock = g_hash_table_lookup(snapshot->root_snapshot->rbs_snapshot,
|
||||
rb_idstr_hash);
|
||||
SyxSnapshotRAMBlock* snapshot_ramblock = g_hash_table_lookup(
|
||||
snapshot->root_snapshot->rbs_snapshot, rb_idstr_hash);
|
||||
|
||||
struct rb_page_root_restore_args root_restore_args = {
|
||||
.rb = rb,
|
||||
.snapshot_rb = snapshot_ramblock
|
||||
};
|
||||
.rb = rb, .snapshot_rb = snapshot_ramblock};
|
||||
|
||||
#ifdef CONFIG_DEBUG_TCG
|
||||
SYX_PRINTF("Restoring RB %s...\n", rb->idstr);
|
||||
#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
|
||||
g_hash_table_foreach(rb_dirty_pages_hash_table, root_restore_rb_page,
|
||||
&root_restore_args);
|
||||
} else {
|
||||
SYX_ERROR("Saved RAMBlock not found.");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void root_restore_check_memory_rb(gpointer rb_idstr_hash, gpointer rb_dirty_pages_hash_table_ptr,
|
||||
gpointer check_memory_args_ptr) {
|
||||
struct rb_check_memory_args *args = check_memory_args_ptr;
|
||||
SyxSnapshot *snapshot = args->snapshot;
|
||||
RAMBlock *rb = ramblock_lookup(rb_idstr_hash);
|
||||
static void root_restore_check_memory_rb(gpointer rb_idstr_hash,
|
||||
gpointer rb_dirty_pages_hash_table_ptr,
|
||||
gpointer check_memory_args_ptr)
|
||||
{
|
||||
struct rb_check_memory_args* args = check_memory_args_ptr;
|
||||
SyxSnapshot* snapshot = args->snapshot;
|
||||
RAMBlock* rb = ramblock_lookup(rb_idstr_hash);
|
||||
|
||||
if (rb) {
|
||||
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->used_length == rb_snapshot->used_length);
|
||||
|
||||
for (uint64_t i = 0; i < rb->used_length; i += syx_snapshot_state.page_size) {
|
||||
if (memcmp(rb->host + i, rb_snapshot->ram + i, syx_snapshot_state.page_size) != 0) {
|
||||
for (uint64_t i = 0; i < rb->used_length;
|
||||
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);
|
||||
for (uint64_t j = 0; j < syx_snapshot_state.page_size; 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++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (args->nb_inconsistent_pages > 0) {
|
||||
SYX_ERROR("[%s] Found %lu page %s.\n", rb->idstr, args->nb_inconsistent_pages,
|
||||
args->nb_inconsistent_pages > 1 ? "inconsistencies" : "inconsistency");
|
||||
SYX_ERROR("[%s] Found %lu page %s.\n", rb->idstr,
|
||||
args->nb_inconsistent_pages,
|
||||
args->nb_inconsistent_pages > 1 ? "inconsistencies"
|
||||
: "inconsistency");
|
||||
} else {
|
||||
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 = {
|
||||
.snapshot = ref_snapshot,
|
||||
.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 = {
|
||||
.nb_inconsistencies = args.nb_inconsistent_pages
|
||||
};
|
||||
struct SyxSnapshotCheckResult res = {.nb_inconsistencies =
|
||||
args.nb_inconsistent_pages};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void syx_snapshot_root_restore(SyxSnapshot *snapshot) {
|
||||
void syx_snapshot_root_restore(SyxSnapshot* snapshot)
|
||||
{
|
||||
// health check.
|
||||
CPUState *cpu;
|
||||
CPU_FOREACH(cpu) {
|
||||
assert(cpu->stopped);
|
||||
}
|
||||
CPUState* cpu;
|
||||
CPU_FOREACH(cpu) { assert(cpu->stopped); }
|
||||
|
||||
bool must_unlock_bql = false;
|
||||
|
||||
@ -638,7 +723,8 @@ void syx_snapshot_root_restore(SyxSnapshot *snapshot) {
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (!syx_snapshot_state.active_bdrv_cache_snapshot) {
|
||||
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 false;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!syx_snapshot_state.active_bdrv_cache_snapshot) {
|
||||
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 false;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ uintptr_t libafl_qemu_host_page_size(void)
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write)
|
||||
{
|
||||
if (addr == -1) {
|
||||
@ -15,10 +16,13 @@ uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write)
|
||||
|
||||
hwaddr xlat;
|
||||
MemoryRegion* mr;
|
||||
WITH_RCU_READ_LOCK_GUARD() {
|
||||
mr = address_space_translate(cpu->as, addr, &xlat, NULL, is_write, MEMTXATTRS_UNSPECIFIED);
|
||||
WITH_RCU_READ_LOCK_GUARD()
|
||||
{
|
||||
mr = address_space_translate(cpu->as, addr, &xlat, NULL, is_write,
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
}
|
||||
|
||||
return qemu_map_ram_ptr(mr->ram_block, xlat);
|
||||
}
|
||||
|
||||
#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,
|
||||
// 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,
|
||||
host_sigcontext *uc)
|
||||
@ -998,6 +997,8 @@ void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc);
|
||||
pc, guest_addr);
|
||||
} */
|
||||
|
||||
#include "libafl/user.h"
|
||||
|
||||
void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc) {
|
||||
host_signal_handler(host_sig, info, puc);
|
||||
}
|
||||
|
@ -54,6 +54,11 @@
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/signalfd.h>
|
||||
//#include <sys/user.h>
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
#include "libafl/hooks/syscall.h"
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
@ -6529,9 +6534,7 @@ typedef struct {
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
#include "libafl/hook.h"
|
||||
|
||||
extern __thread CPUArchState *libafl_qemu_env;
|
||||
#include "libafl/hooks/thread.h"
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
@ -6567,17 +6570,7 @@ static void *clone_func(void *arg)
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
libafl_qemu_env = 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 {
|
||||
if (libafl_hook_new_thread_run(env)) {
|
||||
cpu_loop(env);
|
||||
}
|
||||
|
||||
@ -13886,25 +13879,7 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1,
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
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;
|
||||
}
|
||||
bool skip_syscall = libafl_hook_syscall_pre_run(cpu_env, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, &ret);
|
||||
if (skip_syscall) goto after_syscall;
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
@ -13915,21 +13890,8 @@ abi_long do_syscall(CPUArchState *cpu_env, int num, abi_long arg1,
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
after_syscall:;
|
||||
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;
|
||||
}
|
||||
|
||||
libafl_hook_syscall_post_run(num, arg1, arg2, arg3, arg4,
|
||||
arg5, arg6, arg7, arg8, &ret);
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//// --- Begin LibAFL code ---
|
||||
|
||||
// #include "libafl/hooks/thread.h"
|
||||
|
||||
//// --- End LibAFL code ---
|
||||
|
||||
void qemu_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
@ -671,6 +677,23 @@ void qemu_init_vcpu(CPUState *cpu)
|
||||
while (!cpu->created) {
|
||||
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)
|
||||
|
@ -741,10 +741,14 @@ static int cpu_pre_save(void *opaque)
|
||||
}
|
||||
|
||||
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,
|
||||
cpu->cpreg_array_len * sizeof(uint64_t));
|
||||
memcpy(cpu->cpreg_vmstate_values, cpu->cpreg_values,
|
||||
cpu->cpreg_array_len * sizeof(uint64_t));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user