Hi.

Thanks for your review.
I updated the patch following your comments except
the interrupt-related related comment.
I included your signed-off-by to the patch, is it ok?


On Fri, Jan 13, 2006 at 09:46:04AM -0600, Hollis Blanchard wrote:

> Thanks Isaku! This whole patch has whitespace issues though; please 
> replace your tabs with 4 spaces.

untabified.


> >+    . = ALIGN(32);
> >+    __gdbstub_text_start = . ;
> >+    *(.gdbstub.text)
> >+    __gdbstub_text_end = .  ;
> >+    . = ALIGN(32)           ;
> ...
> >+/* Append this to the declaration of any function needed to be used by
> >+ * the gdb stub.  Any functions marked with this will not be allowed
> >+ * to have a breakpoint set in them. */
> >+#define __gdbstub __attribute__((section(".gdbstub.text")))
> 
> These make sense if we want to avoid setting a breakpoint in GDB stub 
> code or code called by the GDB stub, such as serial output. However, 
> these symbols aren't currently used. (You probably inherited this from 
> the PPC stub.) At least it's worth a TODO comment, possibly in 
> gdb_cmd_write_mem(): we shouldn't be writing to memory between those 
> two symbols.

added __gdbstub_text_start, __gdbstub_text_end declarations and
a comment above gdb_cmd_write_mem()


> >+/* XXX move to some shared location... */
> >+char
> >+hex2char(unsigned long x)
> 
> With hex2char, char2hex, str2hex, str2ulong, I expect that they will be 
> needed in the arch-specific gdb backends. Actually I guess they just 
> need to be added to gdbstub.h; I'm not sure why I added that comment.

added protptypes to gdb.h and removed two XXX comments.


