aboutsummaryrefslogtreecommitdiffstats
path: root/target-arm
diff options
context:
space:
mode:
Diffstat (limited to 'target-arm')
-rw-r--r--target-arm/memcheck_arm_helpers.h26
-rw-r--r--target-arm/translate.c6
2 files changed, 19 insertions, 13 deletions
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);