1 /* Copyright (C) 2007-2010 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 13 /* 14 * Contains implementation of memcheck helper routines used by ARM's translator. 15 */ 16 17 #ifndef QEMU_TARGET_ARM_MEMCHECK_ARM_HELPERS_H 18 #define QEMU_TARGET_ARM_MEMCHECK_ARM_HELPERS_H 19 20 /* This file should compile iff qemu is built with memory checking 21 * configuration turned on. */ 22 #ifndef CONFIG_MEMCHECK 23 #error CONFIG_MEMCHECK is not defined. 24 #endif // CONFIG_MEMCHECK 25 26 #include "helpers.h" 27 #include "memcheck/memcheck_api.h" 28 29 /* Array of return addresses detected in gen_intermediate_code_internal. */ 30 AddrArray ret_addresses = { 0 }; 31 32 /* Checks if call stack collection is enabled for the given context. 33 * We collect call stack only for the user mode (both, code and CPU), and on 34 * condition that memory checking, and call collection are enabled. It also 35 * seems that collecting stack for the linker code is excessive, as it doesn't 36 * provide much useful info for the memory checker. 37 * Return: 38 * boolean: 1 if stack collection is enabled for the given context, or 0 if 39 * it's not enabled. 40 */ 41 static inline int 42 watch_call_stack(DisasContext *s) 43 { 44 if (!memcheck_enabled || !memcheck_watch_call_stack) { 45 return 0; 46 } 47 48 #ifndef CONFIG_USER_ONLY 49 if (!s->user) { 50 /* We're not interested in kernel mode CPU stack. */ 51 return 0; 52 } 53 #endif // CONFIG_USER_ONLY 54 55 /* We're not interested in kernel code stack (pc >= 0xC0000000). 56 * Android specific: We're also not interested in android linker stack 57 * (0xB0000000 - 0xB00FFFFF) */ 58 if (s->pc >= 0xC0000000 || (0xB0000000 <= s->pc && s->pc <= 0xB00FFFFF)) { 59 return 0; 60 } 61 return 1; 62 } 63 64 /* Checks if given ARM instruction is BL, or BLX. 65 * Return: 66 * boolean: 1 if ARM instruction is BL/BLX, or 0 if it's not. 67 */ 68 static inline int 69 is_arm_bl_or_blx(uint32_t insn) 70 { 71 /* ARM BL (immediate): xxxx 1011 xxxx xxxx xxxx xxxx xxxx xxxx 72 * ARM BLX (immediate): 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx 73 * ARM BLX (register): xxxx 0001 0010 xxxx xxxx xxxx 0011 xxxx 74 */ 75 if ((insn & 0x0F000000) == 0x0B000000 || // ARM BL (imm) 76 (insn & 0xFE000000) == 0xFA000000 || // ARM BLX (imm) 77 (insn & 0x0FF000F0) == 0x12000030) { // ARM BLX (reg) 78 return 1; 79 } 80 return 0; 81 } 82 83 /* Checks if given THUMB instruction is BL, or BLX. 84 * Param: 85 * insn - THUMB instruction to check. 86 * pc - Emulated PC address for the instruction. 87 * ret_off - If insn is BL, or BLX, upon return ret_off contains 88 * instruction's byte size. If instruction is not BL, or BLX, content of 89 * this parameter is undefined on return. 90 * Return: 91 * boolean: 1 if THUMB instruction is BL/BLX, or 0 if it's not. 92 */ 93 static inline int 94 is_thumb_bl_or_blx(uint16_t insn, target_ulong pc, target_ulong* ret_off) 95 { 96 /* THUMB BLX(register): 0100 0111 1xxx xxxx 97 * THUMB BL(1-stimmediate): 1111 0xxx xxxx xxxx 98 * THUMB BLX(1-stimmediate): 1111 0xxx xxxx xxxx 99 */ 100 if ((insn & 0xFF80) == 0x4780) { // THUMB BLX(reg) 101 *ret_off = 2; 102 return 1; 103 } else if ((insn & 0xF800) == 0xF000) { // THUMB BL(X)(imm) 104 // This is a 32-bit THUMB. Get the second half of the instuction. 105 insn = lduw_code(pc + 2); 106 if ((insn & 0xC000) == 0xC000) { 107 *ret_off = 4; 108 return 1; 109 } 110 } 111 return 0; 112 } 113 114 /* Registers a return address detected in gen_intermediate_code_internal. 115 * NOTE: If return address has been registered as new in this routine, this will 116 * cause invalidation of all existing TBs that contain translated code for that 117 * address. 118 * NOTE: Before storing PC address in the array, we convert it from emulated 119 * address to a physical address. This way we deal with emulated addresses 120 * overlapping for different processes. 121 * Param: 122 * env - CPU state environment. 123 * addr - Return address to register. 124 * Return: 125 * 1 - Address has been registered in this routine. 126 * -1 - Address has been already registered before. 127 * 0 - Insufficient memory. 128 */ 129 static int 130 register_ret_address(CPUState* env, target_ulong addr) 131 { 132 int ret; 133 if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) { 134 /* Address belongs to a module that always loads at this fixed address. 135 * So, we can keep this address in the global array. */ 136 ret = addrarray_add(&ret_addresses, get_phys_addr_code(env, addr)); 137 } else { 138 ret = addrarray_add(&ret_addresses, get_phys_addr_code(env, addr)); 139 } 140 assert(ret != 0); 141 142 if (ret == 1) { 143 /* If this ret address has been added to the array, we need to make sure 144 * that all TBs that contain translated code for that address are 145 * invalidated. This will force retranslation of that code, which will 146 * make sure that our ret callback is set. This is also important part 147 * in keeping consistency between translated code, and intermediate code 148 * generated for guest PC calculation. If we don't invalidate TBs, and 149 * PC calculation code is generated, there will be inconsistency due to 150 * the fact that TB code doesn't contain ret callback, while PC calc 151 * code contains it. This inconsistency will lead to an immanent 152 * segmentation fault.*/ 153 TranslationBlock* tb; 154 const target_ulong phys_pc = get_phys_addr_code(env, addr); 155 const target_ulong phys_page1 = phys_pc & TARGET_PAGE_MASK; 156 157 for(tb = tb_phys_hash[tb_phys_hash_func(phys_pc)]; tb != NULL; 158 tb = tb->phys_hash_next) { 159 if (tb->pc == addr && tb->page_addr[0] == phys_page1) { 160 tb_phys_invalidate(tb, -1); 161 } 162 } 163 } 164 return ret; 165 } 166 167 /* Checks if given address is recognized as a return address. 168 * Return: 169 * boolean: 1 if if given address is recognized as a return address, 170 * or 0 if it's not. 171 */ 172 static inline int 173 is_ret_address(CPUState* env, target_ulong addr) 174 { 175 if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) { 176 return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); 177 } else { 178 return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); 179 } 180 } 181 182 /* Adds "on_call" callback into generated intermediate code. */ 183 static inline void 184 set_on_call(target_ulong pc, target_ulong ret) 185 { 186 TCGv_ptr tmp_pc = tcg_const_ptr(pc & ~1); 187 TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1); 188 189 gen_helper_on_call(tmp_pc, tmp_ret); 190 191 tcg_temp_free_ptr(tmp_ret); 192 tcg_temp_free_ptr(tmp_pc); 193 } 194 195 /* Adds "on_ret" callback into generated intermediate code. */ 196 static inline void 197 set_on_ret(target_ulong ret) 198 { 199 TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1); 200 201 gen_helper_on_ret(tmp_ret); 202 203 tcg_temp_free_ptr(tmp_ret); 204 } 205 206 #endif // QEMU_TARGET_ARM_MEMCHECK_ARM_HELPERS_H 207