> >+    for (ctx->in_bytes = 0; ctx->in_bytes < sizeof(ctx->in_buf); 
> >ctx->in_bytes++) {
> Exceeds 80 chars.

fixed.


> >+#ifdef CONFIG_GDB_NO_CSUM
> >+    return 0;
> >+#else
> >+    if (received_csum == csum) {
> >+            return 0;
> >+    } else {
> >+            return -1;
> >+    }
> >+#endif
> What is this about? As far as I know, the GDB protocol unconditionally 
> requires the checksum.

removed.


> >+    //XXX optimization to use best native load size
> ...
> >+    //XXX optimization to use best native store size
> I think it's reasonable to leave it up to the arch code to decide what 
> size access to use, so these comments could go.

removed these comments.


> >+    .signum                         = 1,
> >+
> >+    .in_bytes                       = 0,
> >+
> >+    .out_offset                     = 0,
> 
> Blank lines.

removed blank lines.


> >+    /* Try to make things a little more stable by disabling
> >+       interrupts while we're here. */
> >+    local_irq_save(flags);
> ...
> >+    local_irq_restore(flags);
> Shouldn't we enter __trap_to_gdb with interrupts disabled already? 
> That's how it's done on PPC, I believe x86 can choose in the IDT, and 
> I'm sure IA64 can too?

Left as it was. 
As Keir explained, it is a good safe guard.

-- 
yamahata
# HG changeset patch
# User [EMAIL PROTECTED]
# Node ID 3ca0840ea69e85a5693220b54e17368c8b6ddf69
# Parent  9d72a5b18107a3482157b2d6b816a4324a5f8ad4
clean up cdb.
renamed cdb to gdbstub and split it into arch dependent/neutral part.

Signed-off-by: Isaku Yamahata <[EMAIL PROTECTED]>
Signed-off-by: Hollis Blanchard <[EMAIL PROTECTED]>

diff -r 9d72a5b18107 -r 3ca0840ea69e xen/arch/x86/Makefile
--- a/xen/arch/x86/Makefile     Sat Jan 14 01:04:06 2006 +0100
+++ b/xen/arch/x86/Makefile     Sat Jan 14 10:39:43 2006 +0900
@@ -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 9d72a5b18107 -r 3ca0840ea69e xen/arch/x86/x86_32/xen.lds.S
--- a/xen/arch/x86/x86_32/xen.lds.S     Sat Jan 14 01:04:06 2006 +0100
+++ b/xen/arch/x86/x86_32/xen.lds.S     Sat Jan 14 10:39:43 2006 +0900
@@ -21,6 +21,11 @@
   _text = .;                   /* Text and read-only data */
   .text : {
        *(.text)
+       . = ALIGN(32);
+       __gdbstub_text_start = .; 
+       *(.gdbstub.text)
+       __gdbstub_text_end = .; 
+       . = ALIGN(32); 
        *(.fixup)
        *(.gnu.warning)
        } :text =0x9090
diff -r 9d72a5b18107 -r 3ca0840ea69e xen/common/Makefile
--- a/xen/common/Makefile       Sat Jan 14 01:04:06 2006 +0100
+++ b/xen/common/Makefile       Sat Jan 14 10:39:43 2006 +0900
@@ -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 9d72a5b18107 -r 3ca0840ea69e xen/include/asm-x86/debugger.h
--- a/xen/include/asm-x86/debugger.h    Sat Jan 14 01:04:06 2006 +0100
+++ b/xen/include/asm-x86/debugger.h    Sat Jan 14 10:39:43 2006 +0900
@@ -42,19 +42,19 @@
 
 #if defined(CRASH_DEBUG)
 
-extern int __trap_to_cdb(struct cpu_user_regs *r);
+#include <xen/gdb.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 9d72a5b18107 -r 3ca0840ea69e xen/arch/x86/gdbstub.c
--- /dev/null   Thu Jan  1 00:00:00 1970 +0000
+++ b/xen/arch/x86/gdbstub.c    Sat Jan 14 10:39:43 2006 +0900
@@ -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 __gdbstub
+gdb_arch_signal_num(struct cpu_user_regs *regs, unsigned long cookie)
+{
+    // XXX
+    return 1;
+}
+
+void __gdbstub 
+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 __gdbstub 
+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 __gdbstub 
+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 __gdbstub 
+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 __gdbstub 
+gdb_arch_copy_to_user(void *dest, const void *src, unsigned len)
+{
+    // XXX
+    return len;
+}
+
+void __gdbstub 
+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 __gdbstub
+gdb_arch_print_state(struct cpu_user_regs *regs)
+{
+    // XXX
+}
+
+void __gdbstub
+gdb_arch_enter(struct cpu_user_regs *regs)
+{
+    // nothing
+}
+
+void __gdbstub
+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 9d72a5b18107 -r 3ca0840ea69e xen/common/gdbstub.c
--- /dev/null   Thu Jan  1 00:00:00 1970 +0000
+++ b/xen/common/gdbstub.c      Sat Jan 14 10:39:43 2006 +0900
@@ -0,0 +1,589 @@
+/*
+ * Copyright (C) 2005 Jimi Xenidis <[EMAIL PROTECTED]>, 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.
+ */
+/* 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>
+
+/* 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 __gdbstub
+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 __gdbstub
+gdb_io_write_char(u8 data, struct gdb_context *ctx)
+{
+    return gdb_io_write((char*)&data, 1, ctx);
+}
+
+static unsigned char __gdbstub
+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 __gdbstub 
+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)) != '$')
+        ;
+    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));
+    if (received_csum == csum) {
+        return 0;
+    } else {
+        return -1;
+    }
+}
+
+/* Receive a command, discarding up to ten packets with csum
+ * errors.  Acknowledges all received packets. */
+static int __gdbstub 
+receive_command(struct gdb_context *ctx)
+{
+    int r;
+    int count;
+
+    count = 0;
+    do {
+        r = attempt_receive_packet(ctx);
+        if (r < 0)
+            gdb_io_write_char('-', ctx);
+        else
+            gdb_io_write_char('+', ctx);
+        count++;
+    } while (r < 0 && count < GDB_RETRY_MAX);
+    return r;
+}
+
+/* routines to send reply packets */
+
+static void __gdbstub 
+gdb_start_packet(struct gdb_context *ctx)
+{
+    ctx->out_buf[0] = '$';
+    ctx->out_offset = 1;
+    ctx->out_csum = 0;
+}
+
+static void __gdbstub 
+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 __gdbstub 
+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 __gdbstub 
+gdb_write_to_packet_str(const char *buf, struct gdb_context *ctx)
+{
+    gdb_write_to_packet(buf, strlen(buf), ctx);
+}
+
+void __gdbstub
+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;
+    buf[sizeof (unsigned long) * 2] = 0;
+    int width = int_size * 2;
+
+    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 {
+        --i;
+        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 __gdbstub
+gdb_check_ack(struct gdb_context *ctx)
+{
+    u8 c;
+
+    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 __gdbstub 
+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 __gdbstub 
+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 __gdbstub 
+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 __gdbstub 
+gdb_cmd_read_mem(unsigned long addr, unsigned long length,
+                 struct gdb_context *ctx)
+{
+    int x;
+    unsigned char val;
+    int r;
+
+    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);
+}
+
+/*
+ * XXX TODO
+ * prevent from writing to the area [__gdbstub_text_start, __gdbstub_text_end]
+ */ 
+static void __gdbstub 
+gdb_cmd_write_mem(unsigned long addr, unsigned long length,
+                  const char *buf, struct gdb_context *ctx)
+{
+    int x;
+    unsigned char val;
+    int r;
+
+    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;
+        }
+    }
+    if (x != length) {
+        gdb_write_to_packet_str("OK", ctx);
+    } else {
+        gdb_write_to_packet_str("E11", ctx);
+    }
+    dbg_printk("Write done.\n");
+    gdb_send_packet(ctx);
+}
+
+/* command dispatcher */
+static int __gdbstub 
+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 __gdbstub 
+__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);
+
+/*
+ * XXX
+ */
+static unsigned long __gdbstub
+_lib_gdb_xlate_ea(unsigned long eaddr)
+{
+    return eaddr;
+}
+extern unsigned long __gdbstub gdb_xlate_ea(unsigned long eaddr)
+    __attribute__ ((weak, alias("_lib_gdb_xlate_ea")));
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -r 9d72a5b18107 -r 3ca0840ea69e xen/include/xen/gdb.h
--- /dev/null   Thu Jan  1 00:00:00 1970 +0000
+++ b/xen/include/xen/gdb.h     Sat Jan 14 10:39:43 2006 +0900
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2005 Hollis Blanchard <[EMAIL PROTECTED]>, 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_GDB_H__
+#define __XEN_GDB_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); 
+
+/* Append this to the declaration of any function needed to be used by
+ * the gdb stub.  Any functions marked with this will not be allowed
+ * to have a breakpoint set in them. */
+#define __gdbstub __attribute__((section(".gdbstub.text")))
+extern const void* __gdbstub_text_start;
+extern const void* __gdbstub_text_end;
+
+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 __gdbstub gdb_write_to_packet(const char *buf, int count, struct 
gdb_context *ctx);
+void __gdbstub gdb_write_to_packet_hex(unsigned long x, int int_size, struct 
gdb_context *ctx);
+void __gdbstub gdb_send_packet(struct gdb_context *ctx); 
+void __gdbstub gdb_send_reply(const char *buf, struct gdb_context *ctx);
+
+/* gdb stub trap handler: entry point */
+int __gdbstub __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie);
+
+/* arch specific routines */
+u16 __gdbstub gdb_arch_signal_num(struct cpu_user_regs *regs, unsigned long 
cookie);
+void __gdbstub gdb_arch_read_reg_array(struct cpu_user_regs *regs, struct 
gdb_context *ctx);
+void __gdbstub gdb_arch_write_reg_array(struct cpu_user_regs *regs, const 
char* buf, struct gdb_context *ctx);
+void __gdbstub gdb_arch_read_reg(unsigned long regnum, struct cpu_user_regs 
*regs, struct gdb_context *ctx);
+unsigned int __gdbstub gdb_arch_copy_from_user(void *dest, const void *src, 
unsigned len);
+unsigned int __gdbstub gdb_arch_copy_to_user(void *dest, const void *src, 
unsigned len);
+void __gdbstub gdb_arch_resume(struct cpu_user_regs *regs, unsigned long addr, 
unsigned long type, struct gdb_context *ctx);
+void __gdbstub gdb_arch_print_state(struct cpu_user_regs *regs);
+void __gdbstub gdb_arch_enter(struct cpu_user_regs *regs);
+void __gdbstub 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_GDB_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -r 9d72a5b18107 -r 3ca0840ea69e xen/arch/x86/cdb.c
--- a/xen/arch/x86/cdb.c        Sat Jan 14 01:04:06 2006 +0100
+++ /dev/null   Thu Jan  1 00:00:00 1970 +0000
@@ -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-ia64-devel mailing list
Xen-ia64-devel@lists.xensource.com
http://lists.xensource.com/xen-ia64-devel

Reply via email to