static void test_instr_as_immed(void) { void *drcontext = dr_get_current_drcontext(); instrlist_t *ilist = instrlist_create(drcontext); byte *pc; instr_t *ins0, *ins1, *ins2; opnd_t opnd; byte *highmem = PREFERRED_ADDR; pc = dr_raw_mem_alloc(PAGE_SIZE, DR_MEMPROT_READ|DR_MEMPROT_WRITE| DR_MEMPROT_EXEC, highmem); ASSERT(pc == highmem); /* Test push_imm of instr */ ins0 = INSTR_CREATE_nop(drcontext); instrlist_append(ilist, ins0); instrlist_insert_push_instr_addr(drcontext, ins0, highmem, ilist, NULL, &ins1, &ins2); ASSERT(ins2 != NULL); instrlist_append(ilist, INSTR_CREATE_pop (drcontext, opnd_create_reg(DR_REG_RAX))); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, highmem, true); instrlist_clear(drcontext, ilist); ASSERT(pc < highmem + PAGE_SIZE); pc = ((byte* (*)(void))highmem)(); ASSERT(pc == highmem); /* Test mov_imm of instr */ ins0 = INSTR_CREATE_nop(drcontext); instrlist_append(ilist, ins0); /* Beyond TOS, but a convenient mem dest */ opnd = opnd_create_base_disp(DR_REG_RSP, DR_REG_NULL, 0, -8, OPSZ_8); instrlist_insert_mov_instr_addr(drcontext, ins0, highmem, opnd, ilist, NULL, &ins1, &ins2); ASSERT(ins2 != NULL); instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_RAX), opnd)); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, highmem, true); instrlist_clear(drcontext, ilist); ASSERT(pc < highmem + PAGE_SIZE); pc = ((byte* (*)(void))highmem)(); ASSERT(pc == highmem); instrlist_clear_and_destroy(drcontext, ilist); dr_raw_mem_free(highmem, PAGE_SIZE); }
/* code cache to hold the call to "clean_call" and return to DR code cache */ static void code_cache_init(void) { void *drcontext; instrlist_t *ilist; instr_t *where; byte *end; drcontext = dr_get_current_drcontext(); code_cache = dr_nonheap_alloc(PAGE_SIZE, DR_MEMPROT_READ | DR_MEMPROT_WRITE | DR_MEMPROT_EXEC); ilist = instrlist_create(drcontext); /* The lean procecure simply performs a clean call, and then jump back */ /* jump back to the DR's code cache */ where = INSTR_CREATE_jmp_ind(drcontext, opnd_create_reg(DR_REG_XCX)); instrlist_meta_append(ilist, where); /* clean call */ dr_insert_clean_call(drcontext, ilist, where, (void *)clean_call_ins_trace, false, 0); /* Encodes the instructions into memory and then cleans up. */ end = instrlist_encode(drcontext, ilist, code_cache, false); DR_ASSERT((end - code_cache) < PAGE_SIZE); instrlist_clear_and_destroy(drcontext, ilist); /* set the memory as just +rx now */ dr_memory_protect(code_cache, PAGE_SIZE, DR_MEMPROT_READ | DR_MEMPROT_EXEC); }
DR_EXPORT void dr_init(client_id_t id) { /* Generate the "slowpath" which just returns to eax. */ void *dc = dr_get_current_drcontext(); instrlist_t *ilist = instrlist_create(dc); PRE(ilist, NULL, INSTR_CREATE_jmp_ind(dc, opnd_create_reg(DR_REG_XAX))); slowpath = dr_nonheap_alloc(SLOWPATH_SIZE, (DR_MEMPROT_READ| DR_MEMPROT_WRITE| DR_MEMPROT_EXEC)); instrlist_encode(dc, ilist, slowpath, false /*no relative jumps*/); instrlist_clear_and_destroy(dc, ilist); dr_register_bb_event(event_bb); dr_register_exit_event(event_exit); }
static void reachability_test(void) { void *drcontext = dr_get_current_drcontext(); instrlist_t *ilist = instrlist_create(drcontext); byte *gencode = (byte *) dr_nonheap_alloc(PAGE_SIZE, DR_MEMPROT_READ|DR_MEMPROT_WRITE|DR_MEMPROT_EXEC); byte *pc; int res; byte *highmem = PREFERRED_ADDR; pc = dr_raw_mem_alloc(PAGE_SIZE, DR_MEMPROT_READ|DR_MEMPROT_WRITE| DR_MEMPROT_EXEC, highmem); ASSERT(pc == highmem); dr_fprintf(STDERR, " reachability test..."); /* Test auto-magically turning rip-rel that won't reach but targets xax * into absmem. */ instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_EAX), opnd_create_rel_addr(highmem, OPSZ_4))); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, gencode, false); instrlist_clear(drcontext, ilist); ASSERT(pc < gencode + PAGE_SIZE); *(int*)highmem = 0x12345678; res = ((int (*)(void))gencode)(); ASSERT(res == 0x12345678); /* Test auto-magically turning a reachable absmem into a rip-rel. */ instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_ECX), opnd_create_abs_addr(highmem + 0x800, OPSZ_4))); instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_EAX), opnd_create_reg(DR_REG_ECX))); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, highmem, false); instrlist_clear(drcontext, ilist); ASSERT(pc < highmem + PAGE_SIZE); *(int*)(highmem + 0x800) = 0x12345678; res = ((int (*)(void))highmem)(); ASSERT(res == 0x12345678); dr_raw_mem_free(highmem, PAGE_SIZE); /* Test targeting upper 2GB of low 4GB */ highmem = dr_raw_mem_alloc(PAGE_SIZE, DR_MEMPROT_READ|DR_MEMPROT_WRITE| DR_MEMPROT_EXEC, (byte *)0xabcd0000); instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_ECX), opnd_create_abs_addr(highmem, OPSZ_4))); instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_EAX), opnd_create_reg(DR_REG_ECX))); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, gencode, false); instrlist_clear(drcontext, ilist); ASSERT(pc < gencode + PAGE_SIZE); *(int*)highmem = 0x12345678; res = ((int (*)(void))gencode)(); ASSERT(res == 0x12345678); dr_raw_mem_free(highmem, PAGE_SIZE); /* Test targeting lower 2GB of low 4GB */ highmem = dr_raw_mem_alloc(PAGE_SIZE, DR_MEMPROT_READ|DR_MEMPROT_WRITE| DR_MEMPROT_EXEC, (byte *)0x143d0000); instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_ECX), opnd_create_abs_addr(highmem, OPSZ_4))); instrlist_append(ilist, INSTR_CREATE_mov_ld (drcontext, opnd_create_reg(DR_REG_EAX), opnd_create_reg(DR_REG_ECX))); instrlist_append(ilist, INSTR_CREATE_ret(drcontext)); pc = instrlist_encode(drcontext, ilist, gencode, false); instrlist_clear(drcontext, ilist); ASSERT(pc < gencode + PAGE_SIZE); *(int*)highmem = 0x12345678; res = ((int (*)(void))gencode)(); ASSERT(res == 0x12345678); dr_raw_mem_free(highmem, PAGE_SIZE); instrlist_clear_and_destroy(drcontext, ilist); dr_nonheap_free(gencode, PAGE_SIZE); test_instr_as_immed(); dr_fprintf(STDERR, "success\n"); }
static void test_instr_opnds(void *dc) { /* Verbose disasm looks like this: * 32-bit: * 0x080f1ae0 ff 25 e7 1a 0f 08 jmp 0x080f1ae7 * 0x080f1ae6 b8 ef be ad de mov $0xdeadbeef -> %eax * 0x080f1ae0 a0 e6 1a 0f 08 mov 0x080f1ae6 -> %al * 0x080f1ae5 b8 ef be ad de mov $0xdeadbeef -> %eax * 64-bit: * 0x00000000006b8de0 ff 25 02 00 00 00 jmp <rel> 0x00000000006b8de8 * 0x00000000006b8de6 48 b8 ef be ad de 00 mov $0x00000000deadbeef -> %rax * 00 00 00 * 0x00000000006b8de0 8a 05 02 00 00 00 mov <rel> 0x00000000006b8de8 -> %al * 0x00000000006b8de6 48 b8 ef be ad de 00 mov $0x00000000deadbeef -> %rax * 00 00 00 */ instrlist_t *ilist; instr_t *tgt, *instr; byte *pc; short disp; ilist = instrlist_create(dc); /* test mem instr as ind jmp target */ tgt = INSTR_CREATE_mov_imm(dc, opnd_create_reg(DR_REG_XAX), opnd_create_immed_int(0xdeadbeef, OPSZ_PTR)); /* skip rex+opcode */ disp = IF_X64_ELSE(2,1); instrlist_append(ilist, INSTR_CREATE_jmp_ind (dc, opnd_create_mem_instr(tgt, disp, OPSZ_PTR))); instrlist_append(ilist, tgt); pc = instrlist_encode(dc, ilist, buf, true/*instr targets*/); ASSERT(pc != NULL); instrlist_clear(dc, ilist); #if VERBOSE pc = disassemble_with_info(dc, buf, STDOUT, true, true); pc = disassemble_with_info(dc, pc, STDOUT, true, true); #endif pc = buf; instr = instr_create(dc); pc = decode(dc, pc, instr); ASSERT(pc != NULL); ASSERT(instr_get_opcode(instr) == OP_jmp_ind); #ifdef X64 ASSERT(opnd_is_rel_addr(instr_get_src(instr, 0))); ASSERT(opnd_get_addr(instr_get_src(instr, 0)) == pc + disp); #else ASSERT(opnd_is_base_disp(instr_get_src(instr, 0))); ASSERT(opnd_get_base(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_index(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_disp(instr_get_src(instr, 0)) == (ptr_int_t)pc + disp); #endif /* test mem instr as TYPE_O */ tgt = INSTR_CREATE_mov_imm(dc, opnd_create_reg(DR_REG_XAX), opnd_create_immed_int(0xdeadbeef, OPSZ_PTR)); /* skip rex+opcode */ disp = IF_X64_ELSE(2,1); instrlist_append(ilist, INSTR_CREATE_mov_ld (dc, opnd_create_reg(DR_REG_AL), opnd_create_mem_instr(tgt, disp, OPSZ_1))); instrlist_append(ilist, tgt); pc = instrlist_encode(dc, ilist, buf, true/*instr targets*/); ASSERT(pc != NULL); instrlist_clear(dc, ilist); #if VERBOSE pc = disassemble_with_info(dc, buf, STDOUT, true, true); pc = disassemble_with_info(dc, pc, STDOUT, true, true); #endif pc = buf; instr_reset(dc, instr); pc = decode(dc, pc, instr); ASSERT(pc != NULL); ASSERT(instr_get_opcode(instr) == OP_mov_ld); #ifdef X64 ASSERT(opnd_is_rel_addr(instr_get_src(instr, 0))); ASSERT(opnd_get_addr(instr_get_src(instr, 0)) == pc + disp); #else ASSERT(opnd_is_base_disp(instr_get_src(instr, 0))); ASSERT(opnd_get_base(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_index(instr_get_src(instr, 0)) == REG_NULL); ASSERT(opnd_get_disp(instr_get_src(instr, 0)) == (ptr_int_t)pc + disp); #endif instr_free(dc, instr); instrlist_destroy(dc, ilist); }
/* make sure the following are consistent (though they could still all be wrong :)) * with respect to instr length and opcode: * - decode_fast * - decode * - INSTR_CREATE_ * - encode */ static void test_all_opcodes(void *dc) { byte *pc, *next_pc; byte *end; instrlist_t *ilist = instrlist_create(dc); instr_t *instr; /* we cannot pass on variadic args as separate args to another * macro, so we must split ours by # args (xref PR 208603) */ # define MEMARG(sz) (opnd_create_base_disp(REG_XCX, REG_NULL, 0, 0x37, sz)) # define IMMARG(sz) opnd_create_immed_int(37, sz) # define TGTARG opnd_create_instr(instrlist_last(ilist)) # define REGARG(reg) opnd_create_reg(REG_##reg) # define X86_ONLY 1 # define X64_ONLY 2 # define OPCODE(opc, icnm, ...) \ int len_##icnm; # include "ir_0args.h" # include "ir_1args.h" # include "ir_2args.h" # include "ir_3args.h" # include "ir_4args.h" # undef OPCODE /* we can encode+fast-decode some instrs cross-platform but we * leave that testing to the regression run on that platform */ # define OPCODE(opc, icnm, flags) do { \ if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \ instrlist_append(ilist, INSTR_CREATE_##icnm(dc)); \ len_##icnm = instr_length(dc, instrlist_last(ilist)); \ } } while (0); # include "ir_0args.h" # undef OPCODE # define OPCODE(opc, icnm, flags, arg1) do { \ if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \ instrlist_append(ilist, INSTR_CREATE_##icnm(dc, arg1)); \ len_##icnm = instr_length(dc, instrlist_last(ilist)); \ } } while (0); # include "ir_1args.h" # undef OPCODE # define OPCODE(opc, icnm, flags, arg1, arg2) do { \ if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \ instrlist_append(ilist, INSTR_CREATE_##icnm(dc, arg1, arg2)); \ len_##icnm = instr_length(dc, instrlist_last(ilist)); \ } } while (0); # include "ir_2args.h" # undef OPCODE # define OPCODE(opc, icnm, flags, arg1, arg2, arg3) do { \ if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \ instrlist_append(ilist, INSTR_CREATE_##icnm(dc, arg1, arg2, arg3)); \ len_##icnm = instr_length(dc, instrlist_last(ilist)); \ } } while (0); # include "ir_3args.h" # undef OPCODE # define OPCODE(opc, icnm, flags, arg1, arg2, arg3, arg4) do { \ if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0) { \ instrlist_append(ilist, INSTR_CREATE_##icnm(dc, arg1, arg2, arg3, arg4)); \ len_##icnm = instr_length(dc, instrlist_last(ilist)); \ } } while (0); # include "ir_4args.h" # undef OPCODE end = instrlist_encode(dc, ilist, buf, false); instr = instr_create(dc); pc = buf; # define OPCODE(opc, icnm, flags, ...) do { \ if ((flags & IF_X64_ELSE(X86_ONLY, X64_ONLY)) == 0 && len_##icnm != 0) { \ instr_reset(dc, instr); \ next_pc = decode(dc, pc, instr); \ ASSERT((next_pc - pc) == decode_sizeof(dc, pc, NULL _IF_X64(NULL))); \ ASSERT((next_pc - pc) == len_##icnm); \ ASSERT(instr_get_opcode(instr) == OP_##opc); \ pc = next_pc; \ } } while (0); # include "ir_0args.h" # include "ir_1args.h" # include "ir_2args.h" # include "ir_3args.h" # include "ir_4args.h" # undef OPCODE #if VERBOSE for (pc = buf; pc < end; ) pc = disassemble_with_info(dc, pc, STDOUT, true, true); #endif instr_destroy(dc, instr); instrlist_clear_and_destroy(dc, ilist); }
void test_dr_insert_it_instrs_cbr(void *dcontext) { instrlist_t *ilist = instrlist_create(dcontext); instr_t *where = INSTR_CREATE_label(dcontext); instr_t *instr_it1, *instr_it2, *instr_it3; byte buffer[4096]; instrlist_append(ilist, where); instrlist_preinsert(ilist, where, XINST_CREATE_move (dcontext, opnd_create_reg(DR_REG_R1), opnd_create_reg(DR_REG_R2))); instrlist_preinsert(ilist, where, XINST_CREATE_jump (dcontext, opnd_create_instr(where))); instrlist_preinsert(ilist, where, XINST_CREATE_move (dcontext, opnd_create_reg(DR_REG_R1), opnd_create_reg(DR_REG_R2))); instrlist_preinsert(ilist, where, XINST_CREATE_move (dcontext, opnd_create_reg(DR_REG_R1), opnd_create_reg(DR_REG_R2))); instrlist_preinsert(ilist, where, XINST_CREATE_jump (dcontext, opnd_create_instr(where))); instrlist_preinsert(ilist, where, XINST_CREATE_move (dcontext, opnd_create_reg(DR_REG_R1), opnd_create_reg(DR_REG_R2))); instrlist_preinsert(ilist, where, XINST_CREATE_move (dcontext, opnd_create_reg(DR_REG_R1), opnd_create_reg(DR_REG_R2))); instrlist_preinsert(ilist, where, XINST_CREATE_move (dcontext, opnd_create_reg(DR_REG_R1), opnd_create_reg(DR_REG_R2))); instrlist_preinsert(ilist, where, XINST_CREATE_jump (dcontext, opnd_create_instr(where))); /* set them all to be predicated and reinstate it instrs */ for (where = instrlist_first(ilist); where; where = instr_get_next(where)) { bool ok = instr_set_isa_mode(where, DR_ISA_ARM_THUMB); DR_ASSERT(ok); instr_set_predicate(where, DR_PRED_LS); } dr_insert_it_instrs(dcontext, ilist); /* Make sure it was encoded properly, noting that the branches * should *not* be in any IT-block. * it * mov.ls r1, r2 * b.ls @0x47366864 * itt * mov.ls r1, r2 * mov.ls r1, r2 * b.ls @0x47366864 * ittt * mov.ls r1, r2 * mov.ls r1, r2 * mov.ls r1, r2 * b.ls @0x47366864 */ instr_it1 = instrlist_first(ilist); instr_it2 = instr_get_next(instr_get_next(instr_get_next(instr_it1))); instr_it3 = instr_get_next(instr_get_next(instr_get_next(instr_get_next(instr_it2)))); DR_ASSERT(instr_get_opcode(instr_it1) == OP_it); DR_ASSERT(instr_it_block_get_count(instr_it1) == 1); DR_ASSERT(instr_get_opcode(instr_it2) == OP_it); DR_ASSERT(instr_it_block_get_count(instr_it2) == 2); DR_ASSERT(instr_get_opcode(instr_it3) == OP_it); DR_ASSERT(instr_it_block_get_count(instr_it3) == 3); instrlist_encode(dcontext, ilist, buffer, true); }