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
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 @@
 /* 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 @@
  *  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 @@
         *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 @@
  * 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 @@
     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 @@
  *  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 @@
 
 #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 @@
 #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);