From ca52b2260ba9f9bac07092c3d8260ed523de1fe1 Mon Sep 17 00:00:00 2001 From: Vladimir Chtchetkine Date: Wed, 24 Mar 2010 06:38:41 -0700 Subject: Make return address table independent from process context. Use physical addresses (instead of emulated ones) for registered return addresses. This way addresses will be independent from process context, as even if virtual addresses may overlap, the physical ones will not. Change-Id: If5be5174286be0a456c47c48812d7cc9bf19bc1f --- target-arm/memcheck_arm_helpers.h | 26 ++++++++++++++++---------- target-arm/translate.c | 6 +++--- 2 files changed, 19 insertions(+), 13 deletions(-) (limited to 'target-arm') diff --git a/target-arm/memcheck_arm_helpers.h b/target-arm/memcheck_arm_helpers.h index a05668a..d13b89d 100644 --- a/target-arm/memcheck_arm_helpers.h +++ b/target-arm/memcheck_arm_helpers.h @@ -83,6 +83,7 @@ is_arm_bl_or_blx(uint32_t insn) /* Checks if given THUMB instruction is BL, or BLX. * Param: * insn - THUMB instruction to check. + * pc - Emulated PC address for the instruction. * ret_off - If insn is BL, or BLX, upon return ret_off contains * instruction's byte size. If instruction is not BL, or BLX, content of * this parameter is undefined on return. @@ -90,7 +91,7 @@ is_arm_bl_or_blx(uint32_t insn) * boolean: 1 if THUMB instruction is BL/BLX, or 0 if it's not. */ static inline int -is_thumb_bl_or_blx(uint16_t insn, target_ulong* ret_off) +is_thumb_bl_or_blx(uint16_t insn, target_ulong pc, target_ulong* ret_off) { /* THUMB BLX(register): 0100 0111 1xxx xxxx * THUMB BL(1-stimmediate): 1111 0xxx xxxx xxxx @@ -100,8 +101,12 @@ is_thumb_bl_or_blx(uint16_t insn, target_ulong* ret_off) *ret_off = 2; return 1; } else if ((insn & 0xF800) == 0xF000) { // THUMB BL(X)(imm) - *ret_off = 4; - return 1; + // This is a 32-bit THUMB. Get the second half of the instuction. + insn = lduw_code(pc + 2); + if ((insn & 0xC000) == 0xC000) { + *ret_off = 4; + return 1; + } } return 0; } @@ -110,6 +115,9 @@ is_thumb_bl_or_blx(uint16_t insn, target_ulong* ret_off) * NOTE: If return address has been registered as new in this routine, this will * cause invalidation of all existing TBs that contain translated code for that * address. + * NOTE: Before storing PC address in the array, we convert it from emulated + * address to a physical address. This way we deal with emulated addresses + * overlapping for different processes. * Param: * env - CPU state environment. * addr - Return address to register. @@ -125,11 +133,9 @@ register_ret_address(CPUState* env, target_ulong addr) if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) { /* Address belongs to a module that always loads at this fixed address. * So, we can keep this address in the global array. */ - ret = addrarray_add(&ret_addresses, addr); + ret = addrarray_add(&ret_addresses, get_phys_addr_code(env, addr)); } else { - /* TODO: Figure out how to move "floating" part to the process - * descriptor. */ - ret = addrarray_add(&ret_addresses, addr); + ret = addrarray_add(&ret_addresses, get_phys_addr_code(env, addr)); } assert(ret != 0); @@ -164,12 +170,12 @@ register_ret_address(CPUState* env, target_ulong addr) * or 0 if it's not. */ static inline int -is_ret_address(target_ulong addr) +is_ret_address(CPUState* env, target_ulong addr) { if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) { - return addrarray_check(&ret_addresses, addr); + return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); } else { - return addrarray_check(&ret_addresses, addr); + return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); } } diff --git a/target-arm/translate.c b/target-arm/translate.c index 6c8ebde..ca04700 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -5813,7 +5813,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) #ifdef CONFIG_MEMCHECK if (watch_call_stack(s)) { - if (is_ret_address(s->pc)) { + if (is_ret_address(env, s->pc)) { set_on_ret(s->pc); } if (is_arm_bl_or_blx(insn)) { @@ -8197,10 +8197,10 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) #ifdef CONFIG_MEMCHECK if (watch_call_stack(s)) { target_ulong ret_off; - if (is_ret_address(s->pc)) { + if (is_ret_address(env, s->pc)) { set_on_ret(s->pc); } - if (is_thumb_bl_or_blx(insn, &ret_off)) { + if (is_thumb_bl_or_blx(insn, s->pc, &ret_off)) { set_on_call(s->pc, s->pc + ret_off); if (!s->search_pc) { register_ret_address(env, s->pc + ret_off); -- cgit v1.1