From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Kcn1Y-0006kA-MS for qemu-devel@nongnu.org; Mon, 08 Sep 2008 16:07:48 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Kcn1X-0006jp-2V for qemu-devel@nongnu.org; Mon, 08 Sep 2008 16:07:48 -0400 Received: from [199.232.76.173] (port=37327 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Kcn1W-0006jm-Ve for qemu-devel@nongnu.org; Mon, 08 Sep 2008 16:07:47 -0400 Received: from fmmailgate02.web.de ([217.72.192.227]:43560) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Kcn1V-0000ve-Uo for qemu-devel@nongnu.org; Mon, 08 Sep 2008 16:07:46 -0400 Received: from smtp06.web.de (fmsmtp06.dlan.cinetic.de [172.20.5.172]) by fmmailgate02.web.de (Postfix) with ESMTP id 1A07FEC7C8E7 for ; Mon, 8 Sep 2008 22:07:45 +0200 (CEST) Received: from [88.65.248.241] (helo=[192.168.1.198]) by smtp06.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.109 #226) id 1Kcn1U-00047B-00 for qemu-devel@nongnu.org; Mon, 08 Sep 2008 22:07:44 +0200 Message-ID: <48C58610.1020200@web.de> Date: Mon, 08 Sep 2008 22:07:44 +0200 From: Jan Kiszka MIME-Version: 1.0 References: <486CF559.5090805@siemens.com> <48AC2E09.3030405@siemens.com> <48AC2EE9.8050803@siemens.com> In-Reply-To: <48AC2EE9.8050803@siemens.com> Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: 7bit Sender: jan.kiszka@web.de Subject: [Qemu-devel] Re: [RESEND][PATCH 2/13] Refactor and enhance break/watchpoint API Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Jan Kiszka wrote: > This patch prepares the QEMU cpu_watchpoint/breakpoint API to allow the > succeeding enhancements this series comes with. > > First of all, it overcomes MAX_BREAKPOINTS/MAX_WATCHPOINTS by switching > to dynamically allocated data structures that are kept in linked lists. > This also allows to return a stable reference to the related objects, > required for later introduced x86 debug register support. > > Breakpoints and watchpoints are stored with their full information set > and an additional flag field that makes them easily extensible for use > beyond pure guest debugging. > > Finally, this restructuring lays the foundation for KVM to hook into > the debugging infrastructure, providing its own services where hardware > virtualization demands it. Once QEMUAccel is considered for merge, > those entry point should be included into its abstraction layer so that > accellerators can hook in even more cleanly. > Rebased over #5181, made xlat_gdb_type static. Signed-off-by: Jan Kiszka --- cpu-all.h | 23 +++-- cpu-defs.h | 26 +++--- exec.c | 201 ++++++++++++++++++++++++++++------------------- gdbstub.c | 131 ++++++++++++++++-------------- target-alpha/translate.c | 7 - target-arm/translate.c | 9 +- target-cris/translate.c | 9 +- target-i386/translate.c | 7 - target-m68k/translate.c | 9 +- target-mips/translate.c | 7 - target-ppc/translate.c | 7 - target-sh4/translate.c | 7 - target-sparc/translate.c | 7 - 13 files changed, 264 insertions(+), 186 deletions(-) Index: b/cpu-all.h =================================================================== --- a/cpu-all.h +++ b/cpu-all.h @@ -799,12 +799,23 @@ extern int use_icount; void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask); -int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type); -int cpu_watchpoint_remove(CPUState *env, target_ulong addr); -void cpu_watchpoint_remove_all(CPUState *env); -int cpu_breakpoint_insert(CPUState *env, target_ulong pc); -int cpu_breakpoint_remove(CPUState *env, target_ulong pc); -void cpu_breakpoint_remove_all(CPUState *env); +/* Breakpoint/watchpoint flags */ +#define BP_MEM_READ 0x01 +#define BP_MEM_WRITE 0x02 +#define BP_MEM_ACCESS (BP_MEM_READ | BP_MEM_WRITE) +#define BP_GDB 0x10 + +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags, + CPUBreakpoint **breakpoint); +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags); +void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint); +void cpu_breakpoint_remove_all(CPUState *env, int mask); +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len, + int flags, CPUWatchpoint **watchpoint); +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, + target_ulong len, int flags); +void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint); +void cpu_watchpoint_remove_all(CPUState *env, int mask); #define SSTEP_ENABLE 0x1 /* Enable simulated HW single stepping */ #define SSTEP_NOIRQ 0x2 /* Do not use IRQ while single stepping */ Index: b/exec.c =================================================================== --- a/exec.c +++ b/exec.c @@ -503,7 +503,6 @@ void cpu_exec_init(CPUState *env) cpu_index++; } env->cpu_index = cpu_index; - env->nb_watchpoints = 0; *penv = env; #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION, @@ -1277,107 +1276,150 @@ static void breakpoint_invalidate(CPUSta #endif /* Add a watchpoint. */ -int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type) +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len, + int flags, CPUWatchpoint **watchpoint) { - int i; + CPUWatchpoint *wp; - for (i = 0; i < env->nb_watchpoints; i++) { - if (addr == env->watchpoint[i].vaddr) - return 0; - } - if (env->nb_watchpoints >= MAX_WATCHPOINTS) - return -1; + wp = qemu_malloc(sizeof(*wp)); + if (!wp) + return -ENOBUFS; + + wp->vaddr = addr; + wp->len = len; + wp->flags = flags; + + wp->next = env->watchpoints; + wp->prev = NULL; + if (wp->next) + wp->next->prev = wp; + env->watchpoints = wp; - i = env->nb_watchpoints++; - env->watchpoint[i].vaddr = addr; - env->watchpoint[i].type = type; tlb_flush_page(env, addr); /* FIXME: This flush is needed because of the hack to make memory ops terminate the TB. It can be removed once the proper IO trap and re-execute bits are in. */ tb_flush(env); - return i; -} -/* Remove a watchpoint. */ -int cpu_watchpoint_remove(CPUState *env, target_ulong addr) -{ - int i; + if (watchpoint) + *watchpoint = wp; + return 0; +} - for (i = 0; i < env->nb_watchpoints; i++) { - if (addr == env->watchpoint[i].vaddr) { - env->nb_watchpoints--; - env->watchpoint[i] = env->watchpoint[env->nb_watchpoints]; - tlb_flush_page(env, addr); +/* Remove a specific watchpoint. */ +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len, + int flags) +{ + CPUWatchpoint *wp; + + for (wp = env->watchpoints; wp != NULL; wp = wp->next) { + if (addr == wp->vaddr && len == wp->len && flags == wp->flags) { + cpu_watchpoint_remove_by_ref(env, wp); return 0; } } - return -1; + return -ENOENT; } -/* Remove all watchpoints. */ -void cpu_watchpoint_remove_all(CPUState *env) { - int i; +/* Remove a specific watchpoint by reference. */ +void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint) +{ + if (watchpoint->next) + watchpoint->next->prev = watchpoint->prev; + if (watchpoint->prev) + watchpoint->prev->next = watchpoint->next; + else + env->watchpoints = watchpoint->next; - for (i = 0; i < env->nb_watchpoints; i++) { - tlb_flush_page(env, env->watchpoint[i].vaddr); - } - env->nb_watchpoints = 0; + tlb_flush_page(env, watchpoint->vaddr); + + qemu_free(watchpoint); } -/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a - breakpoint is reached */ -int cpu_breakpoint_insert(CPUState *env, target_ulong pc) +/* Remove all matching watchpoints. */ +void cpu_watchpoint_remove_all(CPUState *env, int mask) { -#if defined(TARGET_HAS_ICE) - int i; + CPUWatchpoint *wp; - for(i = 0; i < env->nb_breakpoints; i++) { - if (env->breakpoints[i] == pc) - return 0; - } + for (wp = env->watchpoints; wp != NULL; wp = wp->next) + if (wp->flags & mask) + cpu_watchpoint_remove_by_ref(env, wp); +} - if (env->nb_breakpoints >= MAX_BREAKPOINTS) - return -1; - env->breakpoints[env->nb_breakpoints++] = pc; +/* Add a breakpoint. */ +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags, + CPUBreakpoint **breakpoint) +{ +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp; + + bp = qemu_malloc(sizeof(*bp)); + if (!bp) + return -ENOBUFS; + + bp->pc = pc; + bp->flags = flags; + + bp->next = env->breakpoints; + bp->prev = NULL; + if (bp->next) + bp->next->prev = bp; + env->breakpoints = bp; breakpoint_invalidate(env, pc); + + if (breakpoint) + *breakpoint = bp; return 0; #else - return -1; + return -ENOSYS; #endif } -/* remove all breakpoints */ -void cpu_breakpoint_remove_all(CPUState *env) { +/* Remove a specific breakpoint. */ +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags) +{ #if defined(TARGET_HAS_ICE) - int i; - for(i = 0; i < env->nb_breakpoints; i++) { - breakpoint_invalidate(env, env->breakpoints[i]); + CPUBreakpoint *bp; + + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (bp->pc == pc && bp->flags == flags) { + cpu_breakpoint_remove_by_ref(env, bp); + return 0; + } } - env->nb_breakpoints = 0; + return -ENOENT; +#else + return -ENOSYS; #endif } -/* remove a breakpoint */ -int cpu_breakpoint_remove(CPUState *env, target_ulong pc) +/* Remove a specific breakpoint by reference. */ +void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint) { #if defined(TARGET_HAS_ICE) - int i; - for(i = 0; i < env->nb_breakpoints; i++) { - if (env->breakpoints[i] == pc) - goto found; - } - return -1; - found: - env->nb_breakpoints--; - if (i < env->nb_breakpoints) - env->breakpoints[i] = env->breakpoints[env->nb_breakpoints]; + if (breakpoint->next) + breakpoint->next->prev = breakpoint->prev; + if (breakpoint->prev) + breakpoint->prev->next = breakpoint->next; + else + env->breakpoints = breakpoint->next; - breakpoint_invalidate(env, pc); - return 0; -#else - return -1; + breakpoint_invalidate(env, breakpoint->pc); + + qemu_free(breakpoint); +#endif +} + +/* Remove all matching breakpoints. */ +void cpu_breakpoint_remove_all(CPUState *env, int mask) +{ +#if defined(TARGET_HAS_ICE) + CPUBreakpoint *bp; + + for (bp = env->breakpoints; bp != NULL; bp = bp->next) + if (bp->flags & mask) + cpu_breakpoint_remove_by_ref(env, bp); #endif } @@ -1848,7 +1890,7 @@ int tlb_set_page_exec(CPUState *env, tar target_phys_addr_t addend; int ret; CPUTLBEntry *te; - int i; + CPUWatchpoint *wp; target_phys_addr_t iotlb; p = phys_page_find(paddr >> TARGET_PAGE_BITS); @@ -1889,8 +1931,8 @@ int tlb_set_page_exec(CPUState *env, tar code_address = address; /* Make accesses to pages with watchpoints go via the watchpoint trap routines. */ - for (i = 0; i < env->nb_watchpoints; i++) { - if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) { + for (wp = env->watchpoints; wp != NULL; wp = wp->next) { + if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) { iotlb = io_mem_watch + paddr; /* TODO: The memory case can be optimized by not trapping reads of pages with a write breakpoint. */ @@ -2381,13 +2423,12 @@ static void check_watchpoint(int offset, { CPUState *env = cpu_single_env; target_ulong vaddr; - int i; + CPUWatchpoint *wp; vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset; - for (i = 0; i < env->nb_watchpoints; i++) { - if (vaddr == env->watchpoint[i].vaddr - && (env->watchpoint[i].type & flags)) { - env->watchpoint_hit = i + 1; + for (wp = env->watchpoints; wp != NULL; wp = wp->next) { + if (vaddr == wp->vaddr && (wp->flags & flags)) { + env->watchpoint_hit = wp; cpu_interrupt(env, CPU_INTERRUPT_DEBUG); break; } @@ -2399,40 +2440,40 @@ static void check_watchpoint(int offset, phys routines. */ static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr) { - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ); + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_READ); return ldub_phys(addr); } static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr) { - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ); + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_READ); return lduw_phys(addr); } static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr) { - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ); + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_READ); return ldl_phys(addr); } static void watch_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) { - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE); + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_WRITE); stb_phys(addr, val); } static void watch_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) { - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE); + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_WRITE); stw_phys(addr, val); } static void watch_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) { - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE); + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_WRITE); stl_phys(addr, val); } Index: b/gdbstub.c =================================================================== --- a/gdbstub.c +++ b/gdbstub.c @@ -962,10 +962,64 @@ static void cpu_gdb_write_registers(CPUS #endif +/* GDB breakpoint/watchpoint types */ +#define GDB_BREAKPOINT_SW 0 +#define GDB_BREAKPOINT_HW 1 +#define GDB_WATCHPOINT_WRITE 2 +#define GDB_WATCHPOINT_READ 3 +#define GDB_WATCHPOINT_ACCESS 4 + +#ifndef CONFIG_USER_ONLY +static const int xlat_gdb_type[] = { + [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, + [GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ, + [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS, +}; +#endif + +static int gdb_breakpoint_insert(CPUState *env, target_ulong addr, + target_ulong len, int type) +{ + switch (type) { + case GDB_BREAKPOINT_SW ... GDB_BREAKPOINT_HW: + return cpu_breakpoint_insert(env, addr, BP_GDB, NULL); +#ifndef CONFIG_USER_ONLY + case GDB_WATCHPOINT_WRITE ... GDB_WATCHPOINT_ACCESS: + return cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type], + NULL); +#endif + default: + return -ENOSYS; + } +} + +static int gdb_breakpoint_remove(CPUState *env, target_ulong addr, + target_ulong len, int type) +{ + switch (type) { + case GDB_BREAKPOINT_SW ... GDB_BREAKPOINT_HW: + return cpu_breakpoint_remove(env, addr, BP_GDB); +#ifndef CONFIG_USER_ONLY + case GDB_WATCHPOINT_WRITE ... GDB_WATCHPOINT_ACCESS: + return cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]); +#endif + default: + return -ENOSYS; + } +} + +static void gdb_breakpoint_remove_all(CPUState *env) +{ + cpu_breakpoint_remove_all(env, BP_GDB); +#ifndef CONFIG_USER_ONLY + cpu_watchpoint_remove_all(env, BP_GDB); +#endif +} + static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf) { const char *p; - int ch, reg_size, type; + int ch, reg_size, type, res; char buf[4096]; uint8_t mem_buf[4096]; uint32_t *registers; @@ -985,8 +1039,7 @@ static int gdb_handle_packet(GDBState *s * because gdb is doing and initial connect and the state * should be cleaned up. */ - cpu_breakpoint_remove_all(env); - cpu_watchpoint_remove_all(env); + gdb_breakpoint_remove_all(env); break; case 'c': if (*p != '\0') { @@ -1020,8 +1073,7 @@ static int gdb_handle_packet(GDBState *s exit(0); case 'D': /* Detach packet */ - cpu_breakpoint_remove_all(env); - cpu_watchpoint_remove_all(env); + gdb_breakpoint_remove_all(env); gdb_continue(s); put_packet(s, "OK"); break; @@ -1110,44 +1162,6 @@ static int gdb_handle_packet(GDBState *s put_packet(s, "OK"); break; case 'Z': - type = strtoul(p, (char **)&p, 16); - if (*p == ',') - p++; - addr = strtoull(p, (char **)&p, 16); - if (*p == ',') - p++; - len = strtoull(p, (char **)&p, 16); - switch (type) { - case 0: - case 1: - if (cpu_breakpoint_insert(env, addr) < 0) - goto breakpoint_error; - put_packet(s, "OK"); - break; -#ifndef CONFIG_USER_ONLY - case 2: - type = PAGE_WRITE; - goto insert_watchpoint; - case 3: - type = PAGE_READ; - goto insert_watchpoint; - case 4: - type = PAGE_READ | PAGE_WRITE; - insert_watchpoint: - if (cpu_watchpoint_insert(env, addr, type) < 0) - goto breakpoint_error; - put_packet(s, "OK"); - break; -#endif - default: - put_packet(s, ""); - break; - } - break; - breakpoint_error: - put_packet(s, "E22"); - break; - case 'z': type = strtoul(p, (char **)&p, 16); if (*p == ',') @@ -1156,17 +1170,16 @@ static int gdb_handle_packet(GDBState *s if (*p == ',') p++; len = strtoull(p, (char **)&p, 16); - if (type == 0 || type == 1) { - cpu_breakpoint_remove(env, addr); - put_packet(s, "OK"); -#ifndef CONFIG_USER_ONLY - } else if (type >= 2 || type <= 4) { - cpu_watchpoint_remove(env, addr); - put_packet(s, "OK"); -#endif - } else { + if (ch == 'Z') + res = gdb_breakpoint_insert(env, addr, len, type); + else + res = gdb_breakpoint_remove(env, addr, len, type); + if (res >= 0) + put_packet(s, "OK"); + else if (res == -ENOSYS) put_packet(s, ""); - } + else + put_packet(s, "E22"); break; case 'q': case 'Q': @@ -1236,12 +1249,11 @@ static void gdb_vm_stopped(void *opaque, if (reason == EXCP_DEBUG) { if (s->env->watchpoint_hit) { - switch (s->env->watchpoint[s->env->watchpoint_hit - 1].flags & - (PAGE_READ | PAGE_WRITE)) { - case PAGE_READ: + switch (s->env->watchpoint_hit->flags & BP_MEM_ACCESS) { + case BP_MEM_READ: type = "r"; break; - case PAGE_READ | PAGE_WRITE: + case BP_MEM_ACCESS: type = "a"; break; default: @@ -1249,10 +1261,9 @@ static void gdb_vm_stopped(void *opaque, break; } snprintf(buf, sizeof(buf), "T%02x%swatch:" TARGET_FMT_lx ";", - SIGTRAP, type, - s->env->watchpoint[s->env->watchpoint_hit - 1].vaddr); + SIGTRAP, type, s->env->watchpoint_hit->vaddr); put_packet(s, buf); - s->env->watchpoint_hit = 0; + s->env->watchpoint_hit = NULL; return; } tb_flush(s->env); Index: b/cpu-defs.h =================================================================== --- a/cpu-defs.h +++ b/cpu-defs.h @@ -82,8 +82,6 @@ typedef uint64_t target_phys_addr_t; #define EXCP_HLT 0x10001 /* hlt instruction reached */ #define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */ #define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */ -#define MAX_BREAKPOINTS 32 -#define MAX_WATCHPOINTS 32 #define TB_JMP_CACHE_BITS 12 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS) @@ -142,6 +140,19 @@ typedef struct icount_decr_u16 { } icount_decr_u16; #endif +typedef struct CPUBreakpoint { + target_ulong pc; + int flags; /* BP_* */ + struct CPUBreakpoint *prev, *next; +} CPUBreakpoint; + +typedef struct CPUWatchpoint { + target_ulong vaddr; + target_ulong len; + int flags; /* BP_* */ + struct CPUWatchpoint *prev, *next; +} CPUWatchpoint; + #define CPU_TEMP_BUF_NLONGS 128 #define CPU_COMMON \ struct TranslationBlock *current_tb; /* currently executing TB */ \ @@ -174,16 +185,11 @@ typedef struct icount_decr_u16 { \ /* from this point: preserved by CPU reset */ \ /* ice debug support */ \ - target_ulong breakpoints[MAX_BREAKPOINTS]; \ - int nb_breakpoints; \ + CPUBreakpoint *breakpoints; \ int singlestep_enabled; \ \ - struct { \ - target_ulong vaddr; \ - int type; /* PAGE_READ/PAGE_WRITE */ \ - } watchpoint[MAX_WATCHPOINTS]; \ - int nb_watchpoints; \ - int watchpoint_hit; \ + CPUWatchpoint *watchpoints; \ + CPUWatchpoint *watchpoint_hit; \ \ /* Core interrupt code */ \ jmp_buf jmp_env; \ Index: b/target-i386/translate.c =================================================================== --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7155,6 +7155,7 @@ static inline void gen_intermediate_code DisasContext dc1, *dc = &dc1; target_ulong pc_ptr; uint16_t *gen_opc_end; + CPUBreakpoint *bp; int j, lj, cflags; uint64_t flags; target_ulong pc_start; @@ -7238,9 +7239,9 @@ static inline void gen_intermediate_code gen_icount_start(); for(;;) { - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == pc_ptr) { + if (unlikely(env->breakpoints)) { + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (bp->pc == pc_ptr) { gen_debug(dc, pc_ptr - dc->cs_base); break; } Index: b/target-alpha/translate.c =================================================================== --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -1884,6 +1884,7 @@ static always_inline void gen_intermedia target_ulong pc_start; uint32_t insn; uint16_t *gen_opc_end; + CPUBreakpoint *bp; int j, lj = -1; int ret; int num_insns; @@ -1906,9 +1907,9 @@ static always_inline void gen_intermedia gen_icount_start(); for (ret = 0; ret == 0;) { - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == ctx.pc) { + if (unlikely(env->breakpoints)) { + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (bp->pc == ctx.pc) { gen_excp(&ctx, EXCP_DEBUG, 0); break; } Index: b/target-arm/translate.c =================================================================== --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -8551,6 +8551,7 @@ static inline void gen_intermediate_code int search_pc) { DisasContext dc1, *dc = &dc1; + CPUBreakpoint *bp; uint16_t *gen_opc_end; int j, lj; target_ulong pc_start; @@ -8627,9 +8628,9 @@ static inline void gen_intermediate_code } #endif - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == dc->pc) { + if (unlikely(env->breakpoints)) { + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (bp->pc == dc->pc) { gen_set_condexec(dc); gen_set_pc_im(dc->pc); gen_exception(EXCP_DEBUG); @@ -8682,7 +8683,7 @@ static inline void gen_intermediate_code /* Terminate the TB on memory ops if watchpoints are present. */ /* FIXME: This should be replacd by the deterministic execution * IRQ raising bits. */ - if (dc->is_mem && env->nb_watchpoints) + if (dc->is_mem && env->watchpoints) break; /* Translation stops when a conditional branch is enoutered. Index: b/target-cris/translate.c =================================================================== --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -2973,10 +2973,11 @@ cris_decoder(DisasContext *dc) static void check_breakpoint(CPUState *env, DisasContext *dc) { - int j; - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == dc->pc) { + CPUBreakpoint *bp; + + if (unlikely(env->breakpoints)) { + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (bp->pc == dc->pc) { cris_evaluate_flags (dc); tcg_gen_movi_tl(env_pc, dc->pc); t_gen_raise_exception(EXCP_DEBUG); Index: b/target-m68k/translate.c =================================================================== --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -2915,6 +2915,7 @@ gen_intermediate_code_internal(CPUState { DisasContext dc1, *dc = &dc1; uint16_t *gen_opc_end; + CPUBreakpoint *bp; int j, lj; target_ulong pc_start; int pc_offset; @@ -2948,9 +2949,9 @@ gen_intermediate_code_internal(CPUState do { pc_offset = dc->pc - pc_start; gen_throws_exception = NULL; - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == dc->pc) { + if (unlikely(env->breakpoints)) { + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (bp->pc == dc->pc) { gen_exception(dc, dc->pc, EXCP_DEBUG); dc->is_jmp = DISAS_JUMP; break; @@ -2980,7 +2981,7 @@ gen_intermediate_code_internal(CPUState /* Terminate the TB on memory ops if watchpoints are present. */ /* FIXME: This should be replaced by the deterministic execution * IRQ raising bits. */ - if (dc->is_mem && env->nb_watchpoints) + if (dc->is_mem && env->watchpoints) break; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && Index: b/target-mips/translate.c =================================================================== --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -8458,6 +8458,7 @@ gen_intermediate_code_internal (CPUState DisasContext ctx; target_ulong pc_start; uint16_t *gen_opc_end; + CPUBreakpoint *bp; int j, lj = -1; int num_insns; int max_insns; @@ -8497,9 +8498,9 @@ gen_intermediate_code_internal (CPUState #endif gen_icount_start(); while (ctx.bstate == BS_NONE) { - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == ctx.pc) { + if (unlikely(env->breakpoints)) { + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (bp->pc == ctx.pc) { save_cpu_state(&ctx, 1); ctx.bstate = BS_BRANCH; tcg_gen_helper_0_i(do_raise_exception, EXCP_DEBUG); Index: b/target-ppc/translate.c =================================================================== --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -6215,6 +6215,7 @@ static always_inline void gen_intermedia target_ulong pc_start; uint16_t *gen_opc_end; int supervisor, little_endian; + CPUBreakpoint *bp; int j, lj = -1; int num_insns; int max_insns; @@ -6269,9 +6270,9 @@ static always_inline void gen_intermedia gen_icount_start(); /* Set env in case of segfault during code fetch */ while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) { - if (unlikely(env->nb_breakpoints > 0)) { - for (j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == ctx.nip) { + if (unlikely(env->breakpoints)) { + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (bp->pc == ctx.nip) { gen_update_nip(&ctx, ctx.nip); gen_op_debug(); break; Index: b/target-sh4/translate.c =================================================================== --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1768,6 +1768,7 @@ gen_intermediate_code_internal(CPUState DisasContext ctx; target_ulong pc_start; static uint16_t *gen_opc_end; + CPUBreakpoint *bp; int i, ii; int num_insns; int max_insns; @@ -1801,9 +1802,9 @@ gen_intermediate_code_internal(CPUState max_insns = CF_COUNT_MASK; gen_icount_start(); while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { - if (env->nb_breakpoints > 0) { - for (i = 0; i < env->nb_breakpoints; i++) { - if (ctx.pc == env->breakpoints[i]) { + if (unlikely(env->breakpoints)) { + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (ctx.pc == bp->pc) { /* We have hit a breakpoint - make sure PC is up-to-date */ tcg_gen_movi_i32(cpu_pc, ctx.pc); tcg_gen_helper_0_0(helper_debug); Index: b/target-sparc/translate.c =================================================================== --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -4681,6 +4681,7 @@ static inline void gen_intermediate_code target_ulong pc_start, last_pc; uint16_t *gen_opc_end; DisasContext dc1, *dc = &dc1; + CPUBreakpoint *bp; int j, lj = -1; int num_insns; int max_insns; @@ -4718,9 +4719,9 @@ static inline void gen_intermediate_code max_insns = CF_COUNT_MASK; gen_icount_start(); do { - if (env->nb_breakpoints > 0) { - for(j = 0; j < env->nb_breakpoints; j++) { - if (env->breakpoints[j] == dc->pc) { + if (unlikely(env->breakpoints)) { + for (bp = env->breakpoints; bp != NULL; bp = bp->next) { + if (bp->pc == dc->pc) { if (dc->pc != pc_start) save_state(dc, cpu_cond); tcg_gen_helper_0_0(helper_debug);