Commit a1d1bb3101db1fea4ff47b74de15208971f8d64e

Authored by aliguori
1 parent d6fc1b39

Refactor and enhance break/watchpoint API (Jan Kiszka)

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.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5738 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-all.h
... ... @@ -761,12 +761,23 @@ extern int use_icount;
761 761 void cpu_interrupt(CPUState *s, int mask);
762 762 void cpu_reset_interrupt(CPUState *env, int mask);
763 763  
764   -int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type);
765   -int cpu_watchpoint_remove(CPUState *env, target_ulong addr);
766   -void cpu_watchpoint_remove_all(CPUState *env);
767   -int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
768   -int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
769   -void cpu_breakpoint_remove_all(CPUState *env);
  764 +/* Breakpoint/watchpoint flags */
  765 +#define BP_MEM_READ 0x01
  766 +#define BP_MEM_WRITE 0x02
  767 +#define BP_MEM_ACCESS (BP_MEM_READ | BP_MEM_WRITE)
  768 +#define BP_GDB 0x10
  769 +
  770 +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
  771 + CPUBreakpoint **breakpoint);
  772 +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags);
  773 +void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint);
  774 +void cpu_breakpoint_remove_all(CPUState *env, int mask);
  775 +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
  776 + int flags, CPUWatchpoint **watchpoint);
  777 +int cpu_watchpoint_remove(CPUState *env, target_ulong addr,
  778 + target_ulong len, int flags);
  779 +void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint);
  780 +void cpu_watchpoint_remove_all(CPUState *env, int mask);
770 781  
771 782 #define SSTEP_ENABLE 0x1 /* Enable simulated HW single stepping */
772 783 #define SSTEP_NOIRQ 0x2 /* Do not use IRQ while single stepping */
... ...
cpu-defs.h
... ... @@ -82,8 +82,6 @@ typedef uint64_t target_phys_addr_t;
82 82 #define EXCP_HLT 0x10001 /* hlt instruction reached */
83 83 #define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
84 84 #define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
85   -#define MAX_BREAKPOINTS 32
86   -#define MAX_WATCHPOINTS 32
87 85  
88 86 #define TB_JMP_CACHE_BITS 12
89 87 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
... ... @@ -145,6 +143,19 @@ typedef struct icount_decr_u16 {
145 143 struct kvm_run;
146 144 struct KVMState;
147 145  
  146 +typedef struct CPUBreakpoint {
  147 + target_ulong pc;
  148 + int flags; /* BP_* */
  149 + struct CPUBreakpoint *prev, *next;
  150 +} CPUBreakpoint;
  151 +
  152 +typedef struct CPUWatchpoint {
  153 + target_ulong vaddr;
  154 + target_ulong len_mask;
  155 + int flags; /* BP_* */
  156 + struct CPUWatchpoint *prev, *next;
  157 +} CPUWatchpoint;
  158 +
148 159 #define CPU_TEMP_BUF_NLONGS 128
149 160 #define CPU_COMMON \
150 161 struct TranslationBlock *current_tb; /* currently executing TB */ \
... ... @@ -177,16 +188,11 @@ struct KVMState;
177 188 \
178 189 /* from this point: preserved by CPU reset */ \
179 190 /* ice debug support */ \
180   - target_ulong breakpoints[MAX_BREAKPOINTS]; \
181   - int nb_breakpoints; \
  191 + CPUBreakpoint *breakpoints; \
182 192 int singlestep_enabled; \
183 193 \
184   - struct { \
185   - target_ulong vaddr; \
186   - int type; /* PAGE_READ/PAGE_WRITE */ \
187   - } watchpoint[MAX_WATCHPOINTS]; \
188   - int nb_watchpoints; \
189   - int watchpoint_hit; \
  194 + CPUWatchpoint *watchpoints; \
  195 + CPUWatchpoint *watchpoint_hit; \
190 196 \
191 197 struct GDBRegisterState *gdb_regs; \
192 198 \
... ...
... ... @@ -537,7 +537,6 @@ void cpu_exec_init(CPUState *env)
537 537 cpu_index++;
538 538 }
539 539 env->cpu_index = cpu_index;
540   - env->nb_watchpoints = 0;
541 540 *penv = env;
542 541 #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
543 542 register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
... ... @@ -1299,107 +1298,150 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc)
1299 1298 #endif
1300 1299  
1301 1300 /* Add a watchpoint. */
1302   -int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type)
  1301 +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
  1302 + int flags, CPUWatchpoint **watchpoint)
