All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lubomir Rintel <lkundrak@v3.sk>
To: grub-devel@gnu.org
Subject: [PATCH] Remote GDB debugging stub (for i386)
Date: Thu, 01 May 2008 15:12:25 +0200	[thread overview]
Message-ID: <1209647545.3433.14.camel@localhost.localdomain> (raw)

[-- Attachment #1: Type: text/plain, Size: 2040 bytes --]

Re-sending the GDB stub patch. The GDB protocol part, though being
largely rewritten, originates from GDB source tarball, which refers to
it as a Public Domain code.

Applies against today's CVS.

Is not much of use without debugging symbols, part 2 of patch [1]
preserves those. Neither is it of much use without being able to resolve
load addresses of modules, I will submit the GDB scripts shortly.

[1] http://lists.gnu.org/archive/html/grub-devel/2008-04/msg00080.html

Note that I found this hunk [2] lying around from 2006 when I wrote this
on NetBSD. I am not completely sure what does it do, but the changelog
from then suggests, that "grub_gdb_trapvec" from the gdb module was for
some reason resolved to 0 instead of its actual address. It might have
been dependent on the toolchain used, as I am not able to reproduce the
behavior on current Fedora 9.

[2] http://pastebin.com/f5c791966

2008-05-01:  Lubomir Rintel  <lkundrak@v3.sk>

        * conf/i386-pc.rmk: Add gdb module to the list of modules to be built.

        * term/i386/pc/serial.c (serial_hw_put): Let some useful serial
        driver functions be exported.
        (grub_serial_getkey): Likewise

        * kern/dl.c (grub_dl_resolve_symbols): Let the trapvec symbol be
        resolved correctly (instead of 0).

        * kern/i386/pc/startup.S: (prot_idt) Add region descriptor to hold
        protected mode IDT.
        (real_idt) IDT region dsecriptor that works in real mode
        (real_to_prot) Load protected mode idt IDT when returning to
        protected mode.

        * kern/i386/realmode.S: (prot_to_real) Save protected mode IDT and load
        real mode one before switching to real mode.

        * gdb/cstub.c: New file.
        * gdb/gdb.c:  New file.
        * gdb/i386/idt.c: New file.
        * gdb/i386/signal.c: New file.
        * gdb/i386/machdep.S: New file.
        * include/grub/gdb.h: New file.
        * include/grub/i386/gdb.h: New file.
        * include/grub/i386/pc/kernel.h: New file.

--
Lubomir Rintel (Was: Kundrak)

[-- Attachment #2: grub2-gdb-stub-v3.patch --]
[-- Type: text/x-patch, Size: 27666 bytes --]

2008-05-01:  Lubomir Rintel  <lkundrak@v3.sk>

        * conf/i386-pc.rmk: Add gdb module to the list of modules to be built.

        * term/i386/pc/serial.c (serial_hw_put): Let some useful serial
        driver functions be exported.
        (grub_serial_getkey): Likewise

        * kern/dl.c (grub_dl_resolve_symbols): Let the trapvec symbol be
        resolved correctly (instead of 0).

        * kern/i386/pc/startup.S: (prot_idt) Add region descriptor to hold
        protected mode IDT.
        (real_idt) IDT region dsecriptor that works in real mode
        (real_to_prot) Load protected mode idt IDT when returning to
        protected mode.

        * kern/i386/realmode.S: (prot_to_real) Save protected mode IDT and load
        real mode one before switching to real mode.

        * gdb/cstub.c: New file.
        * gdb/gdb.c:  New file.
        * gdb/i386/idt.c: New file.
        * gdb/i386/signal.c: New file.
        * gdb/i386/machdep.S: New file.
        * include/grub/gdb.h: New file.
        * include/grub/i386/gdb.h: New file.
        * include/grub/i386/pc/kernel.h: New file.

--- grub2/conf/i386-pc.rmk	2008-03-31 13:17:59.000000000 +0200
+++ grub2-gdb/conf/i386-pc.rmk	2008-05-01 12:11:48.000000000 +0200
@@ -155,7 +155,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod
 	vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \
 	videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod	\
 	ata.mod vga.mod memdisk.mod jpeg.mod png.mod pci.mod lspci.mod \
-	aout.mod _bsd.mod bsd.mod
+	aout.mod _bsd.mod bsd.mod gdb.mod
 
 # For biosdisk.mod.
 biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c
@@ -322,4 +322,11 @@ bsd_mod_SOURCES = loader/i386/bsd_normal
 bsd_mod_CFLAGS = $(COMMON_CFLAGS)
 bsd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For gdb.mod
+gdb_mod_SOURCES = gdb/cstub.c gdb/gdb.c gdb/i386/idt.c \
+	gdb/i386/machdep.S gdb/i386/signal.c
+gdb_mod_CFLAGS = $(COMMON_CFLAGS)
+gdb_mod_LDFLAGS = $(COMMON_LDFLAGS)
+gdb_mod_ASFLAGS = $(COMMON_ASFLAGS)
+
 include $(srcdir)/conf/common.mk
--- grub2/gdb/cstub.c	1970-01-01 01:00:00.000000000 +0100
+++ grub2-gdb/gdb/cstub.c	2008-05-01 10:57:57.000000000 +0200
@@ -0,0 +1,362 @@
+/* cstub.c - machine independent portion of remote GDB stub */
+/*
+ *  Copyright (C) 2006  Lubomir Kundrak
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/misc.h>
+#include <grub/cpu/gdb.h>
+#include <grub/gdb.h>
+
+static const char hexchars[] = "0123456789abcdef";
+int grub_gdb_regs[GRUB_MACHINE_NR_REGS];
+
+#define GRUB_GDB_COMBUF_SIZE 400	/* At least sizeof(grub_gdb_regs)*2 are needed for
+					   register packets.  */
+static char grub_gdb_inbuf[GRUB_GDB_COMBUF_SIZE];
+static char grub_gdb_outbuf[GRUB_GDB_COMBUF_SIZE];
+
+int (*grub_gdb_getchar) ();
+void (*grub_gdb_putchar) (int);
+
+static int
+hex (ch)
+     char ch;
+{
+  if ((ch >= 'a') && (ch <= 'f'))
+    return (ch - 'a' + 10);
+  if ((ch >= '0') && (ch <= '9'))
+    return (ch - '0');
+  if ((ch >= 'A') && (ch <= 'F'))
+    return (ch - 'A' + 10);
+  return (-1);
+}
+
+/* Scan for the sequence $<data>#<checksum>.  */
+static char *
+grub_gdb_getpacket (void)
+{
+  char *buffer = &grub_gdb_inbuf[0];
+  unsigned char checksum;
+  unsigned char xmitcsum;
+  int count;
+  char ch;
+
+  while (1)
+    {
+      /* Wait around for the start character, ignore all other
+         characters.  */
+      while ((ch = grub_gdb_getchar ()) != '$');
+
+    retry:
+      checksum = 0;
+      xmitcsum = -1;
+      count = 0;
+
+      /* Now read until a # or end of buffer is found.  */
+      while (count < GRUB_GDB_COMBUF_SIZE)
+	{
+	  ch = grub_gdb_getchar ();
+	  if (ch == '$')
+	    goto retry;
+	  if (ch == '#')
+	    break;
+	  checksum += ch;
+	  buffer[count] = ch;
+	  count = count + 1;
+	}
+      buffer[count] = 0;
+
+      if (ch == '#')
+	{
+	  ch = grub_gdb_getchar ();
+	  xmitcsum = hex (ch) << 4;
+	  ch = grub_gdb_getchar ();
+	  xmitcsum += hex (ch);
+
+	  if (checksum != xmitcsum)
+	    {
+	      grub_dprintf ("gdb",
+			    "bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
+			    checksum, xmitcsum, buffer);
+	      grub_gdb_putchar ('-');	/* Failed checksum.  */
+	    }
+	  else
+	    {
+	      grub_gdb_putchar ('+');	/* Successful transfer.  */
+
+	      /* If a sequence char is present, reply the sequence ID.  */
+	      if (buffer[2] == ':')
+		{
+		  grub_gdb_putchar (buffer[0]);
+		  grub_gdb_putchar (buffer[1]);
+
+		  return &buffer[3];
+		}
+	      return &buffer[0];
+	    }
+	}
+    }
+}
+
+/* Send the packet in buffer.  */
+static void
+grub_gdb_putpacket (char *buffer)
+{
+  unsigned char checksum;
+  int count;
+  char ch;
+
+  /* $<packet info>#<checksum>.  */
+  do
+    {
+      grub_gdb_putchar ('$');
+      checksum = 0;
+      count = 0;
+
+      while ((ch = buffer[count]))
+	{
+	  grub_gdb_putchar (ch);
+	  checksum += ch;
+	  count += 1;
+	}
+
+      grub_gdb_putchar ('#');
+      grub_gdb_putchar (hexchars[checksum >> 4]);
+      grub_gdb_putchar (hexchars[checksum % 16]);
+    }
+  while (grub_gdb_getchar () != '+');
+}
+
+/* Convert the memory pointed to by mem into hex, placing result in buf.
+   Return a pointer to the last char put in buf (NULL).  */
+static char *
+grub_gdb_mem2hex (char *mem, char *buf, int count)
+{
+  int i;
+  unsigned char ch;
+
+  for (i = 0; i < count; i++)
+    {
+      ch = *mem++;
+      *buf++ = hexchars[ch >> 4];
+      *buf++ = hexchars[ch % 16];
+    }
+  *buf = 0;
+  return (buf);
+}
+
+/* Convert the hex array pointed to by buf into binary to be placed in mem.
+   Return a pointer to the character after the last byte written.  */
+static char *
+grub_gdb_hex2mem (char *buf, char *mem, int count)
+{
+  int i;
+  unsigned char ch;
+
+  for (i = 0; i < count; i++)
+    {
+      ch = hex (*buf++) << 4;
+      ch = ch + hex (*buf++);
+      *mem++ = ch;
+    }
+  return (mem);
+}
+
+/* Convert hex characters to int and return the number of characters
+   processed.  */
+static int
+grub_gdb_hex2int (char **ptr, int *int_value)
+{
+  int num_chars = 0;
+  int hex_value;
+
+  *int_value = 0;
+
+  while (**ptr)
+    {
+      hex_value = hex (**ptr);
+      if (hex_value >= 0)
+	{
+	  *int_value = (*int_value << 4) | hex_value;
+	  num_chars++;
+	}
+      else
+	break;
+
+      (*ptr)++;
+    }
+
+  return (num_chars);
+}
+
+/* This function does all command procesing for interfacing to gdb.  */
+void
+grub_gdb_trap (int trap_no)
+{
+  int sig_no;
+  int stepping;
+  int addr;
+  int length;
+  char *ptr;
+  int newPC;
+
+  sig_no = grub_gdb_trap2sig (trap_no);
+
+  ptr = grub_gdb_outbuf;
+
+  /* Reply to host that an exception has occurred.  */
+
+  *ptr++ = 'T';	/* Notify gdb with signo, PC, FP and SP.  */
+
+  *ptr++ = hexchars[sig_no >> 4];
+  *ptr++ = hexchars[sig_no & 0xf];
+
+  /* Stack pointer.  */
+  *ptr++ = hexchars[SP];
+  *ptr++ = ':';
+  ptr = grub_gdb_mem2hex ((char *) &grub_gdb_regs[ESP], ptr, 4);
+  *ptr++ = ';';
+
+  /* Frame pointer.  */
+  *ptr++ = hexchars[FP];
+  *ptr++ = ':';
+  ptr = grub_gdb_mem2hex ((char *) &grub_gdb_regs[EBP], ptr, 4);
+  *ptr++ = ';';
+
+  /* Program counter.  */
+  *ptr++ = hexchars[PC];
+  *ptr++ = ':';
+  ptr = grub_gdb_mem2hex ((char *) &grub_gdb_regs[PC], ptr, 4);
+  *ptr++ = ';';
+
+  *ptr = '\0';
+
+  grub_gdb_putpacket (grub_gdb_outbuf);
+
+  stepping = 0;
+
+  while (1 == 1)
+    {
+      grub_gdb_outbuf[0] = 0;
+      ptr = grub_gdb_getpacket ();
+
+      switch (*ptr++)
+	{
+	case '?':
+	  grub_gdb_outbuf[0] = 'S';
+	  grub_gdb_outbuf[1] = hexchars[sig_no >> 4];
+	  grub_gdb_outbuf[2] = hexchars[sig_no % 16];
+	  grub_gdb_outbuf[3] = 0;
+	  break;
+
+	/* Return values of the CPU registers.  */
+	case 'g':
+	  grub_gdb_mem2hex ((char *) grub_gdb_regs, grub_gdb_outbuf,
+			    sizeof (grub_gdb_regs));
+	  break;
+
+	/* Set values of the CPU registers -- return OK.  */
+	case 'G':
+	  grub_gdb_hex2mem (ptr, (char *) grub_gdb_regs,
+			    sizeof (grub_gdb_regs));
+	  grub_strcpy (grub_gdb_outbuf, "OK");
+	  break;
+
+	/* Set the value of a single CPU register -- return OK.  */
+	case 'P':
+	  {
+	    int regno;
+
+	    if (grub_gdb_hex2int (&ptr, &regno) && *ptr++ == '=')
+	      if (regno >= 0 && regno < GRUB_MACHINE_NR_REGS)
+		{
+		  grub_gdb_hex2mem (ptr, (char *) &grub_gdb_regs[regno], 4);
+		  grub_strcpy (grub_gdb_outbuf, "OK");
+		  break;
+		}
+	    grub_strcpy (grub_gdb_outbuf, "E01");
+	    break;
+	  }
+
+	/* mAA..AA,LLLL: Read LLLL bytes at address AA..AA.  */
+	case 'm':
+	  /* Try to read %x,%x.  Set ptr = 0 if successful.  */
+	  if (grub_gdb_hex2int (&ptr, &addr))
+	    if (*(ptr++) == ',')
+	      if (grub_gdb_hex2int (&ptr, &length))
+		{
+		  ptr = 0;
+		  grub_gdb_mem2hex ((char *) addr, grub_gdb_outbuf, length);
+		}
+	  if (ptr)
+	    {
+	      grub_strcpy (grub_gdb_outbuf, "E01");
+	    }
+	  break;
+
+	/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA -- return OK.  */
+	case 'M':
+	  /* Try to read %x,%x.  Set ptr = 0 if successful.  */
+	  if (grub_gdb_hex2int (&ptr, &addr))
+	    if (*(ptr++) == ',')
+	      if (grub_gdb_hex2int (&ptr, &length))
+		if (*(ptr++) == ':')
+		  {
+		    grub_gdb_hex2mem (ptr, (char *) addr, length);
+		    grub_strcpy (grub_gdb_outbuf, "OK");
+		    ptr = 0;
+		  }
+	  if (ptr)
+	    {
+	      grub_strcpy (grub_gdb_outbuf, "E02");
+	    }
+	  break;
+
+	/* sAA..AA: Step one instruction from AA..AA(optional).  */
+	case 's':
+	  stepping = 1;
+
+	/* cAA..AA: Continue at address AA..AA(optional).  */
+	case 'c':
+	  /* try to read optional parameter, pc unchanged if no parm */
+	  if (grub_gdb_hex2int (&ptr, &addr))
+	    grub_gdb_regs[PC] = addr;
+
+	  newPC = grub_gdb_regs[PC];
+
+	  /* Clear the trace bit.  */
+	  grub_gdb_regs[PS] &= 0xfffffeff;
+
+	  /* Set the trace bit if we're stepping.  */
+	  if (stepping)
+	    grub_gdb_regs[PS] |= 0x100;
+
+	  return;
+	  break;
+
+	/* Kill the program.  */
+	case 'k':
+	  /* Do nothing.  */
+	  return;
+	  break;
+	}
+
+      /* Reply to the request.  */
+      grub_gdb_putpacket (grub_gdb_outbuf);
+    }
+}
+
--- grub2/gdb/gdb.c	1970-01-01 01:00:00.000000000 +0100
+++ grub2-gdb/gdb/gdb.c	2008-05-01 10:57:57.000000000 +0200
@@ -0,0 +1,61 @@
+/* gdb.c - gdb remote stub module */
+/*
+ *  Copyright (C) 2003  Free Software Foundation, Inc.
+ *  Copyright (C) 2006  Lubomir Kundrak
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/normal.h>
+#include <grub/term.h>
+#include <grub/cpu/gdb.h>
+#include <grub/gdb.h>
+
+extern int grub_serial_getkey ();
+extern void serial_hw_put (int);
+
+static grub_err_t
+grub_cmd_break (struct grub_arg_list *state __attribute__ ((unused)),
+		int argc __attribute__ ((unused)),
+		char **args __attribute__ ((unused)))
+{
+  grub_printf ("Now connect the remote debugger, please.\n");
+  grub_gdb_breakpoint ();
+  return 0;
+}
+
+GRUB_MOD_INIT (gdb)
+{
+  (void) mod;			/* To stop warning.  */
+
+  grub_gdb_getchar = &grub_serial_getkey;
+  grub_gdb_putchar = &serial_hw_put;
+
+  grub_gdb_idtinit ();
+  grub_register_command ("break", grub_cmd_break, GRUB_COMMAND_FLAG_BOTH,
+			 "break", "Break into debugger", 0);
+}
+
+GRUB_MOD_FINI (gdb)
+{
+  grub_unregister_command ("break");
+  /* FIXME: restore old IDTR.  */
+}
+
--- grub2/gdb/i386/idt.c	1970-01-01 01:00:00.000000000 +0100
+++ grub2-gdb/gdb/i386/idt.c	2008-05-01 10:57:57.000000000 +0200
@@ -0,0 +1,61 @@
+/* idt.c - routines for constructing IDT fot the GDB stub */
+/*
+ *  Copyright (C) 2006  Lubomir Kundrak
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/machine/memory.h>
+#include <grub/misc.h>
+#include <grub/cpu/gdb.h>
+#include <grub/gdb.h>
+
+struct gate grub_gdb_idt[GRUB_GDB_LAST_TRAP + 1];
+
+/* Sets up a gate descriptor in the IDT table.  */
+static void
+grub_idt_gate (struct gate *gate, void (*offset) (), int selector,
+               int type, int dpl)
+{
+  gate->offset_lo = (int) offset & 0xffff;
+  gate->selector = selector & 0xffff;
+  gate->xx = 0;
+  gate->type = type & 0x1f;
+  gate->dpl = dpl & 0x3;
+  gate->present = 1;
+  gate->offset_hi = ((int) offset >> 16) & 0xffff;
+}
+
+/* Set up interrupt and trap handler descriptors in IDT.  */
+void
+grub_gdb_idtinit ()
+{
+  int i;
+  struct region r;
+
+  for (i = 0; i <= GRUB_GDB_LAST_TRAP; i++)
+    {
+      grub_idt_gate (&grub_gdb_idt[i],
+		     grub_gdb_trapvec[i],
+		     GRUB_MEMORY_MACHINE_PROT_MODE_CSEG,
+                     GRUB_CPU_TRAP_GATE, 0);
+    }
+
+  r.base = (int) grub_gdb_idt;
+  r.limit = sizeof (grub_gdb_idt) - 1;
+
+  grub_idt_load (&r);
+}
+
--- grub2/gdb/i386/machdep.S	1970-01-01 01:00:00.000000000 +0100
+++ grub2-gdb/gdb/i386/machdep.S	2008-05-01 10:57:57.000000000 +0200
@@ -0,0 +1,193 @@
+/* machdep.S - machine dependent assembly routines for the GDB stub */
+/*
+ *  Copyright (C) 2006  Lubomir Kundrak
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define ASM	1
+#include <grub/cpu/gdb.h>
+
+#define EC_PRESENT	1
+#define EC_ABSENT	0
+
+#define GRUB_GDB_STACKSIZE	40000
+
+/*
+ * The .data index for the address vector.
+ */
+
+#define	VECTOR		1
+
+.globl grub_gdb_trap
+.globl grub_gdb_regs
+
+.data
+.globl grub_gdb_stack
+.space GRUB_GDB_STACKSIZE
+grub_gdb_stack:
+
+/*
+ * Supplemental macros for register saving/restoration
+ * on exception handler entry/leave.
+ */
+
+.macro save32 reg ndx
+	movl \reg, grub_gdb_regs+(\ndx * 4)
+.endm
+
+.macro save16 reg ndx
+	mov $0, %eax
+	movw \reg, grub_gdb_regs+(\ndx * 4)
+	movw %ax, grub_gdb_regs+(\ndx * 4 + 2)
+	movl grub_gdb_regs+(EAX * 4), %eax
+.endm
+
+.macro load32 ndx reg
+	movl grub_gdb_regs+(\ndx * 4), \reg
+.endm
+
+.macro load16 ndx reg
+	movw grub_gdb_regs+(\ndx * 4), \reg
+.endm
+
+.macro save_context
+	save32 %eax EAX
+	save32 %ecx ECX
+	save32 %edx EDX
+	save32 %ebx EBX
+	save32 %ebp EBP
+	save32 %esi ESI
+	save32 %edi EDI
+
+	popl %ebx
+	save32 %ebx EIP
+	popl %ebx
+	save32 %ebx CS
+	popl %ebx
+	save32 %ebx EFLAGS
+
+	save32 %esp ESP
+
+	save16 %ds DS
+	save16 %es ES
+	save16 %fs FS
+	save16 %gs GS
+	save16 %ss SS
+.endm
+
+.macro load_context
+	load16 SS %ss
+	load32 ESP %esp
+
+	load32 EBP %ebp
+	load32 ESI %esi
+	load32 EDI %edi
+
+	load16 DS %ds
+	load16 ES %es
+	load16 FS %fs
+	load16 GS %gs
+
+	load32 EFLAGS %eax
+	pushl %eax
+	load32 CS %eax
+	pushl %eax
+	load32 EIP %eax
+	pushl %eax
+
+	load32 EBX %ebx
+	load32 EDX %edx
+	load32 ECX %ecx
+	load32 EAX %eax
+.endm
+
+/*
+ * This macro creates handlers for a given range of exception numbers
+ * and adds their addresses to the grub_gdb_trapvec array.
+ */
+
+.macro ent ec beg end=0
+
+	/*
+	 * Wrapper body itself.
+	 */
+
+	.text
+1:	
+	.if \ec
+		add $4,%esp
+	.endif
+
+	save_context
+	mov	$grub_gdb_stack, %esp
+	mov	$\beg, %eax	/* trap number */
+	call	grub_gdb_trap
+	load_context
+	iret
+
+	/*
+	 * Address entry in trapvec array.
+	 */
+
+	.data VECTOR
+	.long 1b
+
+	/*
+	 * Next... (recursion).
+	 */
+
+	.if \end-\beg > 0
+		ent \ec "(\beg+1)" \end
+	.endif
+.endm
+
+/*
+ * Here does the actual construction of the address array and handlers
+ * take place.
+ */
+
+.data VECTOR
+.globl grub_gdb_trapvec
+grub_gdb_trapvec:
+	ent EC_ABSENT	0 7
+	ent EC_PRESENT	8
+	ent EC_ABSENT	9
+	ent EC_PRESENT	10 14
+	/*
+	 * You may have to split this further or as(1)
+	 * will complain about nesting being too deep.
+	 */
+	ent EC_ABSENT	15 GRUB_GDB_LAST_TRAP
+
+/*
+ * Random stuff
+ */
+
+.text
+.globl grub_gdb_breakpoint
+grub_gdb_breakpoint:
+	int $3
+	ret
+
+.globl grub_idt_load
+grub_idt_load:
+        lidt    (%eax)
+        ret
+
+.end
+
+OMG, Bunnies!
+
--- grub2/gdb/i386/signal.c	1970-01-01 01:00:00.000000000 +0100
+++ grub2-gdb/gdb/i386/signal.c	2008-05-01 10:57:57.000000000 +0200
@@ -0,0 +1,53 @@
+/* idt.c - routines for constructing IDT fot the GDB stub */
+/*
+ *  Copyright (C) 2006  Lubomir Kundrak
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/machine/memory.h>
+#include <grub/misc.h>
+#include <grub/cpu/gdb.h>
+#include <grub/gdb.h>
+
+/* Converting CPU trap number to UNIX signal number as
+   described in System V ABI i386 Processor Supplement, 3-25.  */
+int
+grub_gdb_trap2sig (int trap_no)
+{
+  int signals[] = {
+    SIGFPE,			/* 0:   Divide error fault              */
+    SIGTRAP,			/* 1:   Single step trap fault          */
+    SIGABRT,			/* 2:   # Nonmaskable interrupt         */
+    SIGTRAP,			/* 3:   Breakpoint trap                 */
+    SIGSEGV,			/* 4:   Overflow trap                   */
+    SIGSEGV,			/* 5:   Bounds check fault              */
+    SIGILL,			/* 6:   Invalid opcode fault            */
+    SIGFPE,			/* 7:   No coprocessor fault            */
+    SIGABRT,			/* 8:   # Double fault abort            */
+    SIGSEGV,			/* 9:   Coprocessor overrun abort       */
+    SIGSEGV,			/* 10:  Invalid TSS fault               */
+    SIGSEGV,			/* 11:  Segment not present fault       */
+    SIGSEGV,			/* 12:  Stack exception fault           */
+    SIGSEGV,			/* 13:  General protection fault abort  */
+    SIGSEGV,			/* 14:  Page fault                      */
+    SIGABRT,			/* 15:  (reserved)                      */
+    SIGFPE,			/* 16:  Coprocessor error fault         */
+    SIGUSR1			/* other                                */
+  };
+
+  return signals[trap_no < 17 ? trap_no : 17];
+}
+
--- grub2/genmk.rb	2008-04-17 16:14:10.000000000 +0200
+++ grub2-gdb/genmk.rb	2008-05-01 10:57:14.000000000 +0200
@@ -101,10 +101,11 @@ class PModule
     mod_obj = mod_src.suffix('o')
     defsym = 'def-' + @name.suffix('lst')
     undsym = 'und-' + @name.suffix('lst')
+    exec = @name.suffix('elf')
     mod_name = File.basename(@name, '.mod')
     symbolic_name = mod_name.sub(/\.[^\.]*$/, '')
     
-    "CLEANFILES += #{@name} #{mod_obj} #{mod_src} #{pre_obj} #{objs_str} #{undsym}
+    "CLEANFILES += #{@name} #{mod_obj} #{mod_src} #{pre_obj} #{objs_str} #{undsym} #{exec}
 ifneq ($(#{prefix}_EXPORTS),no)
 CLEANFILES += #{defsym}
 DEFSYMFILES += #{defsym}
@@ -112,10 +113,13 @@ endif
 MOSTLYCLEANFILES += #{deps_str}
 UNDSYMFILES += #{undsym}
 
-#{@name}: #{pre_obj} #{mod_obj}
+#{@name}: #{exec}
+	-rm -f $@
+	$(OBJCOPY) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $^ $@
+
+#{exec}: #{pre_obj} #{mod_obj}
 	-rm -f $@
 	$(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ $^
-	$(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@
 
 #{pre_obj}: $(#{prefix}_DEPENDENCIES) #{objs_str}
 	-rm -f $@
--- grub2/include/grub/gdb.h	1970-01-01 01:00:00.000000000 +0100
+++ grub2-gdb/include/grub/gdb.h	2008-05-01 10:57:57.000000000 +0200
@@ -0,0 +1,38 @@
+/* gdb.h - Various definitions for the remote GDB stub */
+/*
+ *  Copyright (C) 2006  Lubomir Kundrak
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_GDB_HEADER
+#define GRUB_GDB_HEADER		1
+
+#define SIGFPE		8
+#define SIGTRAP		5
+#define SIGABRT		6
+#define SIGSEGV		11
+#define SIGILL		4
+#define SIGUSR1		30
+/* We probably don't need other ones.  */
+
+extern int (*grub_gdb_getchar) ();
+extern void (*grub_gdb_putchar) (int);
+
+void grub_gdb_breakpoint ();
+int grub_gdb_trap2sig (int);
+
+#endif /* ! GRUB_GDB_HEADER */
+
--- grub2/include/grub/i386/gdb.h	1970-01-01 01:00:00.000000000 +0100
+++ grub2-gdb/include/grub/i386/gdb.h	2008-05-01 10:57:57.000000000 +0200
@@ -0,0 +1,80 @@
+/* i386/gdb.h - i386 specific definitions for the remote GDB stub */
+/*
+ *  Copyright (C) 2006	Lubomir Kundrak
+ *
+ *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef GRUB_GDB_CPU_HEADER
+#define GRUB_GDB_CPU_HEADER	1
+
+#define GRUB_GDB_LAST_TRAP	31
+/* You may have to edit the bottom of machdep.S when adjusting
+   GRUB_GDB_LAST_TRAP.	*/
+#define GRUB_MACHINE_NR_REGS	16
+
+#define	EAX	0
+#define	ECX	1
+#define	EDX	2
+#define	EBX	3
+#define	ESP	4
+#define	EBP	5
+#define	ESI	6
+#define	EDI	7
+#define	EIP	8
+#define	EFLAGS	9
+#define	CS	10
+#define	SS	11
+#define	DS	12
+#define	ES	13
+#define	FS	14
+#define	GS	15
+
+#define PC	EIP
+#define FP	EBP
+#define SP	ESP
+#define PS	EFLAGS
+
+#ifndef ASM
+
+#include <grub/gdb.h>
+
+#define GRUB_CPU_TRAP_GATE	15
+
+struct gate
+{
+  unsigned offset_lo:16;
+  unsigned selector:16;
+  unsigned xx:8;
+  unsigned type:5;	/* GRUB_CPU_TRAP_GATE */
+  unsigned dpl:2;
+  unsigned present:1;
+  unsigned offset_hi:16;
+} __attribute__ ((packed));
+
+struct region
+{
+  unsigned limit:16;
+  unsigned base:32;
+} __attribute__ ((packed));
+
+extern void (*grub_gdb_trapvec[]) ();
+extern void grub_gdb_breakpoint ();
+extern void grub_idt_load (struct region *);
+extern void grub_gdb_idtinit ();
+
+#endif /* ! ASM */
+#endif /* ! GRUB_GDB_CPU_HEADER */
+
--- grub2/include/grub/i386/pc/kernel.h	2008-03-24 05:13:36.000000000 +0100
+++ grub2-gdb/include/grub/i386/pc/kernel.h	2008-05-01 14:14:08.000000000 +0200
@@ -44,7 +44,7 @@
 #define GRUB_KERNEL_MACHINE_DATA_END		0x50
 
 /* The size of the first region which won't be compressed.  */
-#define GRUB_KERNEL_MACHINE_RAW_SIZE		0x4A0
+#define GRUB_KERNEL_MACHINE_RAW_SIZE		0x4BC
 
 #ifndef ASM_FILE
 
--- grub2/kern/i386/pc/startup.S	2008-03-30 06:13:47.000000000 +0200
+++ grub2-gdb/kern/i386/pc/startup.S	2008-05-01 12:02:57.000000000 +0200
@@ -276,6 +276,15 @@ VARIABLE(grub_apm_bios_info)
 	.word	0	/* cseg_len */
 	.word	0	/* cseg_16_len */
 	.word	0	/* dseg_16_len */
+
+/* IDT region descriptors */
+VARIABLE(prot_idt)
+	.word	0xffff			/* limit */
+	.long	0x0			/* addr */
+
+VARIABLE(real_idt)
+	.word	0xffff			/* limit */
+	.long	0x0			/* addr */
 	
 	.p2align	2	/* force 4-byte alignment */
 	
@@ -327,6 +336,9 @@ protcseg:
 	/* zero %eax */
 	xorl	%eax, %eax
 
+	/* real mode IDT is no longer pertinent */
+	lidt prot_idt
+
 	/* return on the old (or initialized) stack! */
 	ret
 
@@ -1097,7 +1109,6 @@ xsmap:
 	popl	%ebp
 	ret
 
-	
 /*
  * void grub_console_real_putchar (int c)
  *
--- grub2/kern/i386/realmode.S	2007-10-17 22:04:23.000000000 +0200
+++ grub2-gdb/kern/i386/realmode.S	2008-05-01 12:03:06.000000000 +0200
@@ -120,6 +120,10 @@ prot_to_real:
 	/* just in case, set GDT */
 	lgdt	gdtdesc
 
+	/* our protected mode IDT would cause trouble in real mode */
+	sidt prot_idt
+	lidt real_idt
+
 	/* save the protected mode stack */
 	movl	%esp, %eax
 	movl	%eax, protstack
--- grub2/term/i386/pc/serial.c	2007-12-30 09:52:06.000000000 +0100
+++ grub2-gdb/term/i386/pc/serial.c	2008-05-01 10:58:41.000000000 +0200
@@ -79,7 +79,7 @@ serial_hw_get_port (const unsigned short
 }
 
 /* Fetch a key.  */
-static int
+int
 serial_hw_fetch (void)
 {
   if (grub_inb (serial_settings.port + UART_LSR) & UART_DATA_READY)
@@ -89,7 +89,7 @@ serial_hw_fetch (void)
 }
 
 /* Put a character.  */
-static void
+void
 serial_hw_put (const int c)
 {
   unsigned int timeout = 100000;
@@ -247,7 +247,7 @@ grub_serial_checkkey (void)
 }
 
 /* The serial version of getkey.  */
-static int
+int
 grub_serial_getkey (void)
 {
   int c;

             reply	other threads:[~2008-05-01 13:41 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-05-01 13:12 Lubomir Rintel [this message]
2008-05-06 15:02 ` [PATCH] Remote GDB debugging stub (for i386) Robert Millan
2008-05-06 18:46   ` Vesa Jääskeläinen
2008-05-07  8:17   ` Lubomir Rintel
2008-05-07  8:17 ` [PATCH] GDB stuff updated Lubomir Rintel
2008-05-16 20:17   ` Vesa Jääskeläinen
2008-05-16 20:23     ` Vesa Jääskeläinen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1209647545.3433.14.camel@localhost.localdomain \
    --to=lkundrak@v3.sk \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.