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, ®no) && *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;
next 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.