Revision a1d1bb31
b/cpu-all.h | ||
---|---|---|
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 */ |
b/cpu-defs.h | ||
---|---|---|
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 | 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 | 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 |
\ |
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 |
|
b/gdbstub.c | ||
---|---|---|
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 | 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 | 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 | 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 | 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 | 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 | 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); |
b/target-alpha/translate.c | ||
---|---|---|
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 | 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 |
} |
b/target-arm/translate.c | ||
---|---|---|
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 | 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 | 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. |
b/target-cris/translate.c | ||
---|---|---|
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); |
b/target-i386/translate.c | ||
---|---|---|
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 | 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 |
} |
b/target-m68k/translate.c | ||
---|---|---|
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 | 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 | 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 && |
b/target-mips/translate.c | ||
---|---|---|
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 | 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); |
b/target-ppc/translate.c | ||
---|---|---|
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 | 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; |
b/target-sh4/translate.c | ||
---|---|---|
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 | 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(); |
b/target-sparc/translate.c | ||
---|---|---|
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 | 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(); |
Also available in: Unified diff