Revision a1d1bb31 exec.c
b/exec.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 |
|
Also available in: Unified diff