1303 1303 {
1304   - int i;
  1304 + CPUWatchpoint *wp;
1305 1305  
1306   - for (i = 0; i < env->nb_watchpoints; i++) {
1307   - if (addr == env->watchpoint[i].vaddr)
1308   - return 0;
1309   - }
1310   - if (env->nb_watchpoints >= MAX_WATCHPOINTS)
1311   - return -1;
  1306 + wp = qemu_malloc(sizeof(*wp));
  1307 + if (!wp)
  1308 + return -ENOBUFS;
  1309 +
  1310 + wp->vaddr = addr;
  1311 + wp->len_mask = 0;
  1312 + wp->flags = flags;
  1313 +
  1314 + wp->next = env->watchpoints;
  1315 + wp->prev = NULL;
  1316 + if (wp->next)
  1317 + wp->next->prev = wp;
  1318 + env->watchpoints = wp;
1312 1319  
1313   - i = env->nb_watchpoints++;
1314   - env->watchpoint[i].vaddr = addr;
1315   - env->watchpoint[i].type = type;
1316 1320 tlb_flush_page(env, addr);
1317 1321 /* FIXME: This flush is needed because of the hack to make memory ops
1318 1322 terminate the TB. It can be removed once the proper IO trap and
1319 1323 re-execute bits are in. */
1320 1324 tb_flush(env);
1321   - return i;
  1325 +
  1326 + if (watchpoint)
  1327 + *watchpoint = wp;
  1328 + return 0;
1322 1329 }
1323 1330  
1324   -/* Remove a watchpoint. */
1325   -int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
  1331 +/* Remove a specific watchpoint. */
  1332 +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
  1333 + int flags)
