diff --git a/breakpoint.c b/breakpoint.c index 75665b0..545695d 100644 --- a/breakpoint.c +++ b/breakpoint.c @@ -83,7 +83,7 @@ static void enable_sw_breakpoint(struct task *task, struct breakpoint *bp) bp->sw = 1; bp->enabled = 1; - if (bp->break_insn) + if (unlikely(options.verbose && bp->break_insn)) fprintf(stderr, "!!!break insn pid=%d, addr=%#lx\n", task->pid, bp->addr); } @@ -529,13 +529,11 @@ void breakpoint_delete(struct task *task, struct breakpoint *bp) if (unlikely(options.verbose > 1 && bp->libsym)) { fprintf(stderr, - "delete %s breakpoint %s:%s [%#lx] count=%u was_hw=%u\n", + "delete %s breakpoint %s:%s [%#lx]\n", bp->type == BP_SW ? "sw" : "hw", bp->libsym->libref->filename, bp->libsym->func->demangled_name, - bp->addr, - bp->count, - bp->was_hw); + bp->addr); } bp->deleted = 1; diff --git a/client/readline.c b/client/readline.c index a8972af..86a9ebf 100644 --- a/client/readline.c +++ b/client/readline.c @@ -353,9 +353,8 @@ static void readline_handler(char *line) char *linedup; char *s; - linedup = strdup(line); - if (!linedup) - goto finish; + linedup = alloca(strlen(line) + 1); + strcpy(linedup, line); argv = malloc(argv_size * sizeof(*argv)); if (!argv) @@ -407,7 +406,7 @@ static void readline_handler(char *line) s += n + 1; } if (!i) - return; + goto finish; argc = i; argv[i++] = NULL; @@ -445,7 +444,6 @@ static void readline_handler(char *line) printf("unknown command '%s'\n", argv[0]); finish: free(argv); - free(linedup); if (quit) rl_callback_handler_remove(); @@ -919,5 +917,6 @@ void readline_exit(void) { if (!quit) rl_callback_handler_remove(); + rl_clear_history(); } diff --git a/event.c b/event.c index abc8c12..d47ffd2 100644 --- a/event.c +++ b/event.c @@ -114,27 +114,27 @@ static int do_clone(struct task *task, struct task *newtask) debug(DEBUG_EVENT, "+++ process %s pid=%d, newpid=%d", get_clone_type(task->event.type), task->pid, newtask->pid); if (unlikely(options.verbose)) - fprintf(stderr, "+++ process %s(%d) pid=%d, newpid=%d\n", get_clone_type(task->event.type), task->event.type, task->pid, newtask->pid); + fprintf(stderr, "+++ process %s pid=%d, newpid=%d\n", get_clone_type(task->event.type), task->pid, newtask->pid); assert(task->stopped); assert(newtask->stopped); assert(newtask->is_new); - if (newtask->event.type != EVENT_NEW) + if (unlikely(options.verbose && newtask->event.type != EVENT_NEW)) fprintf(stderr, "!!!task new unexpected event for pid=%d: %d\n", newtask->pid, newtask->event.type); else - if (newtask->event.e_un.signum) + if (unlikely(options.verbose && newtask->event.e_un.signum)) fprintf(stderr, "!!!task new unexpected signal for pid=%d: %d\n", newtask->pid, newtask->event.e_un.signum); if (newtask->leader == newtask) { - if (!options.follow) { - untrace_proc(newtask); - return RET_DELETED; - } - if (task_fork(task, newtask) < 0) goto fail; + if (!options.follow) { + remove_proc(newtask); + return RET_DELETED; + } + report_fork(newtask, task); } else { @@ -207,7 +207,7 @@ static int handle_new(struct task *task) assert(task->is_new); - if (task->event.e_un.signum) + if (unlikely(options.verbose && task->event.e_un.signum)) fprintf(stderr, "!!!task unexpected signal for pid=%d: %d\n", task->pid, task->event.e_un.signum); task->is_new = 0; @@ -338,7 +338,8 @@ static int handle_breakpoint(struct task *task) goto end; } - fprintf(stderr, "%s:%d\n", __func__, __LINE__); + if (unlikely(options.verbose)) + fprintf(stderr, "!!!unhandled skip breakpoint for pid=%d\n", task->pid); } if (unlikely(bp->deleted)) { @@ -396,7 +397,10 @@ static int handle_breakpoint(struct task *task) } } - skip_breakpoint(task, bp); + if (task->bp_skipped) + task->bp_skipped = 0; + else + skip_breakpoint(task, bp); end: breakpoint_put(bp); return 0; @@ -416,10 +420,12 @@ int handle_event(struct task *task) if (task->defer_func) { ret = task->defer_func(task, task->defer_data); + if (ret == RET_DELETED) + return 1; + task->defer_func = NULL; task->defer_data = NULL; - - return ret; + goto out2; } struct event *event = &task->event; @@ -434,7 +440,7 @@ int handle_event(struct task *task) break; case EVENT_ABOUT_EXIT: ret = handle_about_exit(task); - goto out; + goto out1; case EVENT_EXIT: ret = handle_exit(task); break; @@ -451,12 +457,12 @@ int handle_event(struct task *task) break; case EVENT_BREAKPOINT: ret = handle_breakpoint(task); - goto out; + goto out1; case EVENT_NEW: ret = handle_new(task); break; default: - fprintf(stderr, "!!!pid=%d, unknown event %d\n", task->pid, type); + fprintf(stderr, "fatal error, unknown event %d\n", type); abort(); } @@ -467,8 +473,9 @@ int handle_event(struct task *task) assert(task->event.type == EVENT_NONE); assert(task->stopped == 0); } +out2: assert(task->is_new == 0); -out: +out1: return (ret < 0) ? ret : 0; } diff --git a/memtrace.h b/memtrace.h index 15a9a0e..e7b3949 100644 --- a/memtrace.h +++ b/memtrace.h @@ -31,7 +31,7 @@ #define IS64BIT 0 #endif -#define MEMTRACE_SI_VERSION 8 +#define MEMTRACE_SI_VERSION 9 #define MEMTRACE_SI_FORK 1 #define MEMTRACE_SI_EXEC 2 @@ -100,6 +100,7 @@ struct __attribute__((packed)) mt_pid_payload { struct __attribute__((packed)) mt_scan_payload { uint32_t ptr_size; + uint32_t pad; // for 64 bit alignment uint64_t mask; char data[0]; }; diff --git a/report.c b/report.c index 2afcdc0..9533cb0 100644 --- a/report.c +++ b/report.c @@ -106,6 +106,9 @@ static void report_alloc32(struct task *task, enum mt_operation op, unsigned lon } } + task->bp_skipped = 1; + skip_breakpoint(task, task->event.e_un.breakpoint); + server_send_msg(op, task->leader->pid, alloc, sizeof(*alloc) + i * sizeof(uint32_t)); } diff --git a/sysdeps/linux-gnu/os.c b/sysdeps/linux-gnu/os.c index 99d3184..729eb39 100644 --- a/sysdeps/linux-gnu/os.c +++ b/sysdeps/linux-gnu/os.c @@ -256,6 +256,9 @@ void *mem_scan(struct task *task, struct mt_msg *cmd, void *payload, unsigned lo unsigned long start; unsigned long end; + if (unlikely(options.verbose)) + fprintf(stderr, "+++ scan for memory leaks...\n"); + if (!n) return NULL; diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c index ce97ddf..a78abfa 100644 --- a/sysdeps/linux-gnu/trace.c +++ b/sysdeps/linux-gnu/trace.c @@ -65,7 +65,7 @@ static inline int wait_task(struct task *task, int *status) ret = TEMP_FAILURE_RETRY(waitpid(task ? task->pid : -1, status, __WALL)); if (ret == -1) { - if (task) + if (unlikely(options.verbose && task)) fprintf(stderr, "!!!%s: waitpid pid=%d %s\n", __func__, task->pid, strerror(errno)); } return ret; @@ -75,23 +75,25 @@ static int trace_setup(struct task *task, int status, int signum) { int sig; + if (!WIFSTOPPED(status)) { + if (unlikely(options.verbose)) + fprintf(stderr, "!!!pid=%d not stopped\n", task->pid); + return -1; + } + task->attached = 1; task->stopped = 1; task->leader->threads_stopped++; task->event.type = EVENT_NEW; task->event.e_un.signum = 0; - if (!WIFSTOPPED(status)) { - fprintf(stderr, "!!!pid=%d not stopped\n", task->pid); - return -1; - } - sig = WSTOPSIG(status); if (sig != signum) { task->event.e_un.signum = sig; - fprintf(stderr, "!!!pid=%d unexpected trace signal (got:%d expected:%d)\n", task->pid, sig, signum); + if (unlikely(options.verbose)) + fprintf(stderr, "!!!pid=%d unexpected trace signal (got:%d expected:%d)\n", task->pid, sig, signum); return -1; } @@ -123,17 +125,18 @@ int trace_wait(struct task *task) static int child_event(struct task *task, enum event_type ev) { - unsigned long data; + unsigned long data = 0; debug(DEBUG_EVENT, "child event %d pid=%d, newpid=%d", ev, task->pid, task->event.e_un.newpid); - if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) { + if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno)); - return -1; - } int pid = data; + if (!pid) + return -1; + if (!pid2task(pid)) { struct task *child = task_new(pid); @@ -174,7 +177,8 @@ static int _process_event(struct task *task, int status) } if (!WIFSTOPPED(status)) { - fprintf(stderr, "!!!not WIFSTOPPED pid=%d\n", task->pid); + if (unlikely(options.verbose)) + fprintf(stderr, "!!!not WIFSTOPPED pid=%d\n", task->pid); return -1; } @@ -187,7 +191,8 @@ static int _process_event(struct task *task, int status) } if (!task->bad) { - fprintf(stderr, "!!!unexpected state for pid=%d, expected signal SIGSTOP (%d %d)\n", task->pid, sig, status >> 16); + if (unlikely(options.verbose)) + fprintf(stderr, "!!!unexpected state for pid=%d, expected signal SIGSTOP (%d %d)\n", task->pid, sig, status >> 16); task->bad = 1; } } @@ -210,24 +215,24 @@ static int _process_event(struct task *task, int status) return 0; case PTRACE_EVENT_EXIT: { - unsigned long data; + unsigned long data = 0; debug(DEBUG_EVENT, "ABOUT_EXIT: pid=%d", task->pid); - if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) { + if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno)); - return -1; - } + task->event.e_un.ret_val = WEXITSTATUS(data); task->event.type = EVENT_ABOUT_EXIT; return 0; } default: - fprintf(stderr, "!!!PTRACE_EVENT_????? pid=%d %d\n", task->pid, status >> 16); + if (unlikely(options.verbose)) + fprintf(stderr, "!!!PTRACE_EVENT_????? pid=%d %d\n", task->pid, status >> 16); break; } - if (!sig) + if (unlikely(options.verbose && !sig)) fprintf(stderr, "!!!%s: sig == 0 pid=%d\n", __func__, task->pid); if (sig == SIGSTOP) { @@ -238,8 +243,10 @@ static int _process_event(struct task *task, int status) else { if (likely(siginfo.si_pid == mtrace_pid)) sig = 0; - else - fprintf(stderr, "!!!%s: SIGSTOP pid=%d %d %d %d %d\n", __func__, task->pid, siginfo.si_signo, siginfo.si_errno, siginfo.si_code, siginfo.si_pid); + else { + if (unlikely(options.verbose)) + fprintf(stderr, "!!!%s: SIGSTOP pid=%d %d %d %d %d\n", __func__, task->pid, siginfo.si_signo, siginfo.si_errno, siginfo.si_code, siginfo.si_pid); + } } } @@ -307,7 +314,8 @@ static struct task * process_event(struct task *task, int status) { bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK); if (unlikely(!bp)) { - fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid); + if (unlikely(options.verbose)) + fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid); return task; } #if HW_BREAKPOINTS > 0 @@ -345,20 +353,18 @@ void trace_me(void) static inline int chk_signal(struct task *task, int signum) { -#if 1 - if (signum == SIGSTOP) - fprintf(stderr, "!!!%s: SIGSTOP pid=%d\n", __func__, task->pid); - - if (signum == SIGTRAP) - fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid); -#endif + if (unlikely(options.verbose)) { + if (signum == SIGSTOP) + fprintf(stderr, "!!!%s: SIGSTOP pid=%d\n", __func__, task->pid); + if (signum == SIGTRAP) + fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid); + } return signum; } int untrace_task(struct task *task) { - int ret; int sig = 0; assert(task->stopped); @@ -366,8 +372,7 @@ int untrace_task(struct task *task) if (unlikely(ptrace(PTRACE_SETOPTIONS, task->pid, 0, (void *)0) == -1)) { if (errno != ESRCH) fprintf(stderr, "PTRACE_SETOPTIONS pid=%d %s\n", task->pid, strerror(errno)); - ret = -1; - goto skip; + return -1; } if (task->event.type == EVENT_SIGNAL || task->event.type == EVENT_NONE) @@ -376,16 +381,11 @@ int untrace_task(struct task *task) if (unlikely(ptrace(PTRACE_DETACH, task->pid, 0, sig) == -1)) { if (errno != ESRCH) fprintf(stderr, "PTRACE_DETACH pid=%d %s\n", task->pid, strerror(errno)); - ret = -1; + return -1; } - task_kill(task, SIGCONT); -skip: - task->leader->threads_stopped--; - task->stopped = 0; - task->attached = 0; - - return ret; +// task_kill(task, SIGCONT); + return 0; } void stop_task(struct task *task) @@ -397,6 +397,7 @@ void stop_task(struct task *task) int status; task_kill(task, SIGSTOP); + if (wait_task(task, &status) != -1) _process_event(task, status); } @@ -441,14 +442,14 @@ int continue_task(struct task *task, int signum) assert(task->leader != NULL); assert(task->stopped); - if (signum >= 0x80) + if (unlikely(options.verbose && signum >= 0x80)) fprintf(stderr, "!!!signum >= 0x80 pid=%d: %d\n", task->pid, signum); task->leader->threads_stopped--; task->stopped = 0; task->event.type = EVENT_NONE; - if (signum == SIGTRAP) + if (unlikely(options.verbose && signum == SIGTRAP)) fprintf(stderr, "!!!%s: SIGTRAP pid=%d\n", __func__, task->pid); if (unlikely(ptrace(PTRACE_CONT, task->pid, 0, chk_signal(task, signum)) == -1)) { @@ -487,9 +488,10 @@ void stop_threads(struct task *task) each_task(leader, &do_stop_cb, NULL); - while (leader->threads != leader->threads_stopped) { - task = wait_event(); + while(leader->threads != leader->threads_stopped) { + assert(leader->threads > leader->threads_stopped); + task = wait_event(); if (task) queue_event(task); } @@ -511,7 +513,8 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s task->event.type = EVENT_NONE; if (unlikely(singlestep(task) == -1)) { - fprintf(stderr, "!!!%s: single step failed pid=%d\n", __func__, task->pid); + if (unlikely(options.verbose)) + fprintf(stderr, "!!!%s: single step failed pid=%d\n", __func__, task->pid); return -1; } @@ -521,7 +524,8 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s sig = _process_event(task, status); if (sig == -1) { - fprintf(stderr, "!!!%s: failed _process_event pid=%d\n", __func__, task->pid); + if (unlikely(options.verbose)) + fprintf(stderr, "!!!%s: failed _process_event pid=%d\n", __func__, task->pid); return 0; } @@ -535,7 +539,7 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s } if (sig != SIGTRAP) { - if (sig == SIGSTOP) + if (unlikely(options.verbose && sig == SIGSTOP)) fprintf(stderr, "!!!%s: SIGSTOP pid=%d\n", __func__, task->pid); queue_event(task); return 1; @@ -555,7 +559,7 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), s static int ptrace_singlestep(struct task *task) { if (unlikely(ptrace(PTRACE_SINGLESTEP, task->pid, 0, 0) == -1)) { - if (errno != ESRCH) + if (unlikely(options.verbose && errno != ESRCH)) fprintf(stderr, "!!!%s: PTRACE_SINGLESTEP pid=%d %s\n", __func__, task->pid, strerror(errno)); return -1; } @@ -600,7 +604,43 @@ struct task *wait_event(void) return NULL; } - assert(!task->stopped); + if (unlikely(task->stopped)) { + fprintf(stderr, "!!!%s: pid=%d already stopped (%u)\n", __func__, task->pid, task->event.type); + + if (WIFSIGNALED(status)) { + if (unlikely(options.verbose)) + fprintf(stderr, "!!!%s: exit signal for stopped pid=%d\n", __func__, task->pid); + + task->event.type = EVENT_EXIT_SIGNAL; + task->event.e_un.signum = WTERMSIG(status); + return NULL; + } + + if (WIFEXITED(status)) { + if (unlikely(options.verbose)) + fprintf(stderr, "!!!%s: exited process for stopped pid=%d\n", __func__, task->pid); + + task->event.type = EVENT_EXIT; + task->event.e_un.ret_val = WEXITSTATUS(status); + return NULL; + } + + if ((status >> 16) == PTRACE_EVENT_EXIT) { + unsigned long data = 0; + + if (unlikely(options.verbose)) + fprintf(stderr, "!!!%s: exit event for stopped pid=%d\n", __func__, task->pid); + + debug(DEBUG_EVENT, "ABOUT_EXIT: pid=%d", task->pid); + + if (unlikely(ptrace(PTRACE_GETEVENTMSG, task->pid, NULL, &data) == -1)) + debug(DEBUG_EVENT, "PTRACE_GETEVENTMSG pid=%d %s", task->pid, strerror(errno)); + + task->event.e_un.ret_val = WEXITSTATUS(data); + task->event.type = EVENT_ABOUT_EXIT; + return NULL; + } + } task = process_event(task, status); if (task) @@ -659,7 +699,8 @@ ssize_t copy_from_proc(struct task *task, arch_addr_t addr, void *dst, size_t le if (errno != EFAULT) { if (errno != ENOSYS) { - fprintf(stderr, "!!!%s: pid=%d process_vm_readv: %s\n", __func__, task->pid, strerror(errno)); + if (unlikely(options.verbose)) + fprintf(stderr, "!!!%s: pid=%d process_vm_readv: %s\n", __func__, task->pid, strerror(errno)); return -1; } diff --git a/task.c b/task.c index 926d332..4df2c6e 100644 --- a/task.c +++ b/task.c @@ -21,6 +21,8 @@ * 02110-1301 USA */ +#define _GNU_SOURCE + #include "config.h" #include @@ -153,6 +155,15 @@ struct task *pid2task(pid_t pid) return NULL; } +static void delete_task(struct task *task) +{ + arch_task_destroy(task); + os_task_destroy(task); + delete_pid(task); + breakpoint_clear_all(task); + free(task); +} + static int leader_setup(struct task *leader, int was_attached) { if (!elf_read_main_binary(leader, was_attached)) @@ -212,29 +223,13 @@ static int task_init(struct task *task) return 0; } -static int leader_cleanup(struct task *leader) +static void leader_cleanup(struct task *leader) { - if (!leader) - return 0; - - if (--leader->threads) - return 0; - library_clear_all(leader); breakpoint_clear_all(leader); backtrace_destroy(leader); list_del(&leader->leader_list); - - return 1; -} - -static void leader_release(struct task *leader) -{ - if (!leader_cleanup(leader)) - return; - - free(leader); } static void task_destroy(struct task *task) @@ -248,23 +243,32 @@ static void task_destroy(struct task *task) stop_task(task); + if (leader != task) + list_del(&task->task_list); + + leader->threads--; + leader->threads_stopped--; + if (task->event.type == EVENT_BREAKPOINT) breakpoint_put(task->event.e_un.breakpoint); arch_task_destroy(task); os_task_destroy(task); task_reset_bp(task); - remove_event(task); breakpoint_hw_destroy(task); delete_pid(task); + + if (!leader->threads) + leader_cleanup(leader); + untrace_task(task); + remove_event(task); - if (leader != task) { - list_del(&task->task_list); + if (leader != task) free(task); - } - leader_release(leader); + if (!leader->threads) + free(leader); } struct task *task_new(pid_t pid) @@ -279,6 +283,7 @@ struct task *task_new(pid_t pid) task->pid = pid; task->attached = 0; task->stopped = 0; + task->bp_skipped = 0; task->is_new = 1; task->defer_func = NULL; task->defer_data = NULL; @@ -288,7 +293,6 @@ struct task *task_new(pid_t pid) #if HW_BREAKPOINTS > 1 INIT_LIST_HEAD(&task->hw_bp_list); #endif - library_setup(task); init_event(task); @@ -322,16 +326,17 @@ int process_exec(struct task *task) each_task(leader, &remove_task_cb, leader); + assert(leader->threads == 1); + os_task_destroy(leader); arch_task_destroy(leader); leader_cleanup(leader); - assert(leader->threads == 0); - if (task_init(leader) < 0) goto fail; assert(leader->leader == leader); + assert(leader->threads == 1); assert(leader->threads_stopped == 1); if (leader_setup(leader, 0) < 0) @@ -347,9 +352,10 @@ struct task *task_create(char **argv) { struct task *task; pid_t pid; + int ret; pid = fork(); - if (pid < 0) { + if (pid == -1) { perror("fork"); return NULL; } @@ -365,27 +371,34 @@ struct task *task_create(char **argv) task = task_new(pid); if (!task) - goto fail2; + goto fail1; if (trace_wait(task)) goto fail1; if (trace_set_options(task) < 0) - goto fail2; + goto fail1; if (leader_setup(task, 0) < 0) - goto fail1; + goto fail2; - if (handle_event(task)) - goto fail1; + ret = handle_event(task); + if (ret < 0) + goto fail2; + + if (ret > 0) + return NULL; return task; -fail2: - fprintf(stderr, "failed to initialize process %d\n", pid); fail1: - if (task) - remove_proc(task); - kill(pid, SIGKILL); + fprintf(stderr, "failed to initialize process %d\n", pid); + if (task) { + delete_task(task); + kill(pid, SIGKILL); + } + return NULL; +fail2: + remove_proc(task); return NULL; } @@ -475,9 +488,12 @@ static struct task *open_one_pid(pid_t pid) if (trace_set_options(task) < 0) goto fail2; + queue_event(task); + return task; fail2: - task_destroy(task); + delete_task(task); + kill(pid, SIGCONT); fail1: return NULL; } @@ -571,7 +587,9 @@ void each_process(void (*cb)(struct task *task)) { struct list_head *it, *next; - list_for_each_safe(it, next, &list_of_leaders) { + for(it = list_of_leaders.prev; it != &list_of_leaders; it = next) { + next = it->prev; + struct task *task = container_of(it, struct task, leader_list); (*cb)(task); @@ -603,7 +621,10 @@ void remove_proc(struct task *leader) assert(leader->leader == leader); + stop_threads(leader); + breakpoint_disable_all(leader); each_task(leader, &remove_task_cb, leader); + assert(leader->threads == 1); task_destroy(leader); } diff --git a/task.h b/task.h index e29e513..311ac18 100644 --- a/task.h +++ b/task.h @@ -49,6 +49,7 @@ struct task { unsigned int stopped:1; unsigned int is_new:1; unsigned int bad:1; + unsigned int bp_skipped:1; struct breakpoint *breakpoint; struct library_symbol *libsym; diff --git a/trace.c b/trace.c index 4db6a70..04c6557 100644 --- a/trace.c +++ b/trace.c @@ -50,7 +50,7 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp) assert(task->stopped); assert(task->skip_bp == NULL); - if (bp->enabled && !bp->hw) { + if (bp->sw && bp->enabled) { int ret = 0; struct timespec start;