1288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* This file must be included from target-arm/translate.c */ 2288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 3288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/***** 4288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** 5288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** 6288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** C O N F I G _ M E M C H E C K 7288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** 8288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** 9288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner *****/ 10288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 11288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#ifdef CONFIG_MEMCHECK 12288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 13288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* 14288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * Memchecker addition in this module is intended to inject qemu callback into 15288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * translated code for each BL/BLX, as well as BL/BLX returns. These callbacks 16288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * are used to build calling stack of the thread in order to provide better 17288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * reporting on memory access violations. Although this may seem as something 18288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * that may gratly impact the performance, in reality it doesn't. Overhead that 19288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * is added by setting up callbacks and by callbacks themselves is neglectable. 20288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * On the other hand, maintaining calling stack can indeed add some perf. 21288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * overhead (TODO: provide solid numbers here). 22288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * One of the things to watch out with regards to injecting callbacks, is 23288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * consistency between intermediate code generated for execution, and for guest 24288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * PC address calculation. If code doesn't match, a segmentation fault is 25288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * guaranteed. 26288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner */ 27288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 28288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#include "memcheck/memcheck_proc_management.h" 29288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#include "memcheck/memcheck_api.h" 30288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 31288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* Array of return addresses detected in gen_intermediate_code_internal. */ 32288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' TurnerAddrArray ret_addresses = { 0 }; 33288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 34288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* Checks if call stack collection is enabled for the given context. 35288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * We collect call stack only for the user mode (both, code and CPU), and on 36288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * condition that memory checking, and call collection are enabled. It also 37288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * seems that collecting stack for the linker code is excessive, as it doesn't 38288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * provide much useful info for the memory checker. 39288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * Return: 40288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * boolean: 1 if stack collection is enabled for the given context, or 0 if 41288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * it's not enabled. 42288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner */ 43288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerstatic inline int 44288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerwatch_call_stack(DisasContext *s) 45288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner{ 46288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (!memcheck_enabled || !memcheck_watch_call_stack) { 47288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return 0; 48288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 49288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 50288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#ifndef CONFIG_USER_ONLY 51288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (!s->user) { 52288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner /* We're not interested in kernel mode CPU stack. */ 53288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return 0; 54288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 55288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#endif // CONFIG_USER_ONLY 56288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 57288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner /* We're not interested in kernel code stack (pc >= 0xC0000000). 58288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * Android specific: We're also not interested in android linker stack 59288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * (0xB0000000 - 0xB00FFFFF) */ 60288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (s->pc >= 0xC0000000 || (0xB0000000 <= s->pc && s->pc <= 0xB00FFFFF)) { 61288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return 0; 62288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 63288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return 1; 64288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner} 65288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 66288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* Checks if given ARM instruction is BL, or BLX. 67288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * Return: 68288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * boolean: 1 if ARM instruction is BL/BLX, or 0 if it's not. 69288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner */ 70288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerstatic inline int 71288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turneris_arm_bl_or_blx(uint32_t insn) 72288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner{ 73288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner /* ARM BL (immediate): xxxx 1011 xxxx xxxx xxxx xxxx xxxx xxxx 74288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * ARM BLX (immediate): 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx 75288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * ARM BLX (register): xxxx 0001 0010 xxxx xxxx xxxx 0011 xxxx 76288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner */ 77288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if ((insn & 0x0F000000) == 0x0B000000 || // ARM BL (imm) 78288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner (insn & 0xFE000000) == 0xFA000000 || // ARM BLX (imm) 79288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner (insn & 0x0FF000F0) == 0x12000030) { // ARM BLX (reg) 80288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return 1; 81288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 82288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return 0; 83288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner} 84288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 85288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* Checks if given THUMB instruction is BL, or BLX. 86288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * Param: 87288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * insn - THUMB instruction to check. 88288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * pc - Emulated PC address for the instruction. 89288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * ret_off - If insn is BL, or BLX, upon return ret_off contains 90288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * instruction's byte size. If instruction is not BL, or BLX, content of 91288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * this parameter is undefined on return. 92288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * Return: 93288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * boolean: 1 if THUMB instruction is BL/BLX, or 0 if it's not. 94288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner */ 95288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerstatic inline int 96288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turneris_thumb_bl_or_blx(uint16_t insn, target_ulong pc, target_ulong* ret_off) 97288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner{ 98288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner /* THUMB BLX(register): 0100 0111 1xxx xxxx 99288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * THUMB BL(1-stimmediate): 1111 0xxx xxxx xxxx 100288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * THUMB BLX(1-stimmediate): 1111 0xxx xxxx xxxx 101288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner */ 102288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if ((insn & 0xFF80) == 0x4780) { // THUMB BLX(reg) 103288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner *ret_off = 2; 104288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return 1; 105288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } else if ((insn & 0xF800) == 0xF000) { // THUMB BL(X)(imm) 106288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner // This is a 32-bit THUMB. Get the second half of the instuction. 107288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner insn = lduw_code(pc + 2); 108288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if ((insn & 0xC000) == 0xC000) { 109288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner *ret_off = 4; 110288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return 1; 111288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 112288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 113288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return 0; 114288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner} 115288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 116288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* Registers a return address detected in gen_intermediate_code_internal. 117288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * NOTE: If return address has been registered as new in this routine, this will 118288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * cause invalidation of all existing TBs that contain translated code for that 119288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * address. 120288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * NOTE: Before storing PC address in the array, we convert it from emulated 121288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * address to a physical address. This way we deal with emulated addresses 122288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * overlapping for different processes. 123288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * Param: 124288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * env - CPU state environment. 125288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * addr - Return address to register. 126288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * Return: 127288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * 1 - Address has been registered in this routine. 128288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * -1 - Address has been already registered before. 129288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * 0 - Insufficient memory. 130288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner */ 131288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerstatic int 132288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerregister_ret_address(CPUState* env, target_ulong addr) 133288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner{ 134288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner int ret; 135288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) { 136288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner /* Address belongs to a module that always loads at this fixed address. 137288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * So, we can keep this address in the global array. */ 138288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ret = addrarray_add(&ret_addresses, get_phys_addr_code(env, addr)); 139288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } else { 140288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ret = addrarray_add(&ret_addresses, get_phys_addr_code(env, addr)); 141288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 142288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner assert(ret != 0); 143288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 144288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (ret == 1) { 145288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner /* If this ret address has been added to the array, we need to make sure 146288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * that all TBs that contain translated code for that address are 147288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * invalidated. This will force retranslation of that code, which will 148288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * make sure that our ret callback is set. This is also important part 149288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * in keeping consistency between translated code, and intermediate code 150288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * generated for guest PC calculation. If we don't invalidate TBs, and 151288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * PC calculation code is generated, there will be inconsistency due to 152288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * the fact that TB code doesn't contain ret callback, while PC calc 153288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * code contains it. This inconsistency will lead to an immanent 154288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * segmentation fault.*/ 155288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner TranslationBlock* tb; 156288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner const target_ulong phys_pc = get_phys_addr_code(env, addr); 157288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner const target_ulong phys_page1 = phys_pc & TARGET_PAGE_MASK; 158288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 159288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner for(tb = tb_phys_hash[tb_phys_hash_func(phys_pc)]; tb != NULL; 160288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tb = tb->phys_hash_next) { 161288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (tb->pc == addr && tb->page_addr[0] == phys_page1) { 162288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tb_phys_invalidate(tb, -1); 163288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 164288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 165288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 166288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return ret; 167288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner} 168288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 169288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* Checks if given address is recognized as a return address. 170288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * Return: 171288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * boolean: 1 if if given address is recognized as a return address, 172288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * or 0 if it's not. 173288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner */ 174288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerstatic inline int 175288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turneris_ret_address(CPUState* env, target_ulong addr) 176288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner{ 177288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) { 178288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); 179288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } else { 180288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); 181288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 182288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner} 183288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 184288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* Adds "on_call" callback into generated intermediate code. */ 185288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerstatic inline void 186288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerset_on_call(target_ulong pc, target_ulong ret) 187288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner{ 188288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner TCGv_ptr tmp_pc = tcg_const_ptr(pc & ~1); 189288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1); 190288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 191288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_helper_on_call(tmp_pc, tmp_ret); 192288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 193288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_temp_free_ptr(tmp_ret); 194288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_temp_free_ptr(tmp_pc); 195288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner} 196288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 197288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/* Adds "on_ret" callback into generated intermediate code. */ 198288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerstatic inline void 199288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerset_on_ret(target_ulong ret) 200288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner{ 201288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1); 202288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 203288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_helper_on_ret(tmp_ret); 204288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 205288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_temp_free_ptr(tmp_ret); 206288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner} 207288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 208288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 209288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_WATCH_CALLSTACK_ARM(s) \ 210288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (watch_call_stack(s)) { \ 211288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (is_ret_address(env, s->pc)) { \ 212288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner set_on_ret(s->pc); \ 213288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 214288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (is_arm_bl_or_blx(insn)) { \ 215288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner set_on_call(s->pc, s->pc + 4); \ 216288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (!s->search_pc) { \ 217288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner register_ret_address(env, s->pc + 4); \ 218288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 219288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 220288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 221288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 222288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_WATCH_CALLSTACK_THUMB(s) \ 223288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (watch_call_stack(s)) { \ 224288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner target_ulong ret_off; \ 225288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (is_ret_address(env, s->pc)) { \ 226288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner set_on_ret(s->pc); \ 227288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 228288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (is_thumb_bl_or_blx(insn, s->pc, &ret_off)) { \ 229288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner set_on_call(s->pc, s->pc + ret_off); \ 230288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (!s->search_pc) { \ 231288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner register_ret_address(env, s->pc + ret_off); \ 232288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 233288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 234288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } 235288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 236288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_DISAS_CONTEXT_FIELDS \ 237288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner int search_pc; 238288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 239288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_START_CODEGEN(search_pc) \ 240288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner dc->search_pc = search_pc 241288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 242288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner /* When memchecker is enabled, we need to keep a match between 243288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * translated PC and guest PCs, so memchecker can quickly covert 244288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner * one to another. Note that we do that only for user mode. */ 245288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_CHECK_CODEGEN_PC(search_pc) \ 246288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ((search_pc) || (memcheck_enabled && dc->user)) 247288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 248288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_END_CODEGEN() \ 249288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner do { \ 250288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (memcheck_enabled && dc->user) { \ 251288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner j = gen_opc_ptr - gen_opc_buf; \ 252288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner lj++; \ 253288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner while (lj <= j) \ 254288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_opc_instr_start[lj++] = 0; \ 255288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 256288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } while (0) 257288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 258288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#else /* !CONFIG_MEMCHECK */ 259288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 260288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_WATCH_CALLSTACK_ARM ((void)0) 261288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_WATCH_CALLSTACK_THUMB ((void)0) 262288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_DISAS_CONTEXT_FIELDS /* nothing */ 263288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_START_CODEGEN(s) ((void)(s)) 264288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_CHECK_CODEGEN_PC(s) (s) 265288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_END_CODEGEN() ((void)0) 266288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 267288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#endif /* !CONFIG_MEMCHECK */ 268288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 269288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 270288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner/***** 271288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** 272288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** 273288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** C O N F I G _ T R A C E 274288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** 275288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ***** 276288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner *****/ 277288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 278288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#ifdef CONFIG_TRACE 279288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 280406a59bd0a2e7a38cd840a5c08602e3a36bd2df8David 'Digit' Turner#include "android-trace.h" 281288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#define gen_traceInsn() gen_helper_traceInsn() 282288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 283288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerstatic void 284288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnergen_traceTicks( int count ) 285288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner{ 286288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner TCGv tmp = tcg_temp_new_i32(); 287288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_gen_movi_i32(tmp, count); 288288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_helper_traceTicks(tmp); 289288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_temp_free_i32(tmp); 290288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner} 291288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 292288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnerstatic void 293288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turnergen_traceBB( uint64_t bbNum, void* tb ) 294288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner{ 295288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#if HOST_LONG_BITS == 32 296288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner TCGv_i64 tmpNum = tcg_temp_new_i64(); 297288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner TCGv_i32 tmpTb = tcg_temp_new_i32(); 298288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 299288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_gen_movi_i64(tmpNum, (int64_t)bbNum); 300288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_gen_movi_i32(tmpTb, (int32_t)tb); 301288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_helper_traceBB32(tmpNum, tmpTb); 302288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_temp_free_i32(tmpTb); 303288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_temp_free_i64(tmpNum); 304288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#elif HOST_LONG_BITS == 64 305288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner TCGv_i64 tmpNum = tcg_temp_new_i64(); 306288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner TCGv_i64 tmpTb = tcg_temp_new_i64(); 307288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 308288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_gen_movi_i64(tmpNum, (int64_t)bbNum); 309288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_gen_movi_i64(tmpTb, (int64_t)tb); 310288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_helper_traceBB64(tmpNum, tmpTb); 311288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_temp_free_i64(tmpTb); 312288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner tcg_temp_free_i64(tmpNum); 313288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#endif 314288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner} 315288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 316288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_DECLS int ticks = 0; 317288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 318288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_START_ARM() \ 319288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner do { \ 320288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (tracing) { \ 321288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner trace_add_insn(insn, 0); \ 322288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ticks = get_insn_ticks_arm(insn); \ 323288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_traceInsn(); \ 324288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 325288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } while (0) 326288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 327288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_START_THUMB() \ 328288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner do { \ 329288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (tracing) { \ 330288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner int ticks = get_insn_ticks_thumb(insn); \ 331288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner trace_add_insn( insn_wrap_thumb(insn), 1 ); \ 332288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_traceInsn(); \ 333288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_traceTicks(ticks); \ 334288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 335288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } while (0) 336288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 337288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_GEN_TICKS() \ 338288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner do { \ 339288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (tracing) { \ 340288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 341288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } while (0) 342288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 343288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_GEN_SINGLE_TICK() \ 344288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner do { \ 345288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (tracing) { \ 346288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_traceTicks(1); \ 347288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner ticks -= 1; \ 348288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 349288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } while (0) 350288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 351288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_GEN_OTHER_TICKS() \ 352288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner do { \ 353288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (tracing && ticks > 0) { \ 354288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_traceTicks(ticks); \ 355288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 356288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } while (0) 357288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 358288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_START_BB() \ 359288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner do { \ 360288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (tracing) { \ 361288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner gen_traceBB(trace_static_bb_num(), tb); \ 362288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner trace_bb_start(dc->pc); \ 363288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 364288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } while (0) 365288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 366288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_END_BB() \ 367288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner do { \ 368288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner if (tracing) { \ 369288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner trace_bb_end(); \ 370288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } \ 371288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner } while (0) 372288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 373288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#else /* !CONFIG_TRACE */ 374288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 375288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_DECLS /* nothing */ 376288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_START_ARM() ((void)0) 377288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_START_THUMB() ((void)0) 378288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 379288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_GEN_TICKS() ((void)0) 380288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_GEN_SINGLE_TICK() ((void)0) 381288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_GEN_OTHER_TICKS() ((void)0) 382288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 383288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_START_BB() ((void)0) 384288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner# define ANDROID_TRACE_END_BB() ((void)0) 385288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 386288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner#endif /* !CONFIG_TRACE */ 387288208c386810fef725aa448a9f46bd2772bec8cDavid 'Digit' Turner 388