diff --git a/cpu-all.h b/cpu-all.h
index cdd79bc73ad6219c33fcd4e25abbc8379907c08d..1f4f1e76e82c09cf870fff948851681aef5bce23 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -761,12 +761,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 */
diff --git a/cpu-defs.h b/cpu-defs.h
index 46d4487811a85b2da9b2b8a4e80ae604e7f8ab49..069d312e1e7c3ddc683fa423377c6f06ed99bf0e 100644
--- 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)
@@ -145,6 +143,19 @@ typedef struct icount_decr_u16 {
 struct kvm_run;
 struct KVMState;
 
+typedef struct CPUBreakpoint {
+    target_ulong pc;
+    int flags; /* BP_* */
+    struct CPUBreakpoint *prev, *next;
+} CPUBreakpoint;
+
+typedef struct CPUWatchpoint {
+    target_ulong vaddr;
+    target_ulong len_mask;
+    int flags; /* BP_* */
+    struct CPUWatchpoint *prev, *next;
+} CPUWatchpoint;
+
 #define CPU_TEMP_BUF_NLONGS 128
 #define CPU_COMMON                                                      \
     struct TranslationBlock *current_tb; /* currently executing TB  */  \
@@ -177,16 +188,11 @@ struct KVMState;
                                                                         \
     /* 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;                                      \
                                                                         \
     struct GDBRegisterState *gdb_regs;                                  \
                                                                         \
diff --git a/exec.c b/exec.c
index 772b1c10be417b2e874fe5d9a75c8e555733ea11..4619e492fbaeb75493f314ac18b8ff7addbfa954 100644
--- a/exec.c
+++ b/exec.c
@@ -537,7 +537,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,
@@ -1299,107 +1298,150 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc)
 #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_mask = 0;
+    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;
+
+    if (watchpoint)
+        *watchpoint = wp;
+    return 0;
 }
 
-/* Remove a watchpoint.  */
-int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
+/* Remove a specific watchpoint.  */
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
+                          int flags)
 {
-    int i;
+    CPUWatchpoint *wp;
 
-    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);
+    for (wp = env->watchpoints; wp != NULL; wp = wp->next) {
+        if (addr == wp->vaddr && 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);
+}
+
+/* Remove all matching watchpoints.  */
+void cpu_watchpoint_remove_all(CPUState *env, int mask)
+{
+    CPUWatchpoint *wp;
+
+    for (wp = env->watchpoints; wp != NULL; wp = wp->next)
+        if (wp->flags & mask)
+            cpu_watchpoint_remove_by_ref(env, wp);
 }
 
-/* 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)
+/* Add a breakpoint.  */
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
+                          CPUBreakpoint **breakpoint)
 {
 #if defined(TARGET_HAS_ICE)
-    int i;
+    CPUBreakpoint *bp;
 
-    for(i = 0; i < env->nb_breakpoints; i++) {
-        if (env->breakpoints[i] == pc)
-            return 0;
-    }
+    bp = qemu_malloc(sizeof(*bp));
+    if (!bp)
+        return -ENOBUFS;
 
-    if (env->nb_breakpoints >= MAX_BREAKPOINTS)
-        return -1;
-    env->breakpoints[env->nb_breakpoints++] = pc;
+    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
 }
 
@@ -1881,7 +1923,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
     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);
@@ -1922,8 +1964,8 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
     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.  */
@@ -2456,13 +2498,12 @@ static void check_watchpoint(int offset, int flags)
 {
     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;
         }
@@ -2474,40 +2515,40 @@ static void check_watchpoint(int offset, int flags)
    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);
 }
 
diff --git a/gdbstub.c b/gdbstub.c
index aff8189725faa08daf303aab767e702a4a54d2bd..a0fc62d3d7ae9aa2eccdda4cf446b0e4ee36eeb4 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1145,10 +1145,70 @@ void gdb_register_coprocessor(CPUState * env,
     }
 }
 
