This patch modifies report_signal callback for gdbstub and uprobe_handler. Previously we would alert in uprobe_handler that gdb should stop the thread. For this we expected the thread to stop before it singlestepped. However this seems unreliable and also we werent doing a explicit UTRACE_STOP.
With this patch, report_signal callback has enuf intelligence to know if SIGTRAPS were occurring at the address where gdb requested for breakpoints. Now we have a dummy uprobe_handler. Signed-off-by: Srikar Dronamraju <sri...@linux.vnet.ibm.com> diff --git a/kernel/utrace-gdb.c b/kernel/utrace-gdb.c index 0c84afb..f7833dc 100644 --- a/kernel/utrace-gdb.c +++ b/kernel/utrace-gdb.c @@ -231,51 +231,33 @@ static void push_output_packet (struct gdb_connection *p, const char *s) /* ------------------------------------------------------------------------ */ - - -#ifdef CONFIG_HAVE_UPROBES -/* uprobe callback */ -void gdb_uprobe_handler (struct uprobe* up, struct pt_regs* regs) +static bool can_gdb_handle_sigtrap(struct pt_regs *regs, + struct gdb_connection *p) { - struct gdb_connection *p = NULL; - struct list_head *l; unsigned long bkpt = ubp_get_bkpt_addr (regs); struct task_struct *task = current; - pr_debug ("uprobe hit for %d, pc=%p\n", task->pid, (void*)bkpt); - - /* Find the right gdb_connection* for this task. */ - mutex_lock (& gdb_connections_mutex); - list_for_each(l, &gdb_connections) { - p = list_entry (l, struct gdb_connection, link); - if (p->target == task_tgid_nr(task)) { - struct list_head *l; - struct list_head *l2; - struct gdb_uprobe *gup = NULL; - - mutex_unlock (& gdb_connections_mutex); - mutex_lock (& p->output_mutex); - - list_for_each_safe(l, l2, & p->uprobes) { - gup = list_entry (l, struct gdb_uprobe, link); - pr_debug ("considering addr=%p %s\n", (void*) gup->up.vaddr, - gup->disarmed_p ? "disarmed" : ""); - if (gup->up.vaddr == bkpt && !gup->disarmed_p) { - p->at_quiesce_do = UTRACE_STOP; - snprintf (p->stopcode, GDB_BUFMAX, "S%02x", 5); /* SIGTRAP */ - push_output_packet (p, p->stopcode); - /* NB: This thread will be shortly stopped, even before - * uprobes get a chance to singlestep, or to complete an - * unregister_uprobe(). - */ - } - } + if (p->target == task_tgid_nr(task)) { + struct list_head *l; + struct list_head *l2; + struct gdb_uprobe *gup = NULL; + + list_for_each_safe(l, l2, &p->uprobes) { + gup = list_entry(l, struct gdb_uprobe, link); + pr_debug("considering addr=%p %s\n", + (void *)gup->up.vaddr, + gup->disarmed_p ? "disarmed" : ""); + if (gup->up.vaddr == bkpt && !gup->disarmed_p) + return true; + } + } + return false; +} - mutex_unlock (& p->output_mutex); - return; - } - } - mutex_unlock (& gdb_connections_mutex); +#ifdef CONFIG_HAVE_UPROBES +/* uprobe callback */ +void gdb_uprobe_handler(struct uprobe *up, struct pt_regs *regs) +{ } #endif /* CONFIG_HAVE_UPROBES */ @@ -405,14 +387,14 @@ u32 gdb_utrace_report_signal(u32 action, break; case UTRACE_SIGNAL_REPORT: /* case 3 */ - if (p->stop_signals>0) { + if (p->stop_signals > 0) { p->stop_signals --; snprintf (p->stopcode, GDB_BUFMAX, "S%02x", 2); /* SIGINT */ push_output_packet (p, p->stopcode); p->at_quiesce_do = UTRACE_STOP; ret = UTRACE_STOP | UTRACE_SIGNAL_IGN; } else { - ret = UTRACE_RESUME | utrace_signal_action(action); + ret = p->at_quiesce_do | utrace_signal_action(action); } break; @@ -424,14 +406,17 @@ u32 gdb_utrace_report_signal(u32 action, case UTRACE_SIGNAL_TSTP: #ifdef CONFIG_HAVE_UPROBES if (info->si_signo == SIGTRAP) { /* case 2a */ - unsigned long bkpt = ubp_get_bkpt_addr (regs); - /* XXX: search for nearby uprobes. */ - (void) bkpt; - - /* NB: don't set p->at_quiesce_do, since the uprobes_handler - might have already been called, and set UTRACE_STOP there. */ - ret = UTRACE_RESUME; /* Let uprobes consume the signal. */ - break; + if (can_gdb_handle_sigtrap(regs, p)) { + p->at_quiesce_do = UTRACE_STOP; + /* SIGTRAP */ + snprintf(p->stopcode, GDB_BUFMAX, "S%02x", 5); + push_output_packet(p, p->stopcode); + ret = UTRACE_STOP | + utrace_signal_action(action); + } else + ret = UTRACE_RESUME | + utrace_signal_action(action); + break; } #endif /* CONFIG_HAVE_UPROBES */ if (p->pass_signals > 0 /*&& kern_p*/) { /* case 4 */ @@ -443,7 +428,7 @@ u32 gdb_utrace_report_signal(u32 action, map_signal_kern2gdb(info->si_signo)); push_output_packet (p, p->stopcode); p->at_quiesce_do = UTRACE_STOP; - ret = UTRACE_STOP; + ret = UTRACE_STOP | utrace_signal_action(action); } break; } @@ -1327,7 +1312,6 @@ again: mutex_unlock(&p->output_mutex); goto again; } - len = min (count, (size_t)(p->output_buf_size - p->output_buf_read)); if (copy_to_user (buf, & p->output_buf[p->output_buf_read], len)) { rc = -EFAULT;