1326 1334 {
1327   - int i;
  1335 + CPUWatchpoint *wp;
1328 1336  
1329   - for (i = 0; i < env->nb_watchpoints; i++) {
1330   - if (addr == env->watchpoint[i].vaddr) {
1331   - env->nb_watchpoints--;
1332   - env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
1333   - tlb_flush_page(env, addr);
  1337 + for (wp = env->watchpoints; wp != NULL; wp = wp->next) {
  1338 + if (addr == wp->vaddr && flags == wp->flags) {
  1339 + cpu_watchpoint_remove_by_ref(env, wp);
1334 1340 return 0;
1335 1341 }
1336 1342 }
1337   - return -1;
  1343 + return -ENOENT;
1338 1344 }
1339 1345  
1340   -/* Remove all watchpoints. */
1341   -void cpu_watchpoint_remove_all(CPUState *env) {
1342   - int i;
  1346 +/* Remove a specific watchpoint by reference. */
  1347 +void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
  1348 +{
  1349 + if (watchpoint->next)
  1350 + watchpoint->next->prev = watchpoint->prev;
  1351 + if (watchpoint->prev)
  1352 + watchpoint->prev->next = watchpoint->next;
  1353 + else
  1354 + env->watchpoints = watchpoint->next;
1343 1355  
1344   - for (i = 0; i < env->nb_watchpoints; i++) {
1345   - tlb_flush_page(env, env->watchpoint[i].vaddr);
1346   - }
1347   - env->nb_watchpoints = 0;
  1356 + tlb_flush_page(env, watchpoint->vaddr);
  1357 +
  1358 + qemu_free(watchpoint);
  1359 +}
  1360 +
  1361 +/* Remove all matching watchpoints. */
  1362 +void cpu_watchpoint_remove_all(CPUState *env, int mask)
  1363 +{
  1364 + CPUWatchpoint *wp;
  1365 +
  1366 + for (wp = env->watchpoints; wp != NULL; wp = wp->next)
  1367 + if (wp->flags & mask)
  1368 + cpu_watchpoint_remove_by_ref(env, wp);
1348 1369 }
1349 1370  
1350   -/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
1351   - breakpoint is reached */
1352   -int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
  1371 +/* Add a breakpoint. */
  1372 +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
  1373 + CPUBreakpoint **breakpoint)
1353 1374 {
1354 1375 #if defined(TARGET_HAS_ICE)
1355   - int i;
  1376 + CPUBreakpoint *bp;
1356 1377  
1357   - for(i = 0; i < env->nb_breakpoints; i++) {
1358   - if (env->breakpoints[i] == pc)
1359   - return 0;
1360   - }
  1378 + bp = qemu_malloc(sizeof(*bp));
  1379 + if (!bp)
  1380 + return -ENOBUFS;
1361 1381  
1362   - if (env->nb_breakpoints >= MAX_BREAKPOINTS)
1363   - return -1;
1364   - env->breakpoints[env->nb_breakpoints++] = pc;
  1382 + bp->pc = pc;
  1383 + bp->flags = flags;
  1384 +
  1385 + bp->next = env->breakpoints;
  1386 + bp->prev = NULL;
  1387 + if (bp->next)
  1388 + bp->next->prev = bp;
  1389 + env->breakpoints = bp;
1365 1390  
1366 1391 breakpoint_invalidate(env, pc);
  1392 +
  1393 + if (breakpoint)
  1394 + *breakpoint = bp;
1367 1395 return 0;
1368 1396 #else
1369   - return -1;
  1397 + return -ENOSYS;
1370 1398 #endif
1371 1399 }
1372 1400  
1373   -/* remove all breakpoints */
1374   -void cpu_breakpoint_remove_all(CPUState *env) {
  1401 +/* Remove a specific breakpoint. */
  1402 +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
  1403 +{
1375 1404 #if defined(TARGET_HAS_ICE)
1376   - int i;
1377   - for(i = 0; i < env->nb_breakpoints; i++) {
1378   - breakpoint_invalidate(env, env->breakpoints[i]);
  1405 + CPUBreakpoint *bp;
  1406 +
  1407 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  1408 + if (bp->pc == pc && bp->flags == flags) {
  1409 + cpu_breakpoint_remove_by_ref(env, bp);
  1410 + return 0;
  1411 + }
1379 1412 }
1380   - env->nb_breakpoints = 0;
  1413 + return -ENOENT;
  1414 +#else
  1415 + return -ENOSYS;
1381 1416 #endif
1382 1417 }
1383 1418  
1384   -/* remove a breakpoint */
1385   -int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
  1419 +/* Remove a specific breakpoint by reference. */
  1420 +void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
1386 1421 {
1387 1422 #if defined(TARGET_HAS_ICE)
1388   - int i;
1389   - for(i = 0; i < env->nb_breakpoints; i++) {
1390   - if (env->breakpoints[i] == pc)
1391   - goto found;
1392   - }
1393   - return -1;
1394   - found:
1395   - env->nb_breakpoints--;
1396   - if (i < env->nb_breakpoints)
1397   - env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
  1423 + if (breakpoint->next)
  1424 + breakpoint->next->prev = breakpoint->prev;
  1425 + if (breakpoint->prev)
  1426 + breakpoint->prev->next = breakpoint->next;
  1427 + else
  1428 + env->breakpoints = breakpoint->next;
1398 1429  
1399   - breakpoint_invalidate(env, pc);
1400   - return 0;
1401   -#else
1402   - return -1;
  1430 + breakpoint_invalidate(env, breakpoint->pc);
  1431 +
  1432 + qemu_free(breakpoint);
  1433 +#endif
  1434 +}
  1435 +
  1436 +/* Remove all matching breakpoints. */
  1437 +void cpu_breakpoint_remove_all(CPUState *env, int mask)
  1438 +{
  1439 +#if defined(TARGET_HAS_ICE)
  1440 + CPUBreakpoint *bp;
  1441 +
  1442 + for (bp = env->breakpoints; bp != NULL; bp = bp->next)
  1443 + if (bp->flags & mask)
  1444 + cpu_breakpoint_remove_by_ref(env, bp);
1403 1445 #endif
1404 1446 }
1405 1447  
... ... @@ -1881,7 +1923,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1881 1923 target_phys_addr_t addend;
1882 1924 int ret;
1883 1925 CPUTLBEntry *te;
1884   - int i;
  1926 + CPUWatchpoint *wp;
1885 1927 target_phys_addr_t iotlb;
1886 1928  
1887 1929 p = phys_page_find(paddr >> TARGET_PAGE_BITS);
... ... @@ -1922,8 +1964,8 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
1922 1964 code_address = address;
1923 1965 /* Make accesses to pages with watchpoints go via the
1924 1966 watchpoint trap routines. */
1925   - for (i = 0; i < env->nb_watchpoints; i++) {
1926   - if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
  1967 + for (wp = env->watchpoints; wp != NULL; wp = wp->next) {
  1968 + if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
1927 1969 iotlb = io_mem_watch + paddr;
1928 1970 /* TODO: The memory case can be optimized by not trapping
1929 1971 reads of pages with a write breakpoint. */
... ... @@ -2456,13 +2498,12 @@ static void check_watchpoint(int offset, int flags)
2456 2498 {
2457 2499 CPUState *env = cpu_single_env;
2458 2500 target_ulong vaddr;
2459   - int i;
  2501 + CPUWatchpoint *wp;
2460 2502  
2461 2503 vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
2462   - for (i = 0; i < env->nb_watchpoints; i++) {
2463   - if (vaddr == env->watchpoint[i].vaddr
2464   - && (env->watchpoint[i].type & flags)) {
2465   - env->watchpoint_hit = i + 1;
  2504 + for (wp = env->watchpoints; wp != NULL; wp = wp->next) {
  2505 + if (vaddr == wp->vaddr && (wp->flags & flags)) {
  2506 + env->watchpoint_hit = wp;
2466 2507 cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
2467 2508 break;
2468 2509 }
... ... @@ -2474,40 +2515,40 @@ static void check_watchpoint(int offset, int flags)
2474 2515 phys routines. */
2475 2516 static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
2476 2517 {
2477   - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
  2518 + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_READ);
2478 2519 return ldub_phys(addr);
2479 2520 }
2480 2521  
2481 2522 static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
2482 2523 {
2483   - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
  2524 + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_READ);
2484 2525 return lduw_phys(addr);
2485 2526 }
2486 2527  
2487 2528 static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
2488 2529 {
2489   - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
  2530 + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_READ);
2490 2531 return ldl_phys(addr);
2491 2532 }
2492 2533  
2493 2534 static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
2494 2535 uint32_t val)
2495 2536 {
2496   - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
  2537 + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_WRITE);
2497 2538 stb_phys(addr, val);
2498 2539 }
2499 2540  
2500 2541 static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
2501 2542 uint32_t val)
2502 2543 {
2503   - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
  2544 + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_WRITE);
2504 2545 stw_phys(addr, val);
2505 2546 }
2506 2547  
2507 2548 static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
2508 2549 uint32_t val)
2509 2550 {
2510   - check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
  2551 + check_watchpoint(addr & ~TARGET_PAGE_MASK, BP_MEM_WRITE);
2511 2552 stl_phys(addr, val);
2512 2553 }
2513 2554  
... ...
gdbstub.c
... ... @@ -1145,10 +1145,70 @@ void gdb_register_coprocessor(CPUState * env,
1145 1145 }
1146 1146 }
1147 1147  
  1148 +/* GDB breakpoint/watchpoint types */
  1149 +#define GDB_BREAKPOINT_SW 0
  1150 +#define GDB_BREAKPOINT_HW 1
  1151 +#define GDB_WATCHPOINT_WRITE 2
  1152 +#define GDB_WATCHPOINT_READ 3
  1153 +#define GDB_WATCHPOINT_ACCESS 4
  1154 +
  1155 +#ifndef CONFIG_USER_ONLY
  1156 +static const int xlat_gdb_type[] = {
  1157 + [GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE,
  1158 + [GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ,
  1159 + [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
  1160 +};
  1161 +#endif
  1162 +
  1163 +static int gdb_breakpoint_insert(CPUState *env, target_ulong addr,
  1164 + target_ulong len, int type)
  1165 +{
  1166 + switch (type) {
  1167 + case GDB_BREAKPOINT_SW:
  1168 + case GDB_BREAKPOINT_HW:
  1169 + return cpu_breakpoint_insert(env, addr, BP_GDB, NULL);
  1170 +#ifndef CONFIG_USER_ONLY
  1171 + case GDB_WATCHPOINT_WRITE:
  1172 + case GDB_WATCHPOINT_READ:
  1173 + case GDB_WATCHPOINT_ACCESS:
  1174 + return cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type],
  1175 + NULL);
  1176 +#endif
  1177 + default:
  1178 + return -ENOSYS;
  1179 + }
  1180 +}
  1181 +
  1182 +static int gdb_breakpoint_remove(CPUState *env, target_ulong addr,
  1183 + target_ulong len, int type)
  1184 +{
  1185 + switch (type) {
  1186 + case GDB_BREAKPOINT_SW:
  1187 + case GDB_BREAKPOINT_HW:
  1188 + return cpu_breakpoint_remove(env, addr, BP_GDB);
  1189 +#ifndef CONFIG_USER_ONLY
  1190 + case GDB_WATCHPOINT_WRITE:
  1191 + case GDB_WATCHPOINT_READ:
  1192 + case GDB_WATCHPOINT_ACCESS:
  1193 + return cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]);
  1194 +#endif
  1195 + default:
  1196 + return -ENOSYS;
  1197 + }
  1198 +}
  1199 +
  1200 +static void gdb_breakpoint_remove_all(CPUState *env)
  1201 +{
  1202 + cpu_breakpoint_remove_all(env, BP_GDB);
  1203 +#ifndef CONFIG_USER_ONLY
  1204 + cpu_watchpoint_remove_all(env, BP_GDB);
  1205 +#endif
  1206 +}
  1207 +
