From 288208c386810fef725aa448a9f46bd2772bec8c Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Wed, 11 May 2011 19:37:35 +0200 Subject: target-arm/translate.c: move Android-specific stuff out. Change-Id: Id14c6b106dbac9b4016b7423327e9eb22e21fe75 --- Makefile.target | 1 + target-arm/helper-android.c | 51 +++++ target-arm/helper-android.h | 28 +++ target-arm/helper.c | 41 ---- target-arm/helpers.h | 28 +-- target-arm/memcheck_arm_helpers.h | 206 -------------------- target-arm/translate-android.h | 387 ++++++++++++++++++++++++++++++++++++++ target-arm/translate.c | 188 ++---------------- 8 files changed, 487 insertions(+), 443 deletions(-) create mode 100644 target-arm/helper-android.c create mode 100644 target-arm/helper-android.h delete mode 100644 target-arm/memcheck_arm_helpers.h create mode 100644 target-arm/translate-android.h diff --git a/Makefile.target b/Makefile.target index b8eb26c..5f7a8b2 100644 --- a/Makefile.target +++ b/Makefile.target @@ -157,6 +157,7 @@ LOCAL_SRC_FILES += \ target-arm/iwmmxt_helper.c \ target-arm/neon_helper.c \ target-arm/helper.c \ + target-arm/helper-android.c \ target-arm/translate.c \ target-arm/machine.c \ hw/armv7m.c \ diff --git a/target-arm/helper-android.c b/target-arm/helper-android.c new file mode 100644 index 0000000..af9d14b --- /dev/null +++ b/target-arm/helper-android.c @@ -0,0 +1,51 @@ +#include +#include +#include + +#include "cpu.h" +#include "exec-all.h" +#include "gdbstub.h" +#include "def-helper.h" +#include "helper-android.h" +#include "qemu-common.h" + +#ifdef CONFIG_TRACE +#include "trace.h" + +void HELPER(traceTicks)(uint32_t ticks) +{ + sim_time += ticks; +} + +void HELPER(traceInsn)(void) +{ + trace_insn_helper(); +} + +#if HOST_LONG_BITS == 32 +void HELPER(traceBB32)(uint64_t bb_num, uint32_t tb) +{ + trace_bb_helper(bb_num, (void*)tb); +} +#endif + +#if HOST_LONG_BITS == 64 +void HELPER(traceBB64)(uint64_t bb_num, uint64_t tb) +{ + trace_bb_helper(bb_num, (void*)tb); +} +#endif + +#endif /* CONFIG_TRACE */ + +#ifdef CONFIG_MEMCHECK +#include "memcheck/memcheck_api.h" + +void HELPER(on_call)(target_ulong pc, target_ulong ret) { + memcheck_on_call(pc, ret); +} + +void HELPER(on_ret)(target_ulong ret) { + memcheck_on_ret(ret); +} +#endif // CONFIG_MEMCHECK diff --git a/target-arm/helper-android.h b/target-arm/helper-android.h new file mode 100644 index 0000000..5342d1d --- /dev/null +++ b/target-arm/helper-android.h @@ -0,0 +1,28 @@ +/* This file must be included from helper.h */ +#ifdef CONFIG_TRACE +DEF_HELPER_1(traceTicks, void, i32) +DEF_HELPER_0(traceInsn, void) +#if HOST_LONG_BITS == 32 +DEF_HELPER_2(traceBB32, void, i64, i32) +#endif +#if HOST_LONG_BITS == 64 +DEF_HELPER_2(traceBB64, void, i64, i64) +#endif +#endif + +#ifdef CONFIG_MEMCHECK +/* Hooks to translated BL/BLX. This callback is used to build thread's + * calling stack. + * Param: + * First pointer contains guest PC where BL/BLX has been found. + * Second pointer contains guest PC where BL/BLX will return. + */ +DEF_HELPER_2(on_call, void, i32, i32) +/* Hooks to return from translated BL/BLX. This callback is used to build + * thread's calling stack. + * Param: + * Pointer contains guest PC where BL/BLX will return. + */ +DEF_HELPER_1(on_ret, void, i32) +#endif // CONFIG_MEMCHECK +#include "def-helper.h" diff --git a/target-arm/helper.c b/target-arm/helper.c index f595b2c..c69751f 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -10,9 +10,6 @@ #ifdef CONFIG_TRACE #include "trace.h" #endif -#ifdef CONFIG_MEMCHECK -#include "memcheck/memcheck_api.h" -#endif // CONFIG_MEMCHECK static uint32_t cortexa8_cp15_c0_c1[8] = { 0x1031, 0x11, 0x400, 0, 0x31100003, 0x20000000, 0x01202000, 0x11 }; @@ -2634,34 +2631,6 @@ uint32_t HELPER(rsqrte_u32)(uint32_t a, CPUState *env) return float32_to_int32(tmp, s); } -#ifdef CONFIG_TRACE -#include "trace.h" -void HELPER(traceTicks)(uint32_t ticks) -{ - sim_time += ticks; -} - -void HELPER(traceInsn)(void) -{ - trace_insn_helper(); -} - -#if HOST_LONG_BITS == 32 -void HELPER(traceBB32)(uint64_t bb_num, uint32_t tb) -{ - trace_bb_helper(bb_num, (void*)tb); -} -#endif - -#if HOST_LONG_BITS == 64 -void HELPER(traceBB64)(uint64_t bb_num, uint64_t tb) -{ - trace_bb_helper(bb_num, (void*)tb); -} -#endif - -#endif /* CONFIG_TRACE */ - void HELPER(set_teecr)(CPUState *env, uint32_t val) { val &= 1; @@ -2670,13 +2639,3 @@ void HELPER(set_teecr)(CPUState *env, uint32_t val) tb_flush(env); } } - -#ifdef CONFIG_MEMCHECK -void HELPER(on_call)(target_ulong pc, target_ulong ret) { - memcheck_on_call(pc, ret); -} - -void HELPER(on_ret)(target_ulong ret) { - memcheck_on_ret(ret); -} -#endif // CONFIG_MEMCHECK diff --git a/target-arm/helpers.h b/target-arm/helpers.h index 5dd4925..bf210fe 100644 --- a/target-arm/helpers.h +++ b/target-arm/helpers.h @@ -15,17 +15,6 @@ DEF_HELPER_2(udiv, i32, i32, i32) DEF_HELPER_1(rbit, i32, i32) DEF_HELPER_1(abs, i32, i32) -#ifdef CONFIG_TRACE -DEF_HELPER_1(traceTicks, void, i32) -DEF_HELPER_0(traceInsn, void) -#if HOST_LONG_BITS == 32 -DEF_HELPER_2(traceBB32, void, i64, i32) -#endif -#if HOST_LONG_BITS == 64 -DEF_HELPER_2(traceBB64, void, i64, i64) -#endif -#endif - #define PAS_OP(pfx) \ DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \ DEF_HELPER_3(pfx ## sub8, i32, i32, i32, ptr) \ @@ -466,19 +455,4 @@ DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32) DEF_HELPER_2(set_teecr, void, env, i32) -#ifdef CONFIG_MEMCHECK -/* Hooks to translated BL/BLX. This callback is used to build thread's - * calling stack. - * Param: - * First pointer contains guest PC where BL/BLX has been found. - * Second pointer contains guest PC where BL/BLX will return. - */ -DEF_HELPER_2(on_call, void, i32, i32) -/* Hooks to return from translated BL/BLX. This callback is used to build - * thread's calling stack. - * Param: - * Pointer contains guest PC where BL/BLX will return. - */ -DEF_HELPER_1(on_ret, void, i32) -#endif // CONFIG_MEMCHECK -#include "def-helper.h" +#include "helper-android.h" diff --git a/target-arm/memcheck_arm_helpers.h b/target-arm/memcheck_arm_helpers.h deleted file mode 100644 index d13b89d..0000000 --- a/target-arm/memcheck_arm_helpers.h +++ /dev/null @@ -1,206 +0,0 @@ -/* Copyright (C) 2007-2010 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ - -/* - * Contains implementation of memcheck helper routines used by ARM's translator. - */ - -#ifndef QEMU_TARGET_ARM_MEMCHECK_ARM_HELPERS_H -#define QEMU_TARGET_ARM_MEMCHECK_ARM_HELPERS_H - -/* This file should compile iff qemu is built with memory checking - * configuration turned on. */ -#ifndef CONFIG_MEMCHECK -#error CONFIG_MEMCHECK is not defined. -#endif // CONFIG_MEMCHECK - -#include "helpers.h" -#include "memcheck/memcheck_api.h" - -/* Array of return addresses detected in gen_intermediate_code_internal. */ -AddrArray ret_addresses = { 0 }; - -/* Checks if call stack collection is enabled for the given context. - * We collect call stack only for the user mode (both, code and CPU), and on - * condition that memory checking, and call collection are enabled. It also - * seems that collecting stack for the linker code is excessive, as it doesn't - * provide much useful info for the memory checker. - * Return: - * boolean: 1 if stack collection is enabled for the given context, or 0 if - * it's not enabled. - */ -static inline int -watch_call_stack(DisasContext *s) -{ - if (!memcheck_enabled || !memcheck_watch_call_stack) { - return 0; - } - -#ifndef CONFIG_USER_ONLY - if (!s->user) { - /* We're not interested in kernel mode CPU stack. */ - return 0; - } -#endif // CONFIG_USER_ONLY - - /* We're not interested in kernel code stack (pc >= 0xC0000000). - * Android specific: We're also not interested in android linker stack - * (0xB0000000 - 0xB00FFFFF) */ - if (s->pc >= 0xC0000000 || (0xB0000000 <= s->pc && s->pc <= 0xB00FFFFF)) { - return 0; - } - return 1; -} - -/* Checks if given ARM instruction is BL, or BLX. - * Return: - * boolean: 1 if ARM instruction is BL/BLX, or 0 if it's not. - */ -static inline int -is_arm_bl_or_blx(uint32_t insn) -{ - /* ARM BL (immediate): xxxx 1011 xxxx xxxx xxxx xxxx xxxx xxxx - * ARM BLX (immediate): 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx - * ARM BLX (register): xxxx 0001 0010 xxxx xxxx xxxx 0011 xxxx - */ - if ((insn & 0x0F000000) == 0x0B000000 || // ARM BL (imm) - (insn & 0xFE000000) == 0xFA000000 || // ARM BLX (imm) - (insn & 0x0FF000F0) == 0x12000030) { // ARM BLX (reg) - return 1; - } - return 0; -} - -/* 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. - * Return: - * 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 pc, target_ulong* ret_off) -{ - /* THUMB BLX(register): 0100 0111 1xxx xxxx - * THUMB BL(1-stimmediate): 1111 0xxx xxxx xxxx - * THUMB BLX(1-stimmediate): 1111 0xxx xxxx xxxx - */ - if ((insn & 0xFF80) == 0x4780) { // THUMB BLX(reg) - *ret_off = 2; - return 1; - } else if ((insn & 0xF800) == 0xF000) { // THUMB BL(X)(imm) - // 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; -} - -/* Registers a return address detected in gen_intermediate_code_internal. - * 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. - * Return: - * 1 - Address has been registered in this routine. - * -1 - Address has been already registered before. - * 0 - Insufficient memory. - */ -static int -register_ret_address(CPUState* env, target_ulong addr) -{ - int ret; - 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, get_phys_addr_code(env, addr)); - } else { - ret = addrarray_add(&ret_addresses, get_phys_addr_code(env, addr)); - } - assert(ret != 0); - - if (ret == 1) { - /* If this ret address has been added to the array, we need to make sure - * that all TBs that contain translated code for that address are - * invalidated. This will force retranslation of that code, which will - * make sure that our ret callback is set. This is also important part - * in keeping consistency between translated code, and intermediate code - * generated for guest PC calculation. If we don't invalidate TBs, and - * PC calculation code is generated, there will be inconsistency due to - * the fact that TB code doesn't contain ret callback, while PC calc - * code contains it. This inconsistency will lead to an immanent - * segmentation fault.*/ - TranslationBlock* tb; - const target_ulong phys_pc = get_phys_addr_code(env, addr); - const target_ulong phys_page1 = phys_pc & TARGET_PAGE_MASK; - - for(tb = tb_phys_hash[tb_phys_hash_func(phys_pc)]; tb != NULL; - tb = tb->phys_hash_next) { - if (tb->pc == addr && tb->page_addr[0] == phys_page1) { - tb_phys_invalidate(tb, -1); - } - } - } - return ret; -} - -/* Checks if given address is recognized as a return address. - * Return: - * boolean: 1 if if given address is recognized as a return address, - * or 0 if it's not. - */ -static inline int -is_ret_address(CPUState* env, target_ulong addr) -{ - if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) { - return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); - } else { - return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); - } -} - -/* Adds "on_call" callback into generated intermediate code. */ -static inline void -set_on_call(target_ulong pc, target_ulong ret) -{ - TCGv_ptr tmp_pc = tcg_const_ptr(pc & ~1); - TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1); - - gen_helper_on_call(tmp_pc, tmp_ret); - - tcg_temp_free_ptr(tmp_ret); - tcg_temp_free_ptr(tmp_pc); -} - -/* Adds "on_ret" callback into generated intermediate code. */ -static inline void -set_on_ret(target_ulong ret) -{ - TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1); - - gen_helper_on_ret(tmp_ret); - - tcg_temp_free_ptr(tmp_ret); -} - -#endif // QEMU_TARGET_ARM_MEMCHECK_ARM_HELPERS_H diff --git a/target-arm/translate-android.h b/target-arm/translate-android.h new file mode 100644 index 0000000..a09931f --- /dev/null +++ b/target-arm/translate-android.h @@ -0,0 +1,387 @@ +/* This file must be included from target-arm/translate.c */ + +/***** + ***** + ***** + ***** C O N F I G _ M E M C H E C K + ***** + ***** + *****/ + +#ifdef CONFIG_MEMCHECK + +/* + * Memchecker addition in this module is intended to inject qemu callback into + * translated code for each BL/BLX, as well as BL/BLX returns. These callbacks + * are used to build calling stack of the thread in order to provide better + * reporting on memory access violations. Although this may seem as something + * that may gratly impact the performance, in reality it doesn't. Overhead that + * is added by setting up callbacks and by callbacks themselves is neglectable. + * On the other hand, maintaining calling stack can indeed add some perf. + * overhead (TODO: provide solid numbers here). + * One of the things to watch out with regards to injecting callbacks, is + * consistency between intermediate code generated for execution, and for guest + * PC address calculation. If code doesn't match, a segmentation fault is + * guaranteed. + */ + +#include "memcheck/memcheck_proc_management.h" +#include "memcheck/memcheck_api.h" + +/* Array of return addresses detected in gen_intermediate_code_internal. */ +AddrArray ret_addresses = { 0 }; + +/* Checks if call stack collection is enabled for the given context. + * We collect call stack only for the user mode (both, code and CPU), and on + * condition that memory checking, and call collection are enabled. It also + * seems that collecting stack for the linker code is excessive, as it doesn't + * provide much useful info for the memory checker. + * Return: + * boolean: 1 if stack collection is enabled for the given context, or 0 if + * it's not enabled. + */ +static inline int +watch_call_stack(DisasContext *s) +{ + if (!memcheck_enabled || !memcheck_watch_call_stack) { + return 0; + } + +#ifndef CONFIG_USER_ONLY + if (!s->user) { + /* We're not interested in kernel mode CPU stack. */ + return 0; + } +#endif // CONFIG_USER_ONLY + + /* We're not interested in kernel code stack (pc >= 0xC0000000). + * Android specific: We're also not interested in android linker stack + * (0xB0000000 - 0xB00FFFFF) */ + if (s->pc >= 0xC0000000 || (0xB0000000 <= s->pc && s->pc <= 0xB00FFFFF)) { + return 0; + } + return 1; +} + +/* Checks if given ARM instruction is BL, or BLX. + * Return: + * boolean: 1 if ARM instruction is BL/BLX, or 0 if it's not. + */ +static inline int +is_arm_bl_or_blx(uint32_t insn) +{ + /* ARM BL (immediate): xxxx 1011 xxxx xxxx xxxx xxxx xxxx xxxx + * ARM BLX (immediate): 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx + * ARM BLX (register): xxxx 0001 0010 xxxx xxxx xxxx 0011 xxxx + */ + if ((insn & 0x0F000000) == 0x0B000000 || // ARM BL (imm) + (insn & 0xFE000000) == 0xFA000000 || // ARM BLX (imm) + (insn & 0x0FF000F0) == 0x12000030) { // ARM BLX (reg) + return 1; + } + return 0; +} + +/* 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. + * Return: + * 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 pc, target_ulong* ret_off) +{ + /* THUMB BLX(register): 0100 0111 1xxx xxxx + * THUMB BL(1-stimmediate): 1111 0xxx xxxx xxxx + * THUMB BLX(1-stimmediate): 1111 0xxx xxxx xxxx + */ + if ((insn & 0xFF80) == 0x4780) { // THUMB BLX(reg) + *ret_off = 2; + return 1; + } else if ((insn & 0xF800) == 0xF000) { // THUMB BL(X)(imm) + // 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; +} + +/* Registers a return address detected in gen_intermediate_code_internal. + * 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. + * Return: + * 1 - Address has been registered in this routine. + * -1 - Address has been already registered before. + * 0 - Insufficient memory. + */ +static int +register_ret_address(CPUState* env, target_ulong addr) +{ + int ret; + 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, get_phys_addr_code(env, addr)); + } else { + ret = addrarray_add(&ret_addresses, get_phys_addr_code(env, addr)); + } + assert(ret != 0); + + if (ret == 1) { + /* If this ret address has been added to the array, we need to make sure + * that all TBs that contain translated code for that address are + * invalidated. This will force retranslation of that code, which will + * make sure that our ret callback is set. This is also important part + * in keeping consistency between translated code, and intermediate code + * generated for guest PC calculation. If we don't invalidate TBs, and + * PC calculation code is generated, there will be inconsistency due to + * the fact that TB code doesn't contain ret callback, while PC calc + * code contains it. This inconsistency will lead to an immanent + * segmentation fault.*/ + TranslationBlock* tb; + const target_ulong phys_pc = get_phys_addr_code(env, addr); + const target_ulong phys_page1 = phys_pc & TARGET_PAGE_MASK; + + for(tb = tb_phys_hash[tb_phys_hash_func(phys_pc)]; tb != NULL; + tb = tb->phys_hash_next) { + if (tb->pc == addr && tb->page_addr[0] == phys_page1) { + tb_phys_invalidate(tb, -1); + } + } + } + return ret; +} + +/* Checks if given address is recognized as a return address. + * Return: + * boolean: 1 if if given address is recognized as a return address, + * or 0 if it's not. + */ +static inline int +is_ret_address(CPUState* env, target_ulong addr) +{ + if ((0x90000000 <= addr && addr <= 0xBFFFFFFF)) { + return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); + } else { + return addrarray_check(&ret_addresses, get_phys_addr_code(env, addr)); + } +} + +/* Adds "on_call" callback into generated intermediate code. */ +static inline void +set_on_call(target_ulong pc, target_ulong ret) +{ + TCGv_ptr tmp_pc = tcg_const_ptr(pc & ~1); + TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1); + + gen_helper_on_call(tmp_pc, tmp_ret); + + tcg_temp_free_ptr(tmp_ret); + tcg_temp_free_ptr(tmp_pc); +} + +/* Adds "on_ret" callback into generated intermediate code. */ +static inline void +set_on_ret(target_ulong ret) +{ + TCGv_ptr tmp_ret = tcg_const_ptr(ret & ~1); + + gen_helper_on_ret(tmp_ret); + + tcg_temp_free_ptr(tmp_ret); +} + + +# define ANDROID_WATCH_CALLSTACK_ARM(s) \ + if (watch_call_stack(s)) { \ + if (is_ret_address(env, s->pc)) { \ + set_on_ret(s->pc); \ + } \ + if (is_arm_bl_or_blx(insn)) { \ + set_on_call(s->pc, s->pc + 4); \ + if (!s->search_pc) { \ + register_ret_address(env, s->pc + 4); \ + } \ + } \ + } + +# define ANDROID_WATCH_CALLSTACK_THUMB(s) \ + if (watch_call_stack(s)) { \ + target_ulong ret_off; \ + if (is_ret_address(env, s->pc)) { \ + set_on_ret(s->pc); \ + } \ + 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); \ + } \ + } \ + } + +# define ANDROID_DISAS_CONTEXT_FIELDS \ + int search_pc; + +# define ANDROID_START_CODEGEN(search_pc) \ + dc->search_pc = search_pc + + /* When memchecker is enabled, we need to keep a match between + * translated PC and guest PCs, so memchecker can quickly covert + * one to another. Note that we do that only for user mode. */ +# define ANDROID_CHECK_CODEGEN_PC(search_pc) \ + ((search_pc) || (memcheck_enabled && dc->user)) + +# define ANDROID_END_CODEGEN() \ + do { \ + if (memcheck_enabled && dc->user) { \ + j = gen_opc_ptr - gen_opc_buf; \ + lj++; \ + while (lj <= j) \ + gen_opc_instr_start[lj++] = 0; \ + } \ + } while (0) + +#else /* !CONFIG_MEMCHECK */ + +# define ANDROID_WATCH_CALLSTACK_ARM ((void)0) +# define ANDROID_WATCH_CALLSTACK_THUMB ((void)0) +# define ANDROID_DISAS_CONTEXT_FIELDS /* nothing */ +# define ANDROID_START_CODEGEN(s) ((void)(s)) +# define ANDROID_CHECK_CODEGEN_PC(s) (s) +# define ANDROID_END_CODEGEN() ((void)0) + +#endif /* !CONFIG_MEMCHECK */ + + +/***** + ***** + ***** + ***** C O N F I G _ T R A C E + ***** + ***** + *****/ + +#ifdef CONFIG_TRACE + +#include "trace.h" +#define gen_traceInsn() gen_helper_traceInsn() + +static void +gen_traceTicks( int count ) +{ + TCGv tmp = tcg_temp_new_i32(); + tcg_gen_movi_i32(tmp, count); + gen_helper_traceTicks(tmp); + tcg_temp_free_i32(tmp); +} + +static void +gen_traceBB( uint64_t bbNum, void* tb ) +{ +#if HOST_LONG_BITS == 32 + TCGv_i64 tmpNum = tcg_temp_new_i64(); + TCGv_i32 tmpTb = tcg_temp_new_i32(); + + tcg_gen_movi_i64(tmpNum, (int64_t)bbNum); + tcg_gen_movi_i32(tmpTb, (int32_t)tb); + gen_helper_traceBB32(tmpNum, tmpTb); + tcg_temp_free_i32(tmpTb); + tcg_temp_free_i64(tmpNum); +#elif HOST_LONG_BITS == 64 + TCGv_i64 tmpNum = tcg_temp_new_i64(); + TCGv_i64 tmpTb = tcg_temp_new_i64(); + + tcg_gen_movi_i64(tmpNum, (int64_t)bbNum); + tcg_gen_movi_i64(tmpTb, (int64_t)tb); + gen_helper_traceBB64(tmpNum, tmpTb); + tcg_temp_free_i64(tmpTb); + tcg_temp_free_i64(tmpNum); +#endif +} + +# define ANDROID_TRACE_DECLS int ticks = 0; + +# define ANDROID_TRACE_START_ARM() \ + do { \ + if (tracing) { \ + trace_add_insn(insn, 0); \ + ticks = get_insn_ticks_arm(insn); \ + gen_traceInsn(); \ + } \ + } while (0) + +# define ANDROID_TRACE_START_THUMB() \ + do { \ + if (tracing) { \ + int ticks = get_insn_ticks_thumb(insn); \ + trace_add_insn( insn_wrap_thumb(insn), 1 ); \ + gen_traceInsn(); \ + gen_traceTicks(ticks); \ + } \ + } while (0) + +# define ANDROID_TRACE_GEN_TICKS() \ + do { \ + if (tracing) { \ + } \ + } while (0) + +# define ANDROID_TRACE_GEN_SINGLE_TICK() \ + do { \ + if (tracing) { \ + gen_traceTicks(1); \ + ticks -= 1; \ + } \ + } while (0) + +# define ANDROID_TRACE_GEN_OTHER_TICKS() \ + do { \ + if (tracing && ticks > 0) { \ + gen_traceTicks(ticks); \ + } \ + } while (0) + +# define ANDROID_TRACE_START_BB() \ + do { \ + if (tracing) { \ + gen_traceBB(trace_static_bb_num(), tb); \ + trace_bb_start(dc->pc); \ + } \ + } while (0) + +# define ANDROID_TRACE_END_BB() \ + do { \ + if (tracing) { \ + trace_bb_end(); \ + } \ + } while (0) + +#else /* !CONFIG_TRACE */ + +# define ANDROID_TRACE_DECLS /* nothing */ +# define ANDROID_TRACE_START_ARM() ((void)0) +# define ANDROID_TRACE_START_THUMB() ((void)0) + +# define ANDROID_TRACE_GEN_TICKS() ((void)0) +# define ANDROID_TRACE_GEN_SINGLE_TICK() ((void)0) +# define ANDROID_TRACE_GEN_OTHER_TICKS() ((void)0) + +# define ANDROID_TRACE_START_BB() ((void)0) +# define ANDROID_TRACE_END_BB() ((void)0) + +#endif /* !CONFIG_TRACE */ + diff --git a/target-arm/translate.c b/target-arm/translate.c index 019c295..1e189f8 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -30,10 +30,6 @@ #include "tcg-op.h" #include "qemu-log.h" -#ifdef CONFIG_TRACE -#include "trace.h" -#endif - #include "helpers.h" #define GEN_HELPER 1 #include "helpers.h" @@ -66,39 +62,17 @@ typedef struct DisasContext { #endif #ifdef CONFIG_MEMCHECK int search_pc; -#endif // CONFIG_MEMCHECK +#endif } DisasContext; +#include "translate-android.h" + #if defined(CONFIG_USER_ONLY) #define IS_USER(s) 1 #else #define IS_USER(s) (s->user) #endif -#ifdef CONFIG_TRACE -#include "helpers.h" -#endif /* CONFIG_TRACE */ - -#ifdef CONFIG_MEMCHECK -/* - * Memchecker addition in this module is intended to inject qemu callback into - * translated code for each BL/BLX, as well as BL/BLX returns. These callbacks - * are used to build calling stack of the thread in order to provide better - * reporting on memory access violations. Although this may seem as something - * that may gratly impact the performance, in reality it doesn't. Overhead that - * is added by setting up callbacks and by callbacks themselves is neglectable. - * On the other hand, maintaining calling stack can indeed add some perf. - * overhead (TODO: provide solid numbers here). - * One of the things to watch out with regards to injecting callbacks, is - * consistency between intermediate code generated for execution, and for guest - * PC address calculation. If code doesn't match, a segmentation fault is - * guaranteed. - */ - -#include "memcheck/memcheck_proc_management.h" -#include "memcheck_arm_helpers.h" -#endif // CONFIG_MEMCHECK - /* These instructions trap after executing, so defer them until after the conditional executions state has been updated. */ #define DISAS_WFI 4 @@ -5756,50 +5730,10 @@ static void gen_logicq_cc(TCGv_i64 val) } -#ifdef CONFIG_TRACE - -#define gen_traceInsn() gen_helper_traceInsn() - -static void -gen_traceTicks( int count ) -{ - TCGv tmp = tcg_temp_new_i32(); - tcg_gen_movi_i32(tmp, count); - gen_helper_traceTicks(tmp); - tcg_temp_free_i32(tmp); -} - -static void -gen_traceBB( uint64_t bbNum, void* tb ) -{ -#if HOST_LONG_BITS == 32 - TCGv_i64 tmpNum = tcg_temp_new_i64(); - TCGv_i32 tmpTb = tcg_temp_new_i32(); - - tcg_gen_movi_i64(tmpNum, (int64_t)bbNum); - tcg_gen_movi_i32(tmpTb, (int32_t)tb); - gen_helper_traceBB32(tmpNum, tmpTb); - tcg_temp_free_i32(tmpTb); - tcg_temp_free_i64(tmpNum); -#elif HOST_LONG_BITS == 64 - TCGv_i64 tmpNum = tcg_temp_new_i64(); - TCGv_i64 tmpTb = tcg_temp_new_i64(); - - tcg_gen_movi_i64(tmpNum, (int64_t)bbNum); - tcg_gen_movi_i64(tmpTb, (int64_t)tb); - gen_helper_traceBB64(tmpNum, tmpTb); - tcg_temp_free_i64(tmpTb); - tcg_temp_free_i64(tmpNum); -#endif -} -#endif /* CONFIG_TRACE */ - static void disas_arm_insn(CPUState * env, DisasContext *s) { unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh; -#ifdef CONFIG_TRACE - int ticks = 0; -#endif + ANDROID_TRACE_DECLS TCGv tmp; TCGv tmp2; TCGv tmp3; @@ -5807,27 +5741,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) TCGv_i64 tmp64; insn = ldl_code(s->pc); -#ifdef CONFIG_MEMCHECK - if (watch_call_stack(s)) { - if (is_ret_address(env, s->pc)) { - set_on_ret(s->pc); - } - if (is_arm_bl_or_blx(insn)) { - set_on_call(s->pc, s->pc + 4); - if (!s->search_pc) { - register_ret_address(env, s->pc + 4); - } - } - } -#endif // CONFIG_MEMCHECK + ANDROID_WATCH_CALLSTACK_ARM(s); -#ifdef CONFIG_TRACE - if (tracing) { - trace_add_insn(insn, 0); - ticks = get_insn_ticks_arm(insn); - gen_traceInsn(); - } -#endif + ANDROID_TRACE_START_ARM(); s->pc += 4; @@ -5836,11 +5752,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) goto illegal_op; cond = insn >> 28; if (cond == 0xf){ -#ifdef CONFIG_TRACE - if (tracing) { - gen_traceTicks(ticks); - } -#endif + ANDROID_TRACE_GEN_TICKS(); /* Unconditional instructions. */ if (((insn >> 25) & 7) == 1) { /* NEON Data processing. */ @@ -6028,25 +5940,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s) goto illegal_op; } if (cond != 0xe) { -#ifdef CONFIG_TRACE - if (tracing) { - /* a non-executed conditional instruction takes */ - /* only 1 cycle */ - gen_traceTicks(1); - ticks -= 1; - } -#endif + ANDROID_TRACE_GEN_SINGLE_TICK(); /* if not always execute, we generate a conditional jump to next instruction */ s->condlabel = gen_new_label(); gen_test_cc(cond ^ 1, s->condlabel); s->condjmp = 1; } -#ifdef CONFIG_TRACE - if (tracing && ticks > 0) { - gen_traceTicks(ticks); - } -#endif + ANDROID_TRACE_GEN_OTHER_TICKS(); if ((insn & 0x0f900000) == 0x03000000) { if ((insn & (1 << 21)) == 0) { ARCH(6T2); @@ -7198,14 +7099,7 @@ static int disas_thumb2_insn(CPUState *env, DisasContext *s, uint16_t insn_hw1) } insn = lduw_code(s->pc); -#ifdef CONFIG_TRACE - if (tracing) { - int ticks = get_insn_ticks_thumb(insn); - trace_add_insn( insn_wrap_thumb(insn), 1 ); - gen_traceInsn(); - gen_traceTicks(ticks); - } -#endif + ANDROID_TRACE_START_THUMB(); insn |= (uint32_t)insn_hw1 << 16; @@ -8188,29 +8082,10 @@ static void disas_thumb_insn(CPUState *env, DisasContext *s) insn = lduw_code(s->pc); -#ifdef CONFIG_MEMCHECK - if (watch_call_stack(s)) { - target_ulong ret_off; - if (is_ret_address(env, s->pc)) { - set_on_ret(s->pc); - } - 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); - } - } - } -#endif // CONFIG_MEMCHECK - -#ifdef CONFIG_TRACE - if (tracing) { - int ticks = get_insn_ticks_thumb(insn); - trace_add_insn( insn_wrap_thumb(insn), 1 ); - gen_traceInsn(); - gen_traceTicks(ticks); - } -#endif + ANDROID_WATCH_CALLSTACK_THUMB(s); + + ANDROID_TRACE_START_THUMB(); + s->pc += 2; switch (insn >> 12) { @@ -8888,9 +8763,7 @@ static inline void gen_intermediate_code_internal(CPUState *env, dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR; } #endif -#ifdef CONFIG_MEMCHECK - dc->search_pc = search_pc; -#endif // CONFIG_MEMCHECK + ANDROID_START_CODEGEN(search_pc); cpu_F0s = tcg_temp_new_i32(); cpu_F1s = tcg_temp_new_i32(); cpu_F0d = tcg_temp_new_i64(); @@ -8907,12 +8780,7 @@ static inline void gen_intermediate_code_internal(CPUState *env, max_insns = CF_COUNT_MASK; gen_icount_start(); -#ifdef CONFIG_TRACE - if (tracing) { - gen_traceBB(trace_static_bb_num(), tb); - trace_bb_start(dc->pc); - } -#endif + ANDROID_TRACE_START_BB(); do { #ifdef CONFIG_USER_ONLY @@ -8950,14 +8818,7 @@ static inline void gen_intermediate_code_internal(CPUState *env, } } -#ifdef CONFIG_MEMCHECK - /* When memchecker is enabled, we need to keep a match between - * translated PC and guest PCs, so memchecker can quickly covert - * one to another. Note that we do that only for user mode. */ - if (search_pc || (memcheck_enabled && dc->user)) { -#else // CONFIG_MEMCHECK - if (search_pc) { -#endif // CONFIG_MEMCHECK + if (ANDROID_CHECK_CODEGEN_PC(search_pc)) { j = gen_opc_ptr - gen_opc_buf; if (lj < j) { lj++; @@ -9007,11 +8868,7 @@ static inline void gen_intermediate_code_internal(CPUState *env, dc->pc < next_page_start && num_insns < max_insns); -#ifdef CONFIG_TRACE - if (tracing) { - trace_bb_end(); - } -#endif + ANDROID_TRACE_END_BB(); if (tb->cflags & CF_LAST_IO) { if (dc->condjmp) { @@ -9104,14 +8961,7 @@ done_generating: while (lj <= j) gen_opc_instr_start[lj++] = 0; } else { -#ifdef CONFIG_MEMCHECK - if (memcheck_enabled && dc->user) { - j = gen_opc_ptr - gen_opc_buf; - lj++; - while (lj <= j) - gen_opc_instr_start[lj++] = 0; - } -#endif // CONFIG_MEMCHECK + ANDROID_END_CODEGEN(); tb->size = dc->pc - pc_start; tb->icount = num_insns; } -- cgit v1.1