WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] Rename cdb to gdbstub and split it into arch dependent/n

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] Rename cdb to gdbstub and split it into arch dependent/neutral part.
From: Xen patchbot -unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Sat, 14 Jan 2006 17:10:07 +0000
Delivery-date: Sat, 14 Jan 2006 17:17:25 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 1b839e1b1de1b1fcf608fa3803b861f9f0672e4b
# Parent  ef88c2db00ad5076594dc5921e14db89bdf6cb7e
Rename cdb to gdbstub and split it into arch dependent/neutral part.

Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx>
Signed-off-by: Hollis Blanchard <hollisb@xxxxxxxxxx>

diff -r ef88c2db00ad -r 1b839e1b1de1 xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile     Sat Jan 14 09:36:40 2006
+++ b/xen/arch/x86/Makefile     Sat Jan 14 15:58:54 2006
@@ -32,7 +32,7 @@
 OBJS := $(subst $(TARGET_SUBARCH)/xen.lds.o,,$(OBJS))
 
 ifneq ($(crash_debug),y)
-OBJS := $(patsubst cdb%.o,,$(OBJS))
+OBJS := $(patsubst gdbstub%.o,,$(OBJS))
 endif
 
 default: $(TARGET)
diff -r ef88c2db00ad -r 1b839e1b1de1 xen/common/Makefile
--- a/xen/common/Makefile       Sat Jan 14 09:36:40 2006
+++ b/xen/common/Makefile       Sat Jan 14 15:58:54 2006
@@ -3,6 +3,9 @@
 
 ifneq ($(perfc),y)
 OBJS := $(subst perfc.o,,$(OBJS))
+endif
+ifneq ($(crash_debug),y)
+OBJS := $(patsubst gdbstub.o,,$(OBJS))
 endif
 
 default: common.o
diff -r ef88c2db00ad -r 1b839e1b1de1 xen/include/asm-x86/debugger.h
--- a/xen/include/asm-x86/debugger.h    Sat Jan 14 09:36:40 2006
+++ b/xen/include/asm-x86/debugger.h    Sat Jan 14 15:58:54 2006
@@ -42,19 +42,19 @@
 
 #if defined(CRASH_DEBUG)
 
-extern int __trap_to_cdb(struct cpu_user_regs *r);
+#include <xen/gdbstub.h>
 
 #define __debugger_trap_entry(_v, _r) (0)
 
 static inline int __debugger_trap_fatal(
     unsigned int vector, struct cpu_user_regs *regs)
 {
-    (void)__trap_to_cdb(regs);
+    (void)__trap_to_gdb(regs, vector);
     return (vector == TRAP_int3); /* int3 is harmless */
 }
 
 /* Int3 is a trivial way to gather cpu_user_regs context. */
-#define __debugger_trap_immediate() __asm__ __volatile__ ( "int3" );
+#define debugger_trap_immediate() __asm__ __volatile__ ( "int3" );
 
 #elif 0
 
@@ -73,7 +73,7 @@
 }
 
 /* Int3 is a trivial way to gather cpu_user_regs context. */
-#define __debugger_trap_immediate() __asm__ __volatile__ ( "int3" )
+#define debugger_trap_immediate() __asm__ __volatile__ ( "int3" )
 
 #else
 
@@ -100,6 +100,8 @@
 }
 
 #define debugger_trap_fatal(v, r) (__debugger_trap_fatal(v, r))
+#ifndef debugger_trap_immediate
 #define debugger_trap_immediate() (__debugger_trap_immediate())
+#endif
 
 #endif /* __X86_DEBUGGER_H__ */