+/* 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:
+    case GDB_BREAKPOINT_HW:
+        return cpu_breakpoint_insert(env, addr, BP_GDB, NULL);
+#ifndef CONFIG_USER_ONLY
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case 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:
+    case GDB_BREAKPOINT_HW:
+        return cpu_breakpoint_remove(env, addr, BP_GDB);
+#ifndef CONFIG_USER_ONLY
+    case GDB_WATCHPOINT_WRITE:
+    case GDB_WATCHPOINT_READ:
+    case 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[MAX_PACKET_LENGTH];
     uint8_t mem_buf[MAX_PACKET_LENGTH];
     uint8_t *registers;
@@ -1168,8 +1228,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
          * 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') {
@@ -1203,8 +1262,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
         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;
@@ -1327,44 +1385,6 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
         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 == ',')
@@ -1373,17 +1393,16 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
         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':
@@ -1504,12 +1523,11 @@ static void gdb_vm_stopped(void *opaque, int reason)
 
     if (reason == EXCP_DEBUG) {
         if (s->env->watchpoint_hit) {
-            switch (s->env->watchpoint[s->env->watchpoint_hit - 1].type &
-                    (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:
@@ -1517,10 +1535,9 @@ static void gdb_vm_stopped(void *opaque, int reason)
                 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);
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 8fc976650672ea4b189c348cb1b54d7ba2c4001c..3b90f62922325526c666499462e97f7adef65005 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -2340,6 +2340,7 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
     target_ulong pc_start;
     uint32_t insn;
     uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
     int j, lj = -1;
     int ret;
     int num_insns;
@@ -2362,9 +2363,9 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
 
     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;
                 }
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 9d52991b405fd046ee886246eb94f4bb8933fa2e..237c5f694163d4d0c397801a3fc963930dc8d26a 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -8600,6 +8600,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
                                                   int search_pc)
 {
     DisasContext dc1, *dc = &dc1;
+    CPUBreakpoint *bp;
     uint16_t *gen_opc_end;
     int j, lj;
     target_ulong pc_start;
@@ -8676,9 +8677,9 @@ static inline void gen_intermediate_code_internal(CPUState *env,
         }
 #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);
@@ -8731,7 +8732,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
         /* 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.
diff --git a/target-cris/translate.c b/target-cris/translate.c
index a10ccb6e7903f81e9700fd32389ad4cc14fda8f9..ac258a9deb667a4d302752a79993112eed2d6d3b 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -3187,10 +3187,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);
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 5006106a460d24e81a20697f70444bb6df00d2ed..0de238b575977a83111d775c9ba2fdaeec1410f5 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7522,6 +7522,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
     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;
@@ -7605,9 +7606,9 @@ static inline void gen_intermediate_code_internal(CPUState *env,
 
     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;
                 }
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 07f0640c0361a1b941381ea7596b34a0d1982803..49e2cb27df9f3ea2a51b770c4b1b86fba77d49b6 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2965,6 +2965,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
 {
     DisasContext dc1, *dc = &dc1;
     uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
     int j, lj;
     target_ulong pc_start;
     int pc_offset;
@@ -2998,9 +2999,9 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
     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;
@@ -3030,7 +3031,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
         /* 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 &&
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 590c2b683b4a8a62d60534d598dc91e33f32c629..cc7e71c5750a3ab50b642b27dd88d5e47d4429c7 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -8246,6 +8246,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     DisasContext ctx;
     target_ulong pc_start;
     uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
     int j, lj = -1;
     int num_insns;
     int max_insns;
@@ -8285,9 +8286,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
 #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;
                     gen_helper_0i(raise_exception, EXCP_DEBUG);
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index d92e04db3e4b444c6fff65d46a07b4a6a958400e..085c7a1533e29f92e9619d97c33ecc9c82cf4ad2 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -7170,6 +7170,7 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
     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;
@@ -7224,9 +7225,9 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
     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;
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index b05e8fc6f16ddf3e6c8f8c5b4d6744a4e8fb56a7..eb3366ccc8f068557194c58495c6255b04dc9f8b 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -1803,6 +1803,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
     DisasContext ctx;
     target_ulong pc_start;
     static uint16_t *gen_opc_end;
+    CPUBreakpoint *bp;
     int i, ii;
     int num_insns;
     int max_insns;
@@ -1836,9 +1837,9 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
         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);
 		    gen_helper_debug();
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 77fb72396d535d8c7e2e8d7e9b8ee6c47ffb868f..e94e3c536cd1a819f80082e1d5bf39934b546305 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -4778,6 +4778,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
     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;
@@ -4815,9 +4816,9 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
         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);
                     gen_helper_debug();