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;

Reply via email to