diff -r ef88c2db00ad -r 1b839e1b1de1 xen/arch/x86/gdbstub.c
--- /dev/null   Sat Jan 14 09:36:40 2006
+++ b/xen/arch/x86/gdbstub.c    Sat Jan 14 15:58:54 2006
@@ -0,0 +1,146 @@
+/*
+ * x86-specific gdb stub routines
+ * based on x86 cdb(xen/arch/x86/cdb.c), but Extensively modified.
+ * 
+ * Copyright (C) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan. K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#include <asm/debugger.h>
+
+u16
+gdb_arch_signal_num(struct cpu_user_regs *regs, unsigned long cookie)
+{
+    /* XXX */
+    return 1;
+}
+
+void 
+gdb_arch_read_reg_array(struct cpu_user_regs *regs, struct gdb_context *ctx)
+{
+#define GDB_REG(r) gdb_write_to_packet_hex(r, sizeof(r), ctx);
+    GDB_REG(regs->eax);
+    GDB_REG(regs->ecx);
+    GDB_REG(regs->edx);
+    GDB_REG(regs->ebx);
+    GDB_REG(regs->esp);
+    GDB_REG(regs->ebp);
+    GDB_REG(regs->esi);
+    GDB_REG(regs->edi);
+    GDB_REG(regs->eip);
+    GDB_REG(regs->eflags);
+#undef GDB_REG
+#define GDB_SEG_REG(s)  gdb_write_to_packet_hex(s, sizeof(u32), ctx);
+    /* sizeof(segment) = 16bit */
+    /* but gdb requires its return value as 32bit value */
+    GDB_SEG_REG(regs->cs);
+    GDB_SEG_REG(regs->ss);
+    GDB_SEG_REG(regs->ds);
+    GDB_SEG_REG(regs->es);
+    GDB_SEG_REG(regs->fs);
+    GDB_SEG_REG(regs->gs);
+#undef GDB_SEG_REG
+    gdb_send_packet(ctx);
+}
+
+void 
+gdb_arch_write_reg_array(struct cpu_user_regs *regs, const char* buf,
+                         struct gdb_context *ctx)
+{
+    /* XXX TODO */
+    gdb_send_reply("E02", ctx);
+}
+
+void 
+gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs *regs,
+                  struct gdb_context *ctx)
+{
+    gdb_send_reply("", ctx);
+}
+
+/* Like copy_from_user, but safe to call with interrupts disabled.
+   Trust me, and don't look behind the curtain. */
+unsigned 
+gdb_arch_copy_from_user(void *dest, const void *src, unsigned len)
+{
+    int __d0, __d1, __d2;
+    ASSERT(!local_irq_is_enabled());
+    __asm__ __volatile__(
+        "1: rep; movsb\n"
+        "2:\n"
+        ".section .fixup,\"ax\"\n"
+        "3:     addl $4, %%esp\n"
+        "       jmp 2b\n"
+        ".previous\n"
+        ".section __pre_ex_table,\"a\"\n"
+        "   .align 4\n"
+        "   .long 1b,3b\n"
+        ".previous\n"
+        ".section __ex_table,\"a\"\n"
+        "   .align 4\n"
+        "   .long 1b,2b\n"
+        ".previous\n"
+        : "=c"(__d2), "=D" (__d0), "=S" (__d1)
+        : "0"(len), "1"(dest), "2"(src)
+        : "memory");
+    ASSERT(!local_irq_is_enabled());
+    return __d2;
+}
+
+unsigned int 
+gdb_arch_copy_to_user(void *dest, const void *src, unsigned len)
+{
+    /* XXX  */
+    return len;
+}
+
+void 
+gdb_arch_resume(struct cpu_user_regs *regs,
+                unsigned long addr, unsigned long type,
+                struct gdb_context *ctx)
+{
+    /* XXX */
+    if (type == GDB_STEP) {
+        gdb_send_reply("S01", ctx);
+    }
+}
+
+void
+gdb_arch_print_state(struct cpu_user_regs *regs)
+{
+    /* XXX */
+}
+
+void
+gdb_arch_enter(struct cpu_user_regs *regs)
+{
+    /* nothing */
+}
+
+void
+gdb_arch_exit(struct cpu_user_regs *regs)
+{
+    /* nothing */
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -r ef88c2db00ad -r 1b839e1b1de1 xen/common/gdbstub.c
--- /dev/null   Sat Jan 14 09:36:40 2006
+++ b/xen/common/gdbstub.c      Sat Jan 14 15:58:54 2006
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2005 Jimi Xenidis <jimix@xxxxxxxxxxxxxx>, IBM Corporation
+ * Copyright (C) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan. K.K.
+ * 
+ * gdbstub arch neutral part
+ * Based on x86 cdb (xen/arch/x86/cdb.c) and ppc gdbstub(xen/common/gdbstub.c)
+ * But extensively modified.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+/*
+ * gdbstub: implements the architecture independant parts of the
+ * gdb remote protocol.
+ */
+
+/* We try to avoid assuming much about what the rest of the system is
+   doing.  In particular, dynamic memory allocation is out of the
+   question. */
+
+/* Resuming after we've stopped used to work, but more through luck
+   than any actual intention.  It doesn't at the moment. */
+
+#include <xen/lib.h>
+#include <asm/uaccess.h>
+#include <xen/spinlock.h>
+#include <xen/serial.h>
+#include <xen/irq.h>
+#include <asm/debugger.h>
+#include <xen/init.h>
+#include <xen/smp.h>
+#include <xen/console.h>
+
+/* Printk isn't particularly safe just after we've trapped to the
+   debugger. so avoid it. */
+#define dbg_printk(...)
+/*#define dbg_printk(...)   printk(__VA_ARGS__)*/
+
+#define GDB_RETRY_MAX   10
+
+static char opt_gdb[30] = "none";
+string_param("gdb", opt_gdb);
+
+/* value <-> char (de)serialzers */
+char
+hex2char(unsigned long x)
+{
+    const char array[] = "0123456789abcdef";
+
+    return array[x & 15];
+}
+
+int
+char2hex(unsigned char c)
+{
+    if ( (c >= '0') && (c <= '9') )
+        return c - '0';
+    else if ( (c >= 'a') && (c <= 'f') )
+        return c - 'a' + 10;
+    else if ( (c >= 'A') && (c <= 'F') )
+        return c - 'A' + 10;
+    else
+        BUG();
+    return -1;
+}
+
+char
+str2hex(const char *str)
+{
+    return (char2hex(str[0]) << 4) | char2hex(str[1]);
+}
+
+unsigned long
+str2ulong(const char *str, unsigned long bytes)
+{
+    unsigned long x = 0;
+    unsigned long i = 0;
+
+    while ( *str && (i < (bytes * 2)) )
+    {
+        x <<= 4;
+        x += char2hex(*str);
+        ++str;
+        ++i;
+    }
+
+    return x;
+}
+
+/* gdb io wrappers */
+static signed long
+gdb_io_write(const char *buf, unsigned long len, struct gdb_context *ctx)
+{
+    int i;
+    for ( i = 0; i < len; i++ )
+        serial_putc(ctx->serhnd, buf[i]);
+    return i;
+}
+
+static int
+gdb_io_write_char(u8 data, struct gdb_context *ctx)
+{
+    return gdb_io_write((char*)&data, 1, ctx);
+}
+
+static unsigned char
+gdb_io_read(struct gdb_context *ctx)
+{
+    return serial_getc(ctx->serhnd);
+}
+
+/* Receive a command.  Returns -1 on csum error, 0 otherwise. */
+/* Does not acknowledge. */
+static int 
+attempt_receive_packet(struct gdb_context *ctx)
+{
+    u8 csum;
+    u8 received_csum;
+    u8 ch;
+
+    /* Skip over everything up to the first '$' */
+    while ( (ch = gdb_io_read(ctx)) != '$' )
+        continue;
+
+    csum = 0;
+    for ( ctx->in_bytes = 0;
+          ctx->in_bytes < sizeof(ctx->in_buf);
+          ctx->in_bytes++ )
+    {
+        ch = gdb_io_read(ctx);
+        if ( ch == '#' )
+            break;
+        ctx->in_buf[ctx->in_bytes] = ch;
+        csum += ch;
+    }
+
+    if ( ctx->in_bytes == sizeof(ctx->in_buf) )
+    {
+        dbg_printk("WARNING: GDB sent a stupidly big packet.\n");
+        return -1;
+    }
+
+    ctx->in_buf[ctx->in_bytes] = '\0';
+    received_csum = char2hex(gdb_io_read(ctx)) * 16 +
+        char2hex(gdb_io_read(ctx));
+
+    return (received_csum == csum) ? 0 : -1;
+}
+
+/* Receive a command, discarding up to ten packets with csum
+ * errors.  Acknowledges all received packets. */
+static int 
+receive_command(struct gdb_context *ctx)
+{
+    int r, count = 0;
+
+    count = 0;
+    do {
+        r = attempt_receive_packet(ctx);
+        gdb_io_write_char((r < 0) ? '-' : '+', ctx);
+        count++;
+    } while ( (r < 0) && (count < GDB_RETRY_MAX) );
+
+    return r;
+}
+
+/* routines to send reply packets */
+
+static void 
+gdb_start_packet(struct gdb_context *ctx)
+{
+    ctx->out_buf[0] = '$';
+    ctx->out_offset = 1;
+    ctx->out_csum = 0;
+}
+
+static void 
+gdb_write_to_packet_char(u8 data, struct gdb_context *ctx)
+{
+    ctx->out_csum += data;
+    ctx->out_buf[ctx->out_offset] = data;
+    ctx->out_offset++;
+}
+
+void 
+gdb_write_to_packet(const char *buf, int count, struct gdb_context *ctx)
+{
+    int x;
+    for ( x = 0; x < count; x++ )
+        gdb_write_to_packet_char(buf[x], ctx);
+}
+
+void 
+gdb_write_to_packet_str(const char *buf, struct gdb_context *ctx)
+{
+    gdb_write_to_packet(buf, strlen(buf), ctx);
+}
+
+void
+gdb_write_to_packet_hex(unsigned long x, int int_size, struct gdb_context *ctx)
+{
+    char buf[sizeof(unsigned long) * 2 + 1];
+    int i = sizeof(unsigned long) * 2;
+    int width = int_size * 2;
+
+    buf[sizeof(unsigned long) * 2] = 0;
+
+    switch ( int_size )
+    {
+    case sizeof(u8):
+    case sizeof(u16):
+    case sizeof(u32):
+    case sizeof(u64):
+        break;
+    default:
+        dbg_printk("WARNING: %s x: 0x%lx int_size: %d\n",
+                   __func__, x, int_size);
+        break;
+    }
+
+    do {
+        buf[--i] = hex2char(x & 15);
+        x >>= 4;
+    } while ( x );
+
+    while ( (i + width) > (sizeof(unsigned long) * 2) )
+        buf[--i] = '0';
+
+    gdb_write_to_packet(&buf[i], width, ctx);
+}
+
+static int
+gdb_check_ack(struct gdb_context *ctx)
+{
+    u8 c = gdb_io_read(ctx);
+
+    switch ( c )
+    {
+    case '+':
+        return 1;
+    case '-':
+        return 0;
+    default:
+        printk("Bad ack: %c\n", c);
+        return 0;
+    }
+}
+
+/* Return 0 if the reply was successfully received, !0 otherwise. */
+void 
+gdb_send_packet(struct gdb_context *ctx)
+{
+    char buf[3];
+    int count;
+
+    sprintf(buf, "%.02x\n", ctx->out_csum);
+
+    gdb_write_to_packet_char('#', ctx);
+    gdb_write_to_packet(buf, 2, ctx);
+
+    count = 0;
+    do {
+        gdb_io_write(ctx->out_buf, ctx->out_offset, ctx);
+    } while ( !gdb_check_ack(ctx) && (count++ < GDB_RETRY_MAX) );
+
+    if ( count == GDB_RETRY_MAX )
+        dbg_printk("WARNING: %s reached max retry %d\n",
+                   __func__, GDB_RETRY_MAX);
+}
+
+void 
+gdb_send_reply(const char *buf, struct gdb_context *ctx)
+{
+    gdb_start_packet(ctx);
+    gdb_write_to_packet_str(buf, ctx);
+    gdb_send_packet(ctx);
+}
+
+/* arch neutral command handlers */
+
+static void 
+gdb_cmd_signum(struct gdb_context *ctx)
+{
+    gdb_write_to_packet_char('S', ctx);
+    gdb_write_to_packet_hex(ctx->signum, sizeof(ctx->signum), ctx);
+    gdb_send_packet(ctx);
+}
+
+static void 
+gdb_cmd_read_mem(unsigned long addr, unsigned long length,
+                 struct gdb_context *ctx)
+{
+    int x, r;
+    unsigned char val;
+
+    dbg_printk("Memory read starting at %lx, length %lx.\n", addr,
+               length);
+
+    for ( x = 0; x < length; x++ )
+    {
+        r = gdb_arch_copy_from_user(&val, (void *)(addr + x), 1);
+        if ( r != 0 )
+        {
+            dbg_printk("Error reading from %lx.\n", addr + x);
+            break;
+        }
+        gdb_write_to_packet_hex(val, sizeof(val), ctx);
+    }
+
+    if ( x == 0 )
+        gdb_write_to_packet_str("E05", ctx);
+
+    dbg_printk("Read done.\n");
+
+    gdb_send_packet(ctx);
+}
+
+static void 
+gdb_cmd_write_mem(unsigned long addr, unsigned long length,
+                  const char *buf, struct gdb_context *ctx)
+{
+    int x, r;
+    unsigned char val;
+
+    dbg_printk("Memory write starting at %lx, length %lx.\n", addr, length);
+
+    for ( x = 0; x < length; x++, addr++, buf += 2 )
+    {
+        val = str2ulong(buf, sizeof(val));
+        r = gdb_arch_copy_to_user((void*)addr, (void*)&val, 1);
+        if ( r != 0 )
+        {
+            dbg_printk("Error writing to %lx.\n", addr);
+            break;
+        }
+    }
+
+    gdb_write_to_packet_str((x != length) ? "OK" : "E11", ctx);
+
+    dbg_printk("Write done.\n");
+
+    gdb_send_packet(ctx);
+}
+
+/* command dispatcher */
+static int 
+process_command(struct cpu_user_regs *regs, struct gdb_context *ctx)
+{
+    char *ptr;
+    unsigned long addr, length;
+    int resume = 0;
+
+    /* XXX check ctx->in_bytes >= 2 or similar. */
+
+    gdb_start_packet(ctx);
+    switch ( ctx->in_buf[0] )
+    {
+    case '?':    /* query signal number */
+        gdb_cmd_signum(ctx);
+        break;
+    case 'H':    /* thread operations */
+        gdb_send_reply("OK", ctx);
+        break;
+    case 'g': /* Read registers */
+        gdb_arch_read_reg_array(regs, ctx);
+        ASSERT(!local_irq_is_enabled());
+        break;
+    case 'G': /* Write registers */
+        gdb_arch_write_reg_array(regs, ctx->in_buf + 1, ctx);
+        break;
+    case 'm': /* Read memory */
+        addr = simple_strtoul(ctx->in_buf + 1, &ptr, 16);
+        if ( (ptr == (ctx->in_buf + 1)) || (ptr[0] != ',') )
+        {
+            gdb_send_reply("E03", ctx);
+            return 0;
+        }
+        length = simple_strtoul(ptr + 1, &ptr, 16);
+        if ( ptr[0] != 0 )
+        {
+            gdb_send_reply("E04", ctx);
+            return 0;
+        }
+        gdb_cmd_read_mem(addr, length, ctx);
+        ASSERT(!local_irq_is_enabled());
+        break;
+    case 'M': /* Write memory */
+        addr = simple_strtoul(ctx->in_buf + 1, &ptr, 16);
+        if ( (ptr == (ctx->in_buf + 1)) || (ptr[0] != ':') )
+        {
+            gdb_send_reply("E03", ctx);
+            return 0;
+        }
+        length = simple_strtoul(ptr + 1, &ptr, 16);
+        gdb_cmd_write_mem(addr, length, ptr, ctx);
+        break;
+    case 'p': /* read register */
+        addr = simple_strtoul(ctx->in_buf + 1, &ptr, 16);
+        if ( ptr == (ctx->in_buf + 1) )
+        {
+            gdb_send_reply("E03", ctx);
+            return 0;
+        }
+        if ( ptr[0] != 0 )
+        {
+            gdb_send_reply("E04", ctx);
+            return 0;
+        }
+        gdb_arch_read_reg(addr, regs, ctx);
+        break;
+    case 'Z': /* We need to claim to support these or gdb
+                 won't let you continue the process. */
+    case 'z':
+        gdb_send_reply("OK", ctx);
+        break;
+
+    case 'D':
+        ctx->currently_attached = 0;
+        gdb_send_reply("OK", ctx);
+        /* fall through */
+    case 'k':
+        ctx->connected = 0;
+        /* fall through */
+    case 's': /* Single step */
+    case 'c': /* Resume at current address */
+    {
+        unsigned long addr = ~((unsigned long)0);
+        unsigned long type = GDB_CONTINUE;
+        if ( ctx->in_buf[0] == 's' )
+            type = GDB_STEP;
+        if ( ((ctx->in_buf[0] == 's') || (ctx->in_buf[0] == 'c')) &&
+             ctx->in_buf[1] )
+            addr = str2ulong(&ctx->in_buf[1], sizeof(unsigned long));
+        if ( ctx->in_buf[0] != 'D' )
+            ctx->currently_attached = 1;
+        resume = 1;
+        gdb_arch_resume(regs, addr, type, ctx);
+        break;
+    }
+
+    default:
+        gdb_send_reply("", ctx);
+        break;
+    }
+    return resume;
+}
+
+static struct gdb_context
+__gdb_ctx = {
+    .serhnd             = -1,
+    .currently_attached = 0,
+    .running            = ATOMIC_INIT(1),
+    .connected          = 0,
+    .signum             = 1,
+    .in_bytes           = 0,
+    .out_offset         = 0,
+    .out_csum           = 0,
+};
+static struct gdb_context *gdb_ctx = &__gdb_ctx;
+
+/* trap handler: main entry point */
+int 
+__trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
+{
+    int resume = 0;
+    int r;
+    unsigned flags;
+
+    if ( gdb_ctx->serhnd < 0 )
+    {
+        dbg_printk("Debugger not ready yet.\n");
+        return 0;
+    }
+
+    /* We rely on our caller to ensure we're only on one processor
+     * at a time... We should probably panic here, but given that
+     * we're a debugger we should probably be a little tolerant of
+     * things going wrong. */
+    /* We don't want to use a spin lock here, because we're doing
+       two distinct things:
+
+       1 -- we don't want to run on more than one processor at a time,
+            and
+       2 -- we want to do something sensible if we re-enter ourselves.
+
+       Spin locks are good for 1, but useless for 2. */
+    if ( !atomic_dec_and_test(&gdb_ctx->running) )
+    {
+        printk("WARNING WARNING WARNING: Avoiding recursive gdb.\n");
+        atomic_inc(&gdb_ctx->running);
+        return 0;
+    }
+
+    if ( !gdb_ctx->connected )
+    {
+        printk("GDB connection activated\n");
+        gdb_arch_print_state(regs);
+        gdb_ctx->connected = 1;
+    }
+
+    smp_send_stop();
+
+    /* Try to make things a little more stable by disabling
+       interrupts while we're here. */
+    local_irq_save(flags);
+
+    watchdog_disable();
+    console_start_sync();
+
+    /* Shouldn't really do this, but otherwise we stop for no
+       obvious reason, which is Bad */
+    printk("Waiting for GDB to attach to Gdb\n");
+
+    gdb_arch_enter(regs);
+    gdb_ctx->signum = gdb_arch_signal_num(regs, cookie);
+    /* If gdb is already attached, tell it we've stopped again. */
+    if ( gdb_ctx->currently_attached )
+    {
+        gdb_start_packet(gdb_ctx);
+        gdb_cmd_signum(gdb_ctx);
+    }
+
+    while ( resume == 0 )
+    {
+        ASSERT(!local_irq_is_enabled());
+        r = receive_command(gdb_ctx);
+        ASSERT(!local_irq_is_enabled());
+        if ( r < 0 )
+        {
+            dbg_printk("GDB disappeared, trying to resume Xen...\n");
+            resume = 1;
+        }
+        else
+        {
+            ASSERT(!local_irq_is_enabled());
+            resume = process_command(regs, gdb_ctx);
+            ASSERT(!local_irq_is_enabled());
+        }
+    }
+
+    gdb_arch_exit(regs);
+    console_end_sync();
+    watchdog_enable();
+    atomic_inc(&gdb_ctx->running);
+
+    local_irq_restore(flags);
+
+    return 0;
+}
+
+/*
+ * initialization
+ * XXX TODO
+ *     This should be an explicit call from architecture code.               
+ *     initcall is far too late for some early debugging, and only the 
+ *     architecture code knows when this call can be made.          
+ */
+static int
+initialize_gdb(void)
+{
+    if ( !strcmp(opt_gdb, "none") )
+        return 0;
+    gdb_ctx->serhnd = serial_parse_handle(opt_gdb);
+    if ( gdb_ctx->serhnd == -1 )
+        panic("Can't parse %s as GDB serial info.\n", opt_gdb);
+
+    printk("Gdb initialised.\n");
+    return 0;
+}
+
+__initcall(initialize_gdb);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -r ef88c2db00ad -r 1b839e1b1de1 xen/include/xen/gdbstub.h
--- /dev/null   Sat Jan 14 09:36:40 2006
+++ b/xen/include/xen/gdbstub.h Sat Jan 14 15:58:54 2006
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2005 Hollis Blanchard <hollisb@xxxxxxxxxx>, IBM Corporation
+ * Copyright (C) 2006 Isaku Yamahata <yamahata at valinux co jp>
+ *                    VA Linux Systems Japan. K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef __XEN_GDBSTUB_H__
+#define __XEN_GDBSTUB_H__
+
+/* value <-> char (de)serialzers for arch specific gdb backends */
+char hex2char(unsigned long x); 
+int char2hex(unsigned char c); 
+char str2hex(const char *str); 
+unsigned long str2ulong(const char *str, unsigned long bytes); 
+
+struct gdb_context {
+    int                 serhnd;
+    int                 currently_attached:1;
+    atomic_t            running;
+    unsigned long       connected;
+    u8                  signum;
+
+    char                in_buf[PAGE_SIZE];
+    unsigned long       in_bytes;
+
+    char                out_buf[PAGE_SIZE];
+    unsigned long       out_offset;
+    u8                  out_csum;
+};
+
+/* interface to arch specific routines */
+void gdb_write_to_packet(
+    const char *buf, int count, struct gdb_context *ctx);
+void gdb_write_to_packet_hex(
+    unsigned long x, int int_size, struct gdb_context *ctx);
+void gdb_send_packet(struct gdb_context *ctx); 
+void gdb_send_reply(const char *buf, struct gdb_context *ctx);
+
+/* gdb stub trap handler: entry point */
+int __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie);
+
+/* arch specific routines */
+u16 gdb_arch_signal_num(
+    struct cpu_user_regs *regs, unsigned long cookie);
+void gdb_arch_read_reg_array(
+    struct cpu_user_regs *regs, struct gdb_context *ctx);
+void gdb_arch_write_reg_array(
+    struct cpu_user_regs *regs, const char* buf, struct gdb_context *ctx);
+void gdb_arch_read_reg(
+    unsigned long regnum, struct cpu_user_regs *regs, struct gdb_context *ctx);
+unsigned int gdb_arch_copy_from_user(
+    void *dest, const void *src, unsigned len);
+unsigned int gdb_arch_copy_to_user(
+    void *dest, const void *src, unsigned len);
+void gdb_arch_resume(
+    struct cpu_user_regs *regs, unsigned long addr,
+    unsigned long type, struct gdb_context *ctx);
+void gdb_arch_print_state(struct cpu_user_regs *regs);
+void gdb_arch_enter(struct cpu_user_regs *regs);
+void gdb_arch_exit(struct cpu_user_regs *regs);
+
+#define GDB_CONTINUE     0
+#define GDB_STEP         1
+
+#define SIGILL           4
+#define SIGTRAP          5
+#define SIGBUS           7
+#define SIGFPE           8
+#define SIGSEGV         11
+#define SIGALRM         14
+#define SIGTERM         15
+
+#endif /* __XEN_GDBSTUB_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -r ef88c2db00ad -r 1b839e1b1de1 xen/arch/x86/cdb.c
--- a/xen/arch/x86/cdb.c        Sat Jan 14 09:36:40 2006
+++ /dev/null   Sat Jan 14 15:58:54 2006
@@ -1,414 +0,0 @@
-/* Simple hacked-up version of pdb for use in post-mortem debugging of
-   Xen and domain 0. This should be a little cleaner, hopefully.  Note
-   that we can't share a serial line with PDB. */
-/* We try to avoid assuming much about what the rest of the system is
-   doing.  In particular, dynamic memory allocation is out of the
-   question. */
-/* Resuming after we've stopped used to work, but more through luck
-   than any actual intention.  It doesn't at the moment. */
-#include <xen/lib.h>
-#include <asm/uaccess.h>
-#include <xen/spinlock.h>
-#include <xen/serial.h>
-#include <xen/irq.h>
-#include <asm/debugger.h>
-#include <xen/init.h>
-#include <xen/smp.h>
-#include <xen/console.h>
-#include <asm/apic.h>
-
-/* Printk isn't particularly safe just after we've trapped to the
-   debugger. so avoid it. */
-#define dbg_printk(...)
-
-static char opt_cdb[30] = "none";
-string_param("cdb", opt_cdb);
-
-struct xendbg_context {
-       int serhnd;
-       u8 reply_csum;
-       int currently_attached:1;
-};
-
-/* Like copy_from_user, but safe to call with interrupts disabled.
-
-   Trust me, and don't look behind the curtain. */
-static unsigned
-dbg_copy_from_user(void *dest, const void *src, unsigned len)
-{
-       int __d0, __d1, __d2;
-       ASSERT(!local_irq_is_enabled());
-       __asm__ __volatile__(
-               "1:     rep; movsb\n"
-               "2:\n"
-               ".section .fixup,\"ax\"\n"
-               "3:     addl $4, %%esp\n"
-               "       jmp 2b\n"
-               ".previous\n"
-               ".section __pre_ex_table,\"a\"\n"
-               "       .align 4\n"
-               "       .long 1b,3b\n"
-               ".previous\n"
-               ".section __ex_table,\"a\"\n"
-               "       .align 4\n"
-               "       .long 1b,2b\n"
-               ".previous\n"
-               : "=c"(__d2), "=D" (__d0), "=S" (__d1)
-               : "0"(len), "1"(dest), "2"(src)
-               : "memory");
-       ASSERT(!local_irq_is_enabled());
-       return __d2;
-}
-
-static void
-xendbg_put_char(u8 data, struct xendbg_context *ctx)
-{
-       ctx->reply_csum += data;
-       serial_putc(ctx->serhnd, data);
-}
-
-static int
-hex_char_val(unsigned char c)
-{
-       if (c >= '0' && c <= '9')
-               return c - '0';
-       else if (c >= 'a' && c <= 'f')
-               return c - 'a' + 10;
-       else if (c >= 'A' && c <= 'F')
-               return c - 'A' + 10;
-       else
-               BUG();
-       return -1;
-}
-
-/* Receive a command.  Returns -1 on csum error, 0 otherwise. */
-/* Does not acknowledge. */
-static int
-attempt_receive_packet(char *recv_buf, struct xendbg_context *ctx)
-{
-       int count;
-       u8 csum;
-       u8 received_csum;
-       u8 ch;
-
-       /* Skip over everything up to the first '$' */
-       while ((ch = serial_getc(ctx->serhnd)) != '$')
-               ;
-       csum = 0;
-       for (count = 0; count < 4096; count++) {
-               ch = serial_getc(ctx->serhnd);
-               if (ch == '#')
-                       break;
-               recv_buf[count] = ch;
-               csum += ch;
-       }
-       if (count == 4096) {
-               dbg_printk("WARNING: GDB sent a stupidly big packet.\n");
-               return -1;
-       }
-       recv_buf[count] = 0;
-       received_csum = hex_char_val(serial_getc(ctx->serhnd)) * 16 +
-               hex_char_val(serial_getc(ctx->serhnd));
-       if (received_csum == csum) {
-               return 0;
-       } else {
-               return -1;
-       }
-}
-
-/* Send a string of bytes to the debugger. */
-static void
-xendbg_send(const char *buf, int count, struct xendbg_context *ctx)
-{
-       int x;
-       for (x = 0; x < count; x++)
-               xendbg_put_char(buf[x], ctx);
-}
-
-/* Receive a command, discarding up to ten packets with csum
- * errors.  Acknowledges all received packets. */
-static int
-receive_command(char *recv_buf, struct xendbg_context *ctx)
-{
-       int r;
-       int count;
-
-       count = 0;
-       do {
-               r = attempt_receive_packet(recv_buf, ctx);
-               if (r < 0)
-                       xendbg_put_char('-', ctx);
-               else
-                       xendbg_put_char('+', ctx);
-               count++;
-       } while (r < 0 && count < 10);
-       return r;
-}
-
-static void
-xendbg_start_reply(struct xendbg_context *ctx)
-{
-       xendbg_put_char('$', ctx);
-       ctx->reply_csum = 0;
-}
-
-/* Return 0 if the reply was successfully received, !0 otherwise. */
-static int
-xendbg_finish_reply(struct xendbg_context *ctx)
-{
-       char ch;
-       char buf[3];
-
-       sprintf(buf, "%.02x\n", ctx->reply_csum);
-
-       xendbg_put_char('#', ctx);
-       xendbg_send(buf, 2, ctx);
-
-       ch = serial_getc(ctx->serhnd);
-       if (ch == '+')
-               return 0;
-       else
-               return 1;
-}
-
-/* Swap the order of the bytes in a work. */
-static inline unsigned
-bswab32(unsigned val)
-{
-       return (((val >> 0) & 0xff) << 24) |
-               (((val >> 8) & 0xff) << 16) |
-               (((val >> 16) & 0xff) << 8) |
-               (((val >> 24) & 0xff) << 0);
-}
-
-static int
-handle_memory_read_command(unsigned long addr, unsigned long length,
-                          struct xendbg_context *ctx)
-{
-       int x;
-       unsigned char val;
-       int r;
-       char buf[2];
-
-       dbg_printk("Memory read starting at %lx, length %lx.\n", addr,
-                  length);
-       xendbg_start_reply(ctx);
-       for (x = 0; x < length; x++) {
-               r = dbg_copy_from_user(&val, (void *)(addr + x), 1);
-               if (r != 0) {
-                       dbg_printk("Error reading from %lx.\n", addr + x);
-                       break;
-               }
-               sprintf(buf, "%.02x", val);
-               xendbg_send(buf, 2, ctx);
-       }
-       if (x == 0)
-               xendbg_send("E05", 3, ctx);
-       dbg_printk("Read done.\n");
-       return xendbg_finish_reply(ctx);
-}
-
-static int
-xendbg_send_reply(const char *buf, struct xendbg_context *ctx)
-{
-       xendbg_start_reply(ctx);
-       xendbg_send(buf, strlen(buf), ctx);
-       return xendbg_finish_reply(ctx);
-}
-
-static int
-handle_register_read_command(struct cpu_user_regs *regs, struct xendbg_context 
*ctx)
-{
-       char buf[121];
-
-       sprintf(buf,
-               
"%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x%.08x",
-               bswab32(regs->eax),
-               bswab32(regs->ecx),
-               bswab32(regs->edx),
-               bswab32(regs->ebx),
-               bswab32(regs->esp),
-               bswab32(regs->ebp),
-               bswab32(regs->esi),
-               bswab32(regs->edi),
-               bswab32(regs->eip),
-               bswab32(regs->eflags),
-               bswab32(regs->cs),
-               bswab32(regs->ss),
-               bswab32(regs->ds),
-               bswab32(regs->es),
-               bswab32(regs->fs),
-               bswab32(regs->gs));
-       return xendbg_send_reply(buf, ctx);
-}
-
-static int
-process_command(char *received_packet, struct cpu_user_regs *regs,
-               struct xendbg_context *ctx)
-{
-       char *ptr;
-       unsigned long addr, length;
-       int retry;
-       int counter;
-       int resume = 0;
-
-       /* Repeat until gdb acks the reply */
-       counter = 0;
-       do {
-               switch (received_packet[0]) {
-               case 'g': /* Read registers */
-                       retry = handle_register_read_command(regs, ctx);
-                       ASSERT(!local_irq_is_enabled());
-                       break;
-               case 'm': /* Read memory */
-                       addr = simple_strtoul(received_packet + 1, &ptr, 16);
-                       if (ptr == received_packet + 1 ||
-                           ptr[0] != ',') {
-                               xendbg_send_reply("E03", ctx);
-                               return 0;
-                       }
-                       length = simple_strtoul(ptr + 1, &ptr, 16);
-                       if (ptr[0] != 0) {
-                               xendbg_send_reply("E04", ctx);
-                               return 0;
-                       }
-                       retry =
-                               handle_memory_read_command(addr,
-                                                          length,
-                                                          ctx);
-                       ASSERT(!local_irq_is_enabled());
-                       break;
-               case 'G': /* Write registers */
-               case 'M': /* Write memory */
-                       retry = xendbg_send_reply("E02", ctx);
-                       break;
-               case 'D':
-                       resume = 1;
-                       ctx->currently_attached = 0;
-                       retry = xendbg_send_reply("", ctx);
-                       break;
-               case 'c': /* Resume at current address */
-                       ctx->currently_attached = 1;
-                       resume = 1;
-                       retry = 0;
-                       break;
-               case 'Z': /* We need to claim to support these or gdb
-                            won't let you continue the process. */
-               case 'z':
-                       retry = xendbg_send_reply("OK", ctx);
-                       break;
-
-               case 's': /* Single step */
-               case '?':
-                       retry = xendbg_send_reply("S01", ctx);
-                       break;
-               default:
-                       retry = xendbg_send_reply("", ctx);
-                       break;
-               }
-               counter++;
-       } while (retry == 1 && counter < 10);
-       if (retry) {
-               dbg_printk("WARNING: gdb disappeared when we were trying to 
send it a reply.\n");
-               return 1;
-       }
-       return resume;
-}
-
-static struct xendbg_context
-xdb_ctx = {
-       serhnd : -1
-};
-
-int
-__trap_to_cdb(struct cpu_user_regs *regs)
-{
-       int resume = 0;
-       int r;
-       static atomic_t xendbg_running = ATOMIC_INIT(1);
-       static char recv_buf[4096];
-       unsigned flags;
-
-       if (xdb_ctx.serhnd < 0) {
-               dbg_printk("Debugger not ready yet.\n");
-               return 0;
-       }
-
-       /* We rely on our caller to ensure we're only on one processor
-        * at a time... We should probably panic here, but given that
-        * we're a debugger we should probably be a little tolerant of
-        * things going wrong. */
-       /* We don't want to use a spin lock here, because we're doing
-          two distinct things:
-
-          1 -- we don't want to run on more than one processor at a time,
-               and
-          2 -- we want to do something sensible if we re-enter ourselves.
-
-          Spin locks are good for 1, but useless for 2. */
-       if (!atomic_dec_and_test(&xendbg_running)) {
-               printk("WARNING WARNING WARNING: Avoiding recursive xendbg.\n");
-               atomic_inc(&xendbg_running);
-               return 0;
-       }
-
-       smp_send_stop();
-
-       /* Try to make things a little more stable by disabling
-          interrupts while we're here. */
-       local_irq_save(flags);
-
-       watchdog_disable();
-       console_start_sync();
-
-       /* Shouldn't really do this, but otherwise we stop for no
-          obvious reason, which is Bad */
-       printk("Waiting for GDB to attach to XenDBG\n");
-
-       /* If gdb is already attached, tell it we've stopped again. */
-       if (xdb_ctx.currently_attached) {
-               do {
-                       r = xendbg_send_reply("S01", &xdb_ctx);
-               } while (r != 0);
-       }
-
-       while (resume == 0) {
-               ASSERT(!local_irq_is_enabled());
-               r = receive_command(recv_buf, &xdb_ctx);
-               ASSERT(!local_irq_is_enabled());
-               if (r < 0) {
-                       dbg_printk("GDB disappeared, trying to resume 
Xen...\n");
-                       resume = 1;
-               } else {
-                       ASSERT(!local_irq_is_enabled());
-                       resume = process_command(recv_buf, regs, &xdb_ctx);
-                       ASSERT(!local_irq_is_enabled());
-               }
-       }
-
-       console_end_sync();
-       watchdog_enable();
-       atomic_inc(&xendbg_running);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-static int
-initialize_xendbg(void)
-{
-       if (!strcmp(opt_cdb, "none"))
-               return 0;
-       xdb_ctx.serhnd = serial_parse_handle(opt_cdb);
-       if (xdb_ctx.serhnd == -1)
-               panic("Can't parse %s as CDB serial info.\n", opt_cdb);
-
-       /* Acknowledge any spurious GDB packets. */
-       xendbg_put_char('+', &xdb_ctx);
-
-       printk("Xendbg initialised.\n");
-       return 0;
-}
-
-__initcall(initialize_xendbg);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] Rename cdb to gdbstub and split it into arch dependent/neutral part., Xen patchbot -unstable <=