Skip to content

Commit 938efd1

Browse files
add block hook with instruction count (#2378)
Co-authored-by: Mark Leon Giraud <mark.giraud@iosb.fraunhofer.de>
1 parent 09bd8e4 commit 938efd1

6 files changed

Lines changed: 91 additions & 4 deletions

File tree

include/uc_priv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ typedef enum uc_hook_idx {
219219
UC_HOOK_EDGE_GENERATED_IDX,
220220
UC_HOOK_TCG_OPCODE_IDX,
221221
UC_HOOK_TLB_FILL_IDX,
222+
UC_HOOK_BLOCK_ICOUNT_IDX,
222223

223224
UC_HOOK_MAX,
224225
} uc_hook_idx;
@@ -533,6 +534,8 @@ static inline void hooked_regions_check(uc_engine *uc, uint64_t start,
533534
hooked_regions_check_single(uc->hook[UC_HOOK_CODE_IDX].head, start, length);
534535
hooked_regions_check_single(uc->hook[UC_HOOK_BLOCK_IDX].head, start,
535536
length);
537+
hooked_regions_check_single(uc->hook[UC_HOOK_BLOCK_ICOUNT_IDX].head, start,
538+
length);
536539
}
537540

538541
/*

include/unicorn/unicorn.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,8 @@ typedef enum uc_hook_type {
408408
// Register tlb fill request hook on the virtuall addresses.
409409
// The callback will be triggert if the tlb cache don't contain an address.
410410
UC_HOOK_TLB_FILL = 1 << 17,
411+
// Hook basic blocks but get the number of instructions as size
412+
UC_HOOK_BLOCK_ICOUNT = 1 << 18,
411413
} uc_hook_type;
412414

413415
// Hook type for all events of unmapped memory access

qemu/accel/tcg/translator.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
8080
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, uc, db->pc_first);
8181
}
8282

83+
if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_BLOCK_ICOUNT, tb->pc)) {
84+
ops->pc_sync(db, cpu);
85+
prev_op = tcg_last_op(tcg_ctx);
86+
block_hook = true;
87+
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f9, UC_HOOK_BLOCK_ICOUNT_IDX, uc, db->pc_first);
88+
}
89+
8390
// tcg_dump_ops(tcg_ctx, false, "translator loop");
8491

8592
/* Start translating. */
@@ -166,6 +173,10 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
166173
tcg_op = QTAILQ_FIRST(&tcg_ctx->ops);
167174
}
168175

169-
tcg_op->args[1] = db->tb->size;
176+
if (tcg_op->args[1] == 0xf8f8f8f8) {
177+
tcg_op->args[1] = db->tb->size;
178+
} else {
179+
tcg_op->args[1] = db->tb->icount;
180+
}
170181
}
171182
}

