11c3d42c4SPhilippe Mathieu-Daudé /* 21c3d42c4SPhilippe Mathieu-Daudé * CPU watchpoints 31c3d42c4SPhilippe Mathieu-Daudé * 41c3d42c4SPhilippe Mathieu-Daudé * Copyright (c) 2003 Fabrice Bellard 51c3d42c4SPhilippe Mathieu-Daudé * 61c3d42c4SPhilippe Mathieu-Daudé * This library is free software; you can redistribute it and/or 71c3d42c4SPhilippe Mathieu-Daudé * modify it under the terms of the GNU Lesser General Public 81c3d42c4SPhilippe Mathieu-Daudé * License as published by the Free Software Foundation; either 91c3d42c4SPhilippe Mathieu-Daudé * version 2.1 of the License, or (at your option) any later version. 101c3d42c4SPhilippe Mathieu-Daudé * 111c3d42c4SPhilippe Mathieu-Daudé * This library is distributed in the hope that it will be useful, 121c3d42c4SPhilippe Mathieu-Daudé * but WITHOUT ANY WARRANTY; without even the implied warranty of 131c3d42c4SPhilippe Mathieu-Daudé * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 141c3d42c4SPhilippe Mathieu-Daudé * Lesser General Public License for more details. 151c3d42c4SPhilippe Mathieu-Daudé * 161c3d42c4SPhilippe Mathieu-Daudé * You should have received a copy of the GNU Lesser General Public 171c3d42c4SPhilippe Mathieu-Daudé * License along with this library; if not, see <http://www.gnu.org/licenses/>. 181c3d42c4SPhilippe Mathieu-Daudé */ 191c3d42c4SPhilippe Mathieu-Daudé 201c3d42c4SPhilippe Mathieu-Daudé #include "qemu/osdep.h" 211c3d42c4SPhilippe Mathieu-Daudé #include "qemu/main-loop.h" 2254699338SRichard Henderson #include "exec/breakpoint.h" 2354699338SRichard Henderson #include "exec/cpu-interrupt.h" 24487a31e0SPhilippe Mathieu-Daudé #include "exec/page-protection.h" 258865049bSPhilippe Mathieu-Daudé #include "exec/translation-block.h" 2632cad1ffSPhilippe Mathieu-Daudé #include "system/tcg.h" 2732cad1ffSPhilippe Mathieu-Daudé #include "system/replay.h" 2815017436SPhilippe Mathieu-Daudé #include "accel/tcg/cpu-ops.h" 291c3d42c4SPhilippe Mathieu-Daudé #include "hw/core/cpu.h" 301760c5ccSPhilippe Mathieu-Daudé #include "internal-common.h" 311c3d42c4SPhilippe Mathieu-Daudé 321c3d42c4SPhilippe Mathieu-Daudé /* 331c3d42c4SPhilippe Mathieu-Daudé * Return true if this watchpoint address matches the specified 341c3d42c4SPhilippe Mathieu-Daudé * access (ie the address range covered by the watchpoint overlaps 351c3d42c4SPhilippe Mathieu-Daudé * partially or completely with the address range covered by the 361c3d42c4SPhilippe Mathieu-Daudé * access). 371c3d42c4SPhilippe Mathieu-Daudé */ 381c3d42c4SPhilippe Mathieu-Daudé static inline bool watchpoint_address_matches(CPUWatchpoint *wp, 391c3d42c4SPhilippe Mathieu-Daudé vaddr addr, vaddr len) 401c3d42c4SPhilippe Mathieu-Daudé { 411c3d42c4SPhilippe Mathieu-Daudé /* 421c3d42c4SPhilippe Mathieu-Daudé * We know the lengths are non-zero, but a little caution is 431c3d42c4SPhilippe Mathieu-Daudé * required to avoid errors in the case where the range ends 441c3d42c4SPhilippe Mathieu-Daudé * exactly at the top of the address space and so addr + len 451c3d42c4SPhilippe Mathieu-Daudé * wraps round to zero. 461c3d42c4SPhilippe Mathieu-Daudé */ 471c3d42c4SPhilippe Mathieu-Daudé vaddr wpend = wp->vaddr + wp->len - 1; 481c3d42c4SPhilippe Mathieu-Daudé vaddr addrend = addr + len - 1; 491c3d42c4SPhilippe Mathieu-Daudé 501c3d42c4SPhilippe Mathieu-Daudé return !(addr > wpend || wp->vaddr > addrend); 511c3d42c4SPhilippe Mathieu-Daudé } 521c3d42c4SPhilippe Mathieu-Daudé 531c3d42c4SPhilippe Mathieu-Daudé /* Return flags for watchpoints that match addr + prot. */ 541c3d42c4SPhilippe Mathieu-Daudé int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len) 551c3d42c4SPhilippe Mathieu-Daudé { 561c3d42c4SPhilippe Mathieu-Daudé CPUWatchpoint *wp; 571c3d42c4SPhilippe Mathieu-Daudé int ret = 0; 581c3d42c4SPhilippe Mathieu-Daudé 591c3d42c4SPhilippe Mathieu-Daudé QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { 601c3d42c4SPhilippe Mathieu-Daudé if (watchpoint_address_matches(wp, addr, len)) { 611c3d42c4SPhilippe Mathieu-Daudé ret |= wp->flags; 621c3d42c4SPhilippe Mathieu-Daudé } 631c3d42c4SPhilippe Mathieu-Daudé } 641c3d42c4SPhilippe Mathieu-Daudé return ret; 651c3d42c4SPhilippe Mathieu-Daudé } 661c3d42c4SPhilippe Mathieu-Daudé 671c3d42c4SPhilippe Mathieu-Daudé /* Generate a debug exception if a watchpoint has been hit. */ 681c3d42c4SPhilippe Mathieu-Daudé void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, 691c3d42c4SPhilippe Mathieu-Daudé MemTxAttrs attrs, int flags, uintptr_t ra) 701c3d42c4SPhilippe Mathieu-Daudé { 711c3d42c4SPhilippe Mathieu-Daudé CPUWatchpoint *wp; 721c3d42c4SPhilippe Mathieu-Daudé 731c3d42c4SPhilippe Mathieu-Daudé assert(tcg_enabled()); 741c3d42c4SPhilippe Mathieu-Daudé if (cpu->watchpoint_hit) { 751c3d42c4SPhilippe Mathieu-Daudé /* 761c3d42c4SPhilippe Mathieu-Daudé * We re-entered the check after replacing the TB. 771c3d42c4SPhilippe Mathieu-Daudé * Now raise the debug interrupt so that it will 781c3d42c4SPhilippe Mathieu-Daudé * trigger after the current instruction. 791c3d42c4SPhilippe Mathieu-Daudé */ 801c3d42c4SPhilippe Mathieu-Daudé bql_lock(); 811c3d42c4SPhilippe Mathieu-Daudé cpu_interrupt(cpu, CPU_INTERRUPT_DEBUG); 821c3d42c4SPhilippe Mathieu-Daudé bql_unlock(); 831c3d42c4SPhilippe Mathieu-Daudé return; 841c3d42c4SPhilippe Mathieu-Daudé } 851c3d42c4SPhilippe Mathieu-Daudé 86*e27fa95fSPhilippe Mathieu-Daudé if (cpu->cc->tcg_ops->adjust_watchpoint_address) { 871c3d42c4SPhilippe Mathieu-Daudé /* this is currently used only by ARM BE32 */ 88*e27fa95fSPhilippe Mathieu-Daudé addr = cpu->cc->tcg_ops->adjust_watchpoint_address(cpu, addr, len); 891c3d42c4SPhilippe Mathieu-Daudé } 901c3d42c4SPhilippe Mathieu-Daudé 911c3d42c4SPhilippe Mathieu-Daudé assert((flags & ~BP_MEM_ACCESS) == 0); 921c3d42c4SPhilippe Mathieu-Daudé QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) { 931c3d42c4SPhilippe Mathieu-Daudé int hit_flags = wp->flags & flags; 941c3d42c4SPhilippe Mathieu-Daudé 951c3d42c4SPhilippe Mathieu-Daudé if (hit_flags && watchpoint_address_matches(wp, addr, len)) { 961c3d42c4SPhilippe Mathieu-Daudé if (replay_running_debug()) { 971c3d42c4SPhilippe Mathieu-Daudé /* 981c3d42c4SPhilippe Mathieu-Daudé * replay_breakpoint reads icount. 991c3d42c4SPhilippe Mathieu-Daudé * Force recompile to succeed, because icount may 1001c3d42c4SPhilippe Mathieu-Daudé * be read only at the end of the block. 1011c3d42c4SPhilippe Mathieu-Daudé */ 1021c3d42c4SPhilippe Mathieu-Daudé if (!cpu->neg.can_do_io) { 1031c3d42c4SPhilippe Mathieu-Daudé /* Force execution of one insn next time. */ 1041c3d42c4SPhilippe Mathieu-Daudé cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu); 1051c3d42c4SPhilippe Mathieu-Daudé cpu_loop_exit_restore(cpu, ra); 1061c3d42c4SPhilippe Mathieu-Daudé } 1071c3d42c4SPhilippe Mathieu-Daudé /* 1081c3d42c4SPhilippe Mathieu-Daudé * Don't process the watchpoints when we are 1091c3d42c4SPhilippe Mathieu-Daudé * in a reverse debugging operation. 1101c3d42c4SPhilippe Mathieu-Daudé */ 1111c3d42c4SPhilippe Mathieu-Daudé replay_breakpoint(); 1121c3d42c4SPhilippe Mathieu-Daudé return; 1131c3d42c4SPhilippe Mathieu-Daudé } 1141c3d42c4SPhilippe Mathieu-Daudé 1151c3d42c4SPhilippe Mathieu-Daudé wp->flags |= hit_flags << BP_HIT_SHIFT; 1161c3d42c4SPhilippe Mathieu-Daudé wp->hitaddr = MAX(addr, wp->vaddr); 1171c3d42c4SPhilippe Mathieu-Daudé wp->hitattrs = attrs; 1181c3d42c4SPhilippe Mathieu-Daudé 1191c3d42c4SPhilippe Mathieu-Daudé if (wp->flags & BP_CPU 120*e27fa95fSPhilippe Mathieu-Daudé && cpu->cc->tcg_ops->debug_check_watchpoint 121*e27fa95fSPhilippe Mathieu-Daudé && !cpu->cc->tcg_ops->debug_check_watchpoint(cpu, wp)) { 1221c3d42c4SPhilippe Mathieu-Daudé wp->flags &= ~BP_WATCHPOINT_HIT; 1231c3d42c4SPhilippe Mathieu-Daudé continue; 1241c3d42c4SPhilippe Mathieu-Daudé } 1251c3d42c4SPhilippe Mathieu-Daudé cpu->watchpoint_hit = wp; 1261c3d42c4SPhilippe Mathieu-Daudé 1271c3d42c4SPhilippe Mathieu-Daudé mmap_lock(); 1281c3d42c4SPhilippe Mathieu-Daudé /* This call also restores vCPU state */ 1291c3d42c4SPhilippe Mathieu-Daudé tb_check_watchpoint(cpu, ra); 1301c3d42c4SPhilippe Mathieu-Daudé if (wp->flags & BP_STOP_BEFORE_ACCESS) { 1311c3d42c4SPhilippe Mathieu-Daudé cpu->exception_index = EXCP_DEBUG; 1321c3d42c4SPhilippe Mathieu-Daudé mmap_unlock(); 1331c3d42c4SPhilippe Mathieu-Daudé cpu_loop_exit(cpu); 1341c3d42c4SPhilippe Mathieu-Daudé } else { 1351c3d42c4SPhilippe Mathieu-Daudé /* Force execution of one insn next time. */ 1361c3d42c4SPhilippe Mathieu-Daudé cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu); 1371c3d42c4SPhilippe Mathieu-Daudé mmap_unlock(); 1381c3d42c4SPhilippe Mathieu-Daudé cpu_loop_exit_noexc(cpu); 1391c3d42c4SPhilippe Mathieu-Daudé } 1401c3d42c4SPhilippe Mathieu-Daudé } else { 1411c3d42c4SPhilippe Mathieu-Daudé wp->flags &= ~BP_WATCHPOINT_HIT; 1421c3d42c4SPhilippe Mathieu-Daudé } 1431c3d42c4SPhilippe Mathieu-Daudé } 1441c3d42c4SPhilippe Mathieu-Daudé } 145