1148 1208 static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
1149 1209 {
1150 1210 const char *p;
1151   - int ch, reg_size, type;
  1211 + int ch, reg_size, type, res;
1152 1212 char buf[MAX_PACKET_LENGTH];
1153 1213 uint8_t mem_buf[MAX_PACKET_LENGTH];
1154 1214 uint8_t *registers;
... ... @@ -1168,8 +1228,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
1168 1228 * because gdb is doing and initial connect and the state
1169 1229 * should be cleaned up.
1170 1230 */
1171   - cpu_breakpoint_remove_all(env);
1172   - cpu_watchpoint_remove_all(env);
  1231 + gdb_breakpoint_remove_all(env);
1173 1232 break;
1174 1233 case 'c':
1175 1234 if (*p != '\0') {
... ... @@ -1203,8 +1262,7 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
1203 1262 exit(0);
1204 1263 case 'D':
1205 1264 /* Detach packet */
1206   - cpu_breakpoint_remove_all(env);
1207   - cpu_watchpoint_remove_all(env);
  1265 + gdb_breakpoint_remove_all(env);
1208 1266 gdb_continue(s);
1209 1267 put_packet(s, "OK");
1210 1268 break;
... ... @@ -1327,44 +1385,6 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
1327 1385 put_packet(s, "OK");
1328 1386 break;
1329 1387 case 'Z':
1330   - type = strtoul(p, (char **)&p, 16);
1331   - if (*p == ',')
1332   - p++;
1333   - addr = strtoull(p, (char **)&p, 16);
1334   - if (*p == ',')
1335   - p++;
1336   - len = strtoull(p, (char **)&p, 16);
1337   - switch (type) {
1338   - case 0:
1339   - case 1:
1340   - if (cpu_breakpoint_insert(env, addr) < 0)
1341   - goto breakpoint_error;
1342   - put_packet(s, "OK");
1343   - break;
1344   -#ifndef CONFIG_USER_ONLY
1345   - case 2:
1346   - type = PAGE_WRITE;
1347   - goto insert_watchpoint;
1348   - case 3:
1349   - type = PAGE_READ;
1350   - goto insert_watchpoint;
1351   - case 4:
1352   - type = PAGE_READ | PAGE_WRITE;
1353   - insert_watchpoint:
1354   - if (cpu_watchpoint_insert(env, addr, type) < 0)
1355   - goto breakpoint_error;
1356   - put_packet(s, "OK");
1357   - break;
1358   -#endif
1359   - default:
1360   - put_packet(s, "");
1361   - break;
1362   - }
1363   - break;
1364   - breakpoint_error:
1365   - put_packet(s, "E22");
1366   - break;
1367   -
1368 1388 case 'z':
1369 1389 type = strtoul(p, (char **)&p, 16);
1370 1390 if (*p == ',')
... ... @@ -1373,17 +1393,16 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
1373 1393 if (*p == ',')
1374 1394 p++;
1375 1395 len = strtoull(p, (char **)&p, 16);
1376   - if (type == 0 || type == 1) {
1377   - cpu_breakpoint_remove(env, addr);
1378   - put_packet(s, "OK");
1379   -#ifndef CONFIG_USER_ONLY
1380   - } else if (type >= 2 || type <= 4) {
1381   - cpu_watchpoint_remove(env, addr);
1382   - put_packet(s, "OK");
1383   -#endif
1384   - } else {
  1396 + if (ch == 'Z')
  1397 + res = gdb_breakpoint_insert(env, addr, len, type);
  1398 + else
  1399 + res = gdb_breakpoint_remove(env, addr, len, type);
  1400 + if (res >= 0)
  1401 + put_packet(s, "OK");
  1402 + else if (res == -ENOSYS)
1385 1403 put_packet(s, "");
1386   - }
  1404 + else
  1405 + put_packet(s, "E22");
1387 1406 break;
1388 1407 case 'q':
1389 1408 case 'Q':
... ... @@ -1504,12 +1523,11 @@ static void gdb_vm_stopped(void *opaque, int reason)
1504 1523  
1505 1524 if (reason == EXCP_DEBUG) {
1506 1525 if (s->env->watchpoint_hit) {
1507   - switch (s->env->watchpoint[s->env->watchpoint_hit - 1].type &
1508   - (PAGE_READ | PAGE_WRITE)) {
1509   - case PAGE_READ:
  1526 + switch (s->env->watchpoint_hit->flags & BP_MEM_ACCESS) {
  1527 + case BP_MEM_READ:
1510 1528 type = "r";
1511 1529 break;
1512   - case PAGE_READ | PAGE_WRITE:
  1530 + case BP_MEM_ACCESS:
1513 1531 type = "a";
1514 1532 break;
1515 1533 default:
... ... @@ -1517,10 +1535,9 @@ static void gdb_vm_stopped(void *opaque, int reason)
1517 1535 break;
1518 1536 }
1519 1537 snprintf(buf, sizeof(buf), "T%02x%swatch:" TARGET_FMT_lx ";",
1520   - SIGTRAP, type,
1521   - s->env->watchpoint[s->env->watchpoint_hit - 1].vaddr);
  1538 + SIGTRAP, type, s->env->watchpoint_hit->vaddr);
1522 1539 put_packet(s, buf);
1523   - s->env->watchpoint_hit = 0;
  1540 + s->env->watchpoint_hit = NULL;
1524 1541 return;
1525 1542 }
1526 1543 tb_flush(s->env);
... ...
target-alpha/translate.c
... ... @@ -2340,6 +2340,7 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
2340 2340 target_ulong pc_start;
2341 2341 uint32_t insn;
2342 2342 uint16_t *gen_opc_end;
  2343 + CPUBreakpoint *bp;
2343 2344 int j, lj = -1;
2344 2345 int ret;
2345 2346 int num_insns;
... ... @@ -2362,9 +2363,9 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
2362 2363  
2363 2364 gen_icount_start();
2364 2365 for (ret = 0; ret == 0;) {
2365   - if (env->nb_breakpoints > 0) {
2366   - for(j = 0; j < env->nb_breakpoints; j++) {
2367   - if (env->breakpoints[j] == ctx.pc) {
  2366 + if (unlikely(env->breakpoints)) {
  2367 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  2368 + if (bp->pc == ctx.pc) {
2368 2369 gen_excp(&ctx, EXCP_DEBUG, 0);
2369 2370 break;
2370 2371 }
... ...
target-arm/translate.c
... ... @@ -8600,6 +8600,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
8600 8600 int search_pc)
8601 8601 {
8602 8602 DisasContext dc1, *dc = &dc1;
  8603 + CPUBreakpoint *bp;
8603 8604 uint16_t *gen_opc_end;
8604 8605 int j, lj;
8605 8606 target_ulong pc_start;
... ... @@ -8676,9 +8677,9 @@ static inline void gen_intermediate_code_internal(CPUState *env,
8676 8677 }
8677 8678 #endif
8678 8679  
8679   - if (env->nb_breakpoints > 0) {
8680   - for(j = 0; j < env->nb_breakpoints; j++) {
8681   - if (env->breakpoints[j] == dc->pc) {
  8680 + if (unlikely(env->breakpoints)) {
  8681 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  8682 + if (bp->pc == dc->pc) {
8682 8683 gen_set_condexec(dc);
8683 8684 gen_set_pc_im(dc->pc);
8684 8685 gen_exception(EXCP_DEBUG);
... ... @@ -8731,7 +8732,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
8731 8732 /* Terminate the TB on memory ops if watchpoints are present. */
8732 8733 /* FIXME: This should be replacd by the deterministic execution
8733 8734 * IRQ raising bits. */
8734   - if (dc->is_mem && env->nb_watchpoints)
  8735 + if (dc->is_mem && env->watchpoints)
8735 8736 break;
8736 8737  
8737 8738 /* Translation stops when a conditional branch is enoutered.
... ...
target-cris/translate.c
... ... @@ -3187,10 +3187,11 @@ cris_decoder(DisasContext *dc)
3187 3187  
3188 3188 static void check_breakpoint(CPUState *env, DisasContext *dc)
3189 3189 {
3190   - int j;
3191   - if (env->nb_breakpoints > 0) {
3192   - for(j = 0; j < env->nb_breakpoints; j++) {
3193   - if (env->breakpoints[j] == dc->pc) {
  3190 + CPUBreakpoint *bp;
  3191 +
  3192 + if (unlikely(env->breakpoints)) {
  3193 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  3194 + if (bp->pc == dc->pc) {
3194 3195 cris_evaluate_flags (dc);
3195 3196 tcg_gen_movi_tl(env_pc, dc->pc);
3196 3197 t_gen_raise_exception(EXCP_DEBUG);
... ...
target-i386/translate.c
... ... @@ -7522,6 +7522,7 @@ static inline void gen_intermediate_code_internal(CPUState *env,
7522 7522 DisasContext dc1, *dc = &dc1;
7523 7523 target_ulong pc_ptr;
7524 7524 uint16_t *gen_opc_end;
  7525 + CPUBreakpoint *bp;
7525 7526 int j, lj, cflags;
7526 7527 uint64_t flags;
7527 7528 target_ulong pc_start;
... ... @@ -7605,9 +7606,9 @@ static inline void gen_intermediate_code_internal(CPUState *env,
7605 7606  
7606 7607 gen_icount_start();
7607 7608 for(;;) {
7608   - if (env->nb_breakpoints > 0) {
7609   - for(j = 0; j < env->nb_breakpoints; j++) {
7610   - if (env->breakpoints[j] == pc_ptr) {
  7609 + if (unlikely(env->breakpoints)) {
  7610 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  7611 + if (bp->pc == pc_ptr) {
7611 7612 gen_debug(dc, pc_ptr - dc->cs_base);
7612 7613 break;
7613 7614 }
... ...
target-m68k/translate.c
... ... @@ -2965,6 +2965,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
2965 2965 {
2966 2966 DisasContext dc1, *dc = &dc1;
2967 2967 uint16_t *gen_opc_end;
  2968 + CPUBreakpoint *bp;
2968 2969 int j, lj;
2969 2970 target_ulong pc_start;
2970 2971 int pc_offset;
... ... @@ -2998,9 +2999,9 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
2998 2999 do {
2999 3000 pc_offset = dc->pc - pc_start;
3000 3001 gen_throws_exception = NULL;
3001   - if (env->nb_breakpoints > 0) {
3002   - for(j = 0; j < env->nb_breakpoints; j++) {
3003   - if (env->breakpoints[j] == dc->pc) {
  3002 + if (unlikely(env->breakpoints)) {
  3003 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  3004 + if (bp->pc == dc->pc) {
3004 3005 gen_exception(dc, dc->pc, EXCP_DEBUG);
3005 3006 dc->is_jmp = DISAS_JUMP;
3006 3007 break;
... ... @@ -3030,7 +3031,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
3030 3031 /* Terminate the TB on memory ops if watchpoints are present. */
3031 3032 /* FIXME: This should be replaced by the deterministic execution
3032 3033 * IRQ raising bits. */
3033   - if (dc->is_mem && env->nb_watchpoints)
  3034 + if (dc->is_mem && env->watchpoints)
3034 3035 break;
3035 3036 } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
3036 3037 !env->singlestep_enabled &&
... ...
target-mips/translate.c
... ... @@ -8246,6 +8246,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
8246 8246 DisasContext ctx;
8247 8247 target_ulong pc_start;
8248 8248 uint16_t *gen_opc_end;
  8249 + CPUBreakpoint *bp;
8249 8250 int j, lj = -1;
8250 8251 int num_insns;
8251 8252 int max_insns;
... ... @@ -8285,9 +8286,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
8285 8286 #endif
8286 8287 gen_icount_start();
8287 8288 while (ctx.bstate == BS_NONE) {
8288   - if (env->nb_breakpoints > 0) {
8289   - for(j = 0; j < env->nb_breakpoints; j++) {
8290   - if (env->breakpoints[j] == ctx.pc) {
  8289 + if (unlikely(env->breakpoints)) {
  8290 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  8291 + if (bp->pc == ctx.pc) {
8291 8292 save_cpu_state(&ctx, 1);
8292 8293 ctx.bstate = BS_BRANCH;
8293 8294 gen_helper_0i(raise_exception, EXCP_DEBUG);
... ...
target-ppc/translate.c
... ... @@ -7170,6 +7170,7 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
7170 7170 target_ulong pc_start;
7171 7171 uint16_t *gen_opc_end;
7172 7172 int supervisor, little_endian;
  7173 + CPUBreakpoint *bp;
7173 7174 int j, lj = -1;
7174 7175 int num_insns;
7175 7176 int max_insns;
... ... @@ -7224,9 +7225,9 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
7224 7225 gen_icount_start();
7225 7226 /* Set env in case of segfault during code fetch */
7226 7227 while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
7227   - if (unlikely(env->nb_breakpoints > 0)) {
7228   - for (j = 0; j < env->nb_breakpoints; j++) {
7229   - if (env->breakpoints[j] == ctx.nip) {
  7228 + if (unlikely(env->breakpoints)) {
  7229 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  7230 + if (bp->pc == ctx.nip) {
7230 7231 gen_update_nip(&ctx, ctx.nip);
7231 7232 gen_op_debug();
7232 7233 break;
... ...
target-sh4/translate.c
... ... @@ -1803,6 +1803,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
1803 1803 DisasContext ctx;
1804 1804 target_ulong pc_start;
1805 1805 static uint16_t *gen_opc_end;
  1806 + CPUBreakpoint *bp;
1806 1807 int i, ii;
1807 1808 int num_insns;
1808 1809 int max_insns;
... ... @@ -1836,9 +1837,9 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
1836 1837 max_insns = CF_COUNT_MASK;
1837 1838 gen_icount_start();
1838 1839 while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
1839   - if (env->nb_breakpoints > 0) {
1840   - for (i = 0; i < env->nb_breakpoints; i++) {
1841   - if (ctx.pc == env->breakpoints[i]) {
  1840 + if (unlikely(env->breakpoints)) {
  1841 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  1842 + if (ctx.pc == bp->pc) {
1842 1843 /* We have hit a breakpoint - make sure PC is up-to-date */
1843 1844 tcg_gen_movi_i32(cpu_pc, ctx.pc);
1844 1845 gen_helper_debug();
... ...
target-sparc/translate.c
... ... @@ -4778,6 +4778,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
4778 4778 target_ulong pc_start, last_pc;
4779 4779 uint16_t *gen_opc_end;
4780 4780 DisasContext dc1, *dc = &dc1;
  4781 + CPUBreakpoint *bp;
4781 4782 int j, lj = -1;
4782 4783 int num_insns;
4783 4784 int max_insns;
... ... @@ -4815,9 +4816,9 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
4815 4816 max_insns = CF_COUNT_MASK;
4816 4817 gen_icount_start();
4817 4818 do {
4818   - if (env->nb_breakpoints > 0) {
4819   - for(j = 0; j < env->nb_breakpoints; j++) {
4820   - if (env->breakpoints[j] == dc->pc) {
  4819 + if (unlikely(env->breakpoints)) {
  4820 + for (bp = env->breakpoints; bp != NULL; bp = bp->next) {
  4821 + if (bp->pc == dc->pc) {
4821 4822 if (dc->pc != pc_start)
4822 4823 save_state(dc, cpu_cond);
4823 4824 gen_helper_debug();
... ...