Use sys-queue.h for break/watchpoint managment (Jan Kiszka)

This switches cpu_break/watchpoint_* to TAILQ wrappers, simplifying the
code and also fixing a use after release issue in
cpu_break/watchpoint_remove_all.

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@5799 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
aliguori 2008-11-25 22:13:57 +00:00
parent 31280d92d1
commit c0ce998e94
13 changed files with 49 additions and 84 deletions

View File

@ -28,6 +28,7 @@
#include <setjmp.h> #include <setjmp.h>
#include <inttypes.h> #include <inttypes.h>
#include "osdep.h" #include "osdep.h"
#include "sys-queue.h"
#ifndef TARGET_LONG_BITS #ifndef TARGET_LONG_BITS
#error TARGET_LONG_BITS must be defined before including this header #error TARGET_LONG_BITS must be defined before including this header
@ -146,14 +147,14 @@ struct KVMState;
typedef struct CPUBreakpoint { typedef struct CPUBreakpoint {
target_ulong pc; target_ulong pc;
int flags; /* BP_* */ int flags; /* BP_* */
struct CPUBreakpoint *prev, *next; TAILQ_ENTRY(CPUBreakpoint) entry;
} CPUBreakpoint; } CPUBreakpoint;
typedef struct CPUWatchpoint { typedef struct CPUWatchpoint {
target_ulong vaddr; target_ulong vaddr;
target_ulong len_mask; target_ulong len_mask;
int flags; /* BP_* */ int flags; /* BP_* */
struct CPUWatchpoint *prev, *next; TAILQ_ENTRY(CPUWatchpoint) entry;
} CPUWatchpoint; } CPUWatchpoint;
#define CPU_TEMP_BUF_NLONGS 128 #define CPU_TEMP_BUF_NLONGS 128
@ -188,10 +189,10 @@ typedef struct CPUWatchpoint {
\ \
/* from this point: preserved by CPU reset */ \ /* from this point: preserved by CPU reset */ \
/* ice debug support */ \ /* ice debug support */ \
CPUBreakpoint *breakpoints; \ TAILQ_HEAD(breakpoints_head, CPUBreakpoint) breakpoints; \
int singlestep_enabled; \ int singlestep_enabled; \
\ \
CPUWatchpoint *watchpoints; \ TAILQ_HEAD(watchpoints_head, CPUWatchpoint) watchpoints; \
CPUWatchpoint *watchpoint_hit; \ CPUWatchpoint *watchpoint_hit; \
\ \
struct GDBRegisterState *gdb_regs; \ struct GDBRegisterState *gdb_regs; \

View File

@ -198,7 +198,7 @@ static void cpu_handle_debug_exception(CPUState *env)
CPUWatchpoint *wp; CPUWatchpoint *wp;
if (!env->watchpoint_hit) if (!env->watchpoint_hit)
for (wp = env->watchpoints; wp != NULL; wp = wp->next) TAILQ_FOREACH(wp, &env->watchpoints, entry)
wp->flags &= ~BP_WATCHPOINT_HIT; wp->flags &= ~BP_WATCHPOINT_HIT;
if (debug_excp_handler) if (debug_excp_handler)

84
exec.c
View File

@ -537,6 +537,8 @@ void cpu_exec_init(CPUState *env)
cpu_index++; cpu_index++;
} }
env->cpu_index = cpu_index; env->cpu_index = cpu_index;
TAILQ_INIT(&env->breakpoints);
TAILQ_INIT(&env->watchpoints);
*penv = env; *penv = env;
#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY) #if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION, register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
@ -1302,7 +1304,7 @@ int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
int flags, CPUWatchpoint **watchpoint) int flags, CPUWatchpoint **watchpoint)
{ {
target_ulong len_mask = ~(len - 1); target_ulong len_mask = ~(len - 1);
CPUWatchpoint *wp, *prev_wp; CPUWatchpoint *wp;
/* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */ /* sanity checks: allow power-of-2 lengths, deny unaligned watchpoints */
if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) { if ((len != 1 && len != 2 && len != 4 && len != 8) || (addr & ~len_mask)) {
@ -1319,25 +1321,10 @@ int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len,
wp->flags = flags; wp->flags = flags;
/* keep all GDB-injected watchpoints in front */ /* keep all GDB-injected watchpoints in front */
if (!(flags & BP_GDB) && env->watchpoints) { if (flags & BP_GDB)
prev_wp = env->watchpoints; TAILQ_INSERT_HEAD(&env->watchpoints, wp, entry);
while (prev_wp->next != NULL && (prev_wp->next->flags & BP_GDB)) else
prev_wp = prev_wp->next; TAILQ_INSERT_TAIL(&env->watchpoints, wp, entry);
} else {
prev_wp = NULL;
}
/* Insert new watchpoint */
if (prev_wp) {
wp->next = prev_wp->next;
prev_wp->next = wp;
} else {
wp->next = env->watchpoints;
env->watchpoints = wp;
}
if (wp->next)
wp->next->prev = wp;
wp->prev = prev_wp;
tlb_flush_page(env, addr); tlb_flush_page(env, addr);
@ -1353,7 +1340,7 @@ int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
target_ulong len_mask = ~(len - 1); target_ulong len_mask = ~(len - 1);
CPUWatchpoint *wp; CPUWatchpoint *wp;
for (wp = env->watchpoints; wp != NULL; wp = wp->next) { TAILQ_FOREACH(wp, &env->watchpoints, entry) {
if (addr == wp->vaddr && len_mask == wp->len_mask if (addr == wp->vaddr && len_mask == wp->len_mask
&& flags == (wp->flags & ~BP_WATCHPOINT_HIT)) { && flags == (wp->flags & ~BP_WATCHPOINT_HIT)) {
cpu_watchpoint_remove_by_ref(env, wp); cpu_watchpoint_remove_by_ref(env, wp);
@ -1366,12 +1353,7 @@ int cpu_watchpoint_remove(CPUState *env, target_ulong addr, target_ulong len,
/* Remove a specific watchpoint by reference. */ /* Remove a specific watchpoint by reference. */
void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint) void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
{ {
if (watchpoint->next) TAILQ_REMOVE(&env->watchpoints, watchpoint, entry);
watchpoint->next->prev = watchpoint->prev;
if (watchpoint->prev)
watchpoint->prev->next = watchpoint->next;
else
env->watchpoints = watchpoint->next;
tlb_flush_page(env, watchpoint->vaddr); tlb_flush_page(env, watchpoint->vaddr);
@ -1381,11 +1363,12 @@ void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint)
/* Remove all matching watchpoints. */ /* Remove all matching watchpoints. */
void cpu_watchpoint_remove_all(CPUState *env, int mask) void cpu_watchpoint_remove_all(CPUState *env, int mask)
{ {
CPUWatchpoint *wp; CPUWatchpoint *wp, *next;
for (wp = env->watchpoints; wp != NULL; wp = wp->next) TAILQ_FOREACH_SAFE(wp, &env->watchpoints, entry, next) {
if (wp->flags & mask) if (wp->flags & mask)
cpu_watchpoint_remove_by_ref(env, wp); cpu_watchpoint_remove_by_ref(env, wp);
}
} }
/* Add a breakpoint. */ /* Add a breakpoint. */
@ -1393,7 +1376,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
CPUBreakpoint **breakpoint) CPUBreakpoint **breakpoint)
{ {
#if defined(TARGET_HAS_ICE) #if defined(TARGET_HAS_ICE)
CPUBreakpoint *bp, *prev_bp; CPUBreakpoint *bp;
bp = qemu_malloc(sizeof(*bp)); bp = qemu_malloc(sizeof(*bp));
if (!bp) if (!bp)
@ -1403,25 +1386,10 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags,
bp->flags = flags; bp->flags = flags;
/* keep all GDB-injected breakpoints in front */ /* keep all GDB-injected breakpoints in front */
if (!(flags & BP_GDB) && env->breakpoints) { if (flags & BP_GDB)
prev_bp = env->breakpoints; TAILQ_INSERT_HEAD(&env->breakpoints, bp, entry);
while (prev_bp->next != NULL && (prev_bp->next->flags & BP_GDB)) else
prev_bp = prev_bp->next; TAILQ_INSERT_TAIL(&env->breakpoints, bp, entry);
} else {
prev_bp = NULL;
}
/* Insert new breakpoint */
if (prev_bp) {
bp->next = prev_bp->next;
prev_bp->next = bp;
} else {
bp->next = env->breakpoints;
env->breakpoints = bp;
}
if (bp->next)
bp->next->prev = bp;
bp->prev = prev_bp;
breakpoint_invalidate(env, pc); breakpoint_invalidate(env, pc);
@ -1439,7 +1407,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags)
#if defined(TARGET_HAS_ICE) #if defined(TARGET_HAS_ICE)
CPUBreakpoint *bp; CPUBreakpoint *bp;
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == pc && bp->flags == flags) { if (bp->pc == pc && bp->flags == flags) {
cpu_breakpoint_remove_by_ref(env, bp); cpu_breakpoint_remove_by_ref(env, bp);
return 0; return 0;
@ -1455,12 +1423,7 @@ 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_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
{ {
#if defined(TARGET_HAS_ICE) #if defined(TARGET_HAS_ICE)
if (breakpoint->next) TAILQ_REMOVE(&env->breakpoints, breakpoint, entry);
breakpoint->next->prev = breakpoint->prev;
if (breakpoint->prev)
breakpoint->prev->next = breakpoint->next;
else
env->breakpoints = breakpoint->next;
breakpoint_invalidate(env, breakpoint->pc); breakpoint_invalidate(env, breakpoint->pc);
@ -1472,11 +1435,12 @@ void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint)
void cpu_breakpoint_remove_all(CPUState *env, int mask) void cpu_breakpoint_remove_all(CPUState *env, int mask)
{ {
#if defined(TARGET_HAS_ICE) #if defined(TARGET_HAS_ICE)
CPUBreakpoint *bp; CPUBreakpoint *bp, *next;
for (bp = env->breakpoints; bp != NULL; bp = bp->next) TAILQ_FOREACH_SAFE(bp, &env->breakpoints, entry, next) {
if (bp->flags & mask) if (bp->flags & mask)
cpu_breakpoint_remove_by_ref(env, bp); cpu_breakpoint_remove_by_ref(env, bp);
}
#endif #endif
} }
@ -2005,7 +1969,7 @@ int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
code_address = address; code_address = address;
/* Make accesses to pages with watchpoints go via the /* Make accesses to pages with watchpoints go via the
watchpoint trap routines. */ watchpoint trap routines. */
for (wp = env->watchpoints; wp != NULL; wp = wp->next) { TAILQ_FOREACH(wp, &env->watchpoints, entry) {
if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) { if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
iotlb = io_mem_watch + paddr; iotlb = io_mem_watch + paddr;
/* TODO: The memory case can be optimized by not trapping /* TODO: The memory case can be optimized by not trapping
@ -2552,7 +2516,7 @@ static void check_watchpoint(int offset, int len_mask, int flags)
return; return;
} }
vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset; vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
for (wp = env->watchpoints; wp != NULL; wp = wp->next) { TAILQ_FOREACH(wp, &env->watchpoints, entry) {
if ((vaddr == (wp->vaddr & len_mask) || if ((vaddr == (wp->vaddr & len_mask) ||
(vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) { (vaddr & wp->len_mask) == wp->vaddr) && (wp->flags & flags)) {
wp->flags |= BP_WATCHPOINT_HIT; wp->flags |= BP_WATCHPOINT_HIT;

View File

@ -2363,8 +2363,8 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
gen_icount_start(); gen_icount_start();
for (ret = 0; ret == 0;) { for (ret = 0; ret == 0;) {
if (unlikely(env->breakpoints)) { if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == ctx.pc) { if (bp->pc == ctx.pc) {
gen_excp(&ctx, EXCP_DEBUG, 0); gen_excp(&ctx, EXCP_DEBUG, 0);
break; break;

View File

@ -8677,8 +8677,8 @@ static inline void gen_intermediate_code_internal(CPUState *env,
} }
#endif #endif
if (unlikely(env->breakpoints)) { if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == dc->pc) { if (bp->pc == dc->pc) {
gen_set_condexec(dc); gen_set_condexec(dc);
gen_set_pc_im(dc->pc); gen_set_pc_im(dc->pc);

View File

@ -3189,8 +3189,8 @@ static void check_breakpoint(CPUState *env, DisasContext *dc)
{ {
CPUBreakpoint *bp; CPUBreakpoint *bp;
if (unlikely(env->breakpoints)) { if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == dc->pc) { if (bp->pc == dc->pc) {
cris_evaluate_flags (dc); cris_evaluate_flags (dc);
tcg_gen_movi_tl(env_pc, dc->pc); tcg_gen_movi_tl(env_pc, dc->pc);

View File

@ -1364,7 +1364,7 @@ static void breakpoint_handler(CPUState *env)
cpu_resume_from_signal(env, NULL); cpu_resume_from_signal(env, NULL);
} }
} else { } else {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) TAILQ_FOREACH(bp, &env->breakpoints, entry)
if (bp->pc == env->eip) { if (bp->pc == env->eip) {
if (bp->flags & BP_CPU) { if (bp->flags & BP_CPU) {
check_hw_breakpoints(env, 1); check_hw_breakpoints(env, 1);

View File

@ -7606,8 +7606,8 @@ static inline void gen_intermediate_code_internal(CPUState *env,
gen_icount_start(); gen_icount_start();
for(;;) { for(;;) {
if (unlikely(env->breakpoints)) { if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == pc_ptr) { if (bp->pc == pc_ptr) {
gen_debug(dc, pc_ptr - dc->cs_base); gen_debug(dc, pc_ptr - dc->cs_base);
break; break;

View File

@ -2999,8 +2999,8 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
do { do {
pc_offset = dc->pc - pc_start; pc_offset = dc->pc - pc_start;
gen_throws_exception = NULL; gen_throws_exception = NULL;
if (unlikely(env->breakpoints)) { if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == dc->pc) { if (bp->pc == dc->pc) {
gen_exception(dc, dc->pc, EXCP_DEBUG); gen_exception(dc, dc->pc, EXCP_DEBUG);
dc->is_jmp = DISAS_JUMP; dc->is_jmp = DISAS_JUMP;

View File

@ -8286,8 +8286,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
#endif #endif
gen_icount_start(); gen_icount_start();
while (ctx.bstate == BS_NONE) { while (ctx.bstate == BS_NONE) {
if (unlikely(env->breakpoints)) { if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == ctx.pc) { if (bp->pc == ctx.pc) {
save_cpu_state(&ctx, 1); save_cpu_state(&ctx, 1);
ctx.bstate = BS_BRANCH; ctx.bstate = BS_BRANCH;

View File

@ -7562,8 +7562,8 @@ static always_inline void gen_intermediate_code_internal (CPUState *env,
gen_icount_start(); gen_icount_start();
/* Set env in case of segfault during code fetch */ /* Set env in case of segfault during code fetch */
while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) { while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
if (unlikely(env->breakpoints)) { if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == ctx.nip) { if (bp->pc == ctx.nip) {
gen_update_nip(&ctx, ctx.nip); gen_update_nip(&ctx, ctx.nip);
gen_helper_raise_debug(); gen_helper_raise_debug();

View File

@ -1776,8 +1776,8 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
max_insns = CF_COUNT_MASK; max_insns = CF_COUNT_MASK;
gen_icount_start(); gen_icount_start();
while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
if (unlikely(env->breakpoints)) { if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (ctx.pc == bp->pc) { if (ctx.pc == bp->pc) {
/* We have hit a breakpoint - make sure PC is up-to-date */ /* We have hit a breakpoint - make sure PC is up-to-date */
tcg_gen_movi_i32(cpu_pc, ctx.pc); tcg_gen_movi_i32(cpu_pc, ctx.pc);

View File

@ -4816,8 +4816,8 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb,
max_insns = CF_COUNT_MASK; max_insns = CF_COUNT_MASK;
gen_icount_start(); gen_icount_start();
do { do {
if (unlikely(env->breakpoints)) { if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) {
for (bp = env->breakpoints; bp != NULL; bp = bp->next) { TAILQ_FOREACH(bp, &env->breakpoints, entry) {
if (bp->pc == dc->pc) { if (bp->pc == dc->pc) {
if (dc->pc != pc_start) if (dc->pc != pc_start)
save_state(dc, cpu_cond); save_state(dc, cpu_cond);