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é */
watchpoint_address_matches(CPUWatchpoint * wp,vaddr addr,vaddr len)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. */
cpu_watchpoint_address_matches(CPUState * cpu,vaddr addr,vaddr len)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. */
cpu_check_watchpoint(CPUState * cpu,vaddr addr,vaddr len,MemTxAttrs attrs,int flags,uintptr_t ra)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é /* This call also restores vCPU state */
1281c3d42c4SPhilippe Mathieu-Daudé tb_check_watchpoint(cpu, ra);
1291c3d42c4SPhilippe Mathieu-Daudé if (wp->flags & BP_STOP_BEFORE_ACCESS) {
1301c3d42c4SPhilippe Mathieu-Daudé cpu->exception_index = EXCP_DEBUG;
1311c3d42c4SPhilippe Mathieu-Daudé cpu_loop_exit(cpu);
1321c3d42c4SPhilippe Mathieu-Daudé } else {
1331c3d42c4SPhilippe Mathieu-Daudé /* Force execution of one insn next time. */
1341c3d42c4SPhilippe Mathieu-Daudé cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu);
1351c3d42c4SPhilippe Mathieu-Daudé cpu_loop_exit_noexc(cpu);
1361c3d42c4SPhilippe Mathieu-Daudé }
1371c3d42c4SPhilippe Mathieu-Daudé } else {
1381c3d42c4SPhilippe Mathieu-Daudé wp->flags &= ~BP_WATCHPOINT_HIT;
1391c3d42c4SPhilippe Mathieu-Daudé }
1401c3d42c4SPhilippe Mathieu-Daudé }
1411c3d42c4SPhilippe Mathieu-Daudé }
142