qemu/tcg/tcg.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ void uc_add_inline_hook(uc_engine *uc, struct hook *hk, void** args, int args_le
686686
// Only UC_HOOK_BLOCK and UC_HOOK_CODE is generated into tcg code and can be inlined.
687687
switch (hk->type) {
688688
case UC_HOOK_BLOCK:
689+
case UC_HOOK_BLOCK_ICOUNT:
689690
case UC_HOOK_CODE:
690691
// (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
691692
sizemask = dh_sizemask(void, 0) | dh_sizemask(ptr, 1) | dh_sizemask(i64, 2) | dh_sizemask(i32, 3) | dh_sizemask(ptr, 4);

tests/unit/test_ctl.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,48 @@ static void test_add_block_hook(void)
429429
OK(uc_close(uc));
430430
}
431431

432+
static void test_add_block_icount_hook_block_cb(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
433+
{
434+
uint64_t *icount = user_data;
435+
*icount += size;
436+
}
437+
438+
static void test_add_block_icount_hook(void)
439+
{
440+
uc_engine *uc;
441+
uint64_t icount = 0;
442+
uc_hook syscall_hook;
443+
uc_hook block_hook;
444+
/* nop
445+
* syscall
446+
*/
447+
char code[] = "\x90\x0F\x05";
448+
449+
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code) - 1);
450+
OK(uc_hook_add(uc, &syscall_hook, UC_HOOK_INSN, &test_add_block_hook_syscall_cb, NULL, 1, 0, UC_X86_INS_SYSCALL));
451+
OK(uc_emu_start(uc, code_start, 0, 0, 0));
452+
OK(uc_hook_add(uc, &block_hook, UC_HOOK_BLOCK_ICOUNT, &test_add_block_icount_hook_block_cb, &icount, code_start, code_start+0x1000));
453+
OK(uc_emu_start(uc, code_start, 0, 0, 0));
454+
TEST_CHECK(icount == 2);
455+
TEST_CHECK(uc_hook_add(uc, &block_hook, UC_HOOK_BLOCK, &test_add_block_icount_hook_block_cb, &icount, 0, code_start+0x1000) == UC_ERR_HOOK_EXIST);
456+
TEST_CHECK(uc_hook_add(uc, &block_hook, UC_HOOK_BLOCK,
457+
&test_add_block_icount_hook_block_cb, &icount,
458+
code_start + 0x1000,
459+
code_start + 0x2000) == UC_ERR_HOOK_EXIST);
460+
TEST_CHECK(uc_hook_add(uc, &block_hook,
461+
UC_HOOK_BLOCK | UC_HOOK_BLOCK_ICOUNT,
462+
&test_add_block_icount_hook_block_cb, &icount,
463+
code_start, code_start) == UC_ERR_HOOK);
464+
OK(uc_hook_del(uc, block_hook));
465+
OK(uc_hook_add(uc, &block_hook, UC_HOOK_BLOCK_ICOUNT,
466+
&test_add_block_icount_hook_block_cb, &icount, code_start,
467+
code_start));
468+
TEST_CHECK(uc_hook_add(uc, &block_hook, UC_HOOK_BLOCK,
469+
&test_add_block_icount_hook_block_cb, &icount,
470+
code_start, code_start) == UC_ERR_HOOK_EXIST);
471+
OK(uc_close(uc));
472+
}
473+
432474
TEST_LIST = {
433475
{"test_uc_ctl_mode", test_uc_ctl_mode},
434476
{"test_uc_ctl_page_size", test_uc_ctl_page_size},
@@ -448,4 +490,5 @@ TEST_LIST = {
448490
{"test_tlb_clear", test_tlb_clear},
449491
{"test_noexec", test_noexec},
450492
{"test_add_block_hook", test_add_block_hook},
493+
{"test_add_block_icount_hook", test_add_block_icount_hook},
451494
{NULL, NULL}};

uc.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,6 +1927,30 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
19271927

19281928
UC_INIT(uc);
19291929

1930+
int block_type = type & (UC_HOOK_BLOCK | UC_HOOK_BLOCK_ICOUNT);
1931+
if (block_type == (UC_HOOK_BLOCK | UC_HOOK_BLOCK_ICOUNT)) {
1932+
restore_jit_state(uc);
1933+
return UC_ERR_HOOK;
1934+
}
1935+
if (block_type != 0) {
1936+
int opposite_idx = block_type == UC_HOOK_BLOCK
1937+
? UC_HOOK_BLOCK_ICOUNT_IDX
1938+
: UC_HOOK_BLOCK_IDX;
1939+
for (struct list_item *c = uc->hook[opposite_idx].head; c;
1940+
c = c->next) {
1941+
struct hook *other = c->data;
1942+
if (other->to_delete) {
1943+
continue;
1944+
}
1945+
bool overlaps = begin > end || other->begin > other->end ||
1946+
(begin <= other->end && other->begin <= end);
1947+
if (overlaps) {
1948+
restore_jit_state(uc);
1949+
return UC_ERR_HOOK_EXIST;
1950+
}
1951+
}
1952+
}
1953+
19301954
struct hook *hook = calloc(1, sizeof(struct hook));
19311955
if (hook == NULL) {
19321956
restore_jit_state(uc);
@@ -2013,7 +2037,8 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
20132037
return UC_ERR_OK;
20142038
}
20152039

2016-
if (type & UC_HOOK_CODE || type & UC_HOOK_BLOCK) {
2040+
if (type & UC_HOOK_CODE || type & UC_HOOK_BLOCK ||
2041+
type & UC_HOOK_BLOCK_ICOUNT) {
20172042
if (end <= begin) {
20182043
uc->tb_flush(uc);
20192044
} else {
@@ -2073,7 +2098,8 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
20732098
// and store the type mask in the hook pointer.
20742099
for (i = 0; i < UC_HOOK_MAX; i++) {
20752100
if (list_exists(&uc->hook[i], (void *)hook)) {
2076-
if (hook->type & UC_HOOK_CODE || hook->type & UC_HOOK_BLOCK) {
2101+
if (hook->type & UC_HOOK_CODE || hook->type & UC_HOOK_BLOCK ||
2102+
hook->type & UC_HOOK_BLOCK_ICOUNT) {
20772103
g_hash_table_foreach(hook->hooked_regions,
20782104
hook_invalidate_region, uc);
20792105
}
@@ -2092,7 +2118,8 @@ UNICORN_EXPORT
20922118
uc_err uc_hook_set_user_data(uc_engine *uc, uc_hook hh, void *user_data)
20932119
{
20942120
struct hook *hook = (struct hook *)hh;
2095-
if (hook->type == UC_HOOK_BLOCK || hook->type == UC_HOOK_CODE) {
2121+
if (hook->type == UC_HOOK_BLOCK || hook->type == UC_HOOK_CODE ||
2122+
hook->type == UC_HOOK_BLOCK_ICOUNT) {
20962123
if (uc->nested_level) {
20972124
return UC_ERR_ARG;
20982125
}

0 commit comments

Comments
 (0)