[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
backtrace support
From: |
Vincent Guffens |
Subject: |
backtrace support |
Date: |
Thu, 18 Aug 2005 22:22:59 +0200 |
User-agent: |
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) |
Hi,
After having searched for the reason of the unaligned pointer caused by
the nested functions bug, I thought that it could be interesting to have
a backtrace in grub. It would be triggered in grub_fatal and would print
the last few function calls that triggered the problem.
I have implemented such a backtrace function using the stack base
pointer. You can see how it looks like on the picture attached. This is
a screenshot taken after the bug mentioned above and it points directly
to the cause of the problem.
However, the price to pay for that, at least with my implementation, is
quite high. One has to disable the optimization flag to prevent the
-fomit-frame-pointer and the module must not be stripped. Still, during
the developpement phase, it might be usefull to get good bug reports.
The feature is added with
./configure --with-backtrace
and grub must be compile with ./btmake instead of make which is a simple
script which calls make twice instead of only once.
I include the patch as attachment, if not for inclusion in grub, at
least for the potential interrested reader.
--
Vincent Guffens
PhD Student UCL/CESAME
tel: +32 10 47 80 30
Value your freedom, or you will lose it, teaches history.
"Don't bother us with politics," respond those who don't want to learn.
-- Richard M. Stallman
diff -ru -N -b -B grub2/btmake grub2-backtrace/btmake
--- grub2/btmake 1970-01-01 01:00:00.000000000 +0100
+++ grub2-backtrace/btmake 2005-08-18 18:48:36.000000000 +0200
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Create a grub kernel image with backtrace support
+# configure must have been run with : --with-backtrace
+make
+./genbtsym.sh kernel.exec > kern/i386/pc/grub_btsym_list.txt
+rm kernel_img-kern_i386_pc_backtrace.d
+rm kernel_img-kern_i386_pc_backtrace.o
+make
+
diff -ru -N -b -B grub2/conf/i386-pc.rmk grub2-backtrace/conf/i386-pc.rmk
--- grub2/conf/i386-pc.rmk 2005-08-12 21:53:32.000000000 +0200
+++ grub2-backtrace/conf/i386-pc.rmk 2005-08-15 16:22:03.000000000 +0200
@@ -25,7 +25,7 @@
kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \
kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \
kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \
- kern/i386/dl.c kern/i386/pc/init.c kern/partition.c \
+ kern/i386/dl.c kern/i386/pc/init.c kern/i386/pc/backtrace.c
kern/partition.c \
kern/env.c disk/i386/pc/biosdisk.c \
term/i386/pc/console.c \
symlist.c
@@ -92,7 +92,7 @@
partmap/amiga.c partmap/apple.c partmap/pc.c partmap/sun.c \
util/console.c util/grub-emu.c util/misc.c \
util/i386/pc/biosdisk.c util/i386/pc/getroot.c \
- util/i386/pc/misc.c
+ util/i386/pc/misc.c kern/i386/pc/backtrace.c
grub_emu_LDFLAGS = $(LIBCURSES)
diff -ru -N -b -B grub2/config.h.in grub2-backtrace/config.h.in
--- grub2/config.h.in 2005-08-09 01:15:21.000000000 +0200
+++ grub2-backtrace/config.h.in 2005-08-13 18:32:23.000000000 +0200
@@ -16,6 +16,9 @@
/* Define it to either end or _end */
#undef END_SYMBOL
+/* enable backtrace support */
+#undef GRUB_BACKTRACE
+
/* Define if C symbols get an underscore after compilation */
#undef HAVE_ASM_USCORE
diff -ru -N -b -B grub2/configure.ac grub2-backtrace/configure.ac
--- grub2/configure.ac 2005-08-09 01:15:21.000000000 +0200
+++ grub2-backtrace/configure.ac 2005-08-18 17:36:26.000000000 +0200
@@ -57,9 +57,19 @@
AC_TRY_COMPILE(, , size_flag=yes, size_flag=no)
])
if test "x$size_flag" = xyes; then
+ if test "$with_backtrace" == "yes"
+ then
+ tmp_CFLAGS="$tmp_CFLAGS -O0"
+ else
tmp_CFLAGS="$tmp_CFLAGS -Os"
+ fi
+ else
+ if test "$with_backtrace" == "yes"
+ then
+ tmp_CFLAGS="$tmp_CFLAGS -O0 -fno-strength-reduce -fno-unroll-loops"
else
- tmp_CFLAGS="$tmp_CFLAGS -O2 -fno-strength-reduce -fno-unroll-loops"
+ tmp_CFLAGS="$tmp_CFLAGS -Os -fno-strength-reduce -fno-unroll-loops"
+ fi
fi
# Force no alignment to save space on i386.
@@ -108,6 +118,16 @@
# This is not a "must".
AC_PATH_PROG(RUBY, ruby)
+# Include the stack trace support ?
+AC_ARG_WITH(backtrace, [ --with-backtrace enable stack trace
support for i386])
+if test "$with_backtrace" == "yes"
+then
+ case "$host_cpu" in
+ i[[3456]]86) AC_DEFINE([GRUB_BACKTRACE], [], [enable backtrace
support]) ;;
+ *) AC_MSG_NOTICE([backtrace support available for i386 only]) ;;
+ esac
+fi
+
# For cross-compiling.
if test "x$build" != "x$host"; then
AC_CHECK_PROGS(BUILD_CC, [gcc egcs cc],
diff -ru -N -b -B grub2/genbtsym.sh grub2-backtrace/genbtsym.sh
--- grub2/genbtsym.sh 1970-01-01 01:00:00.000000000 +0100
+++ grub2-backtrace/genbtsym.sh 2005-08-18 18:34:12.000000000 +0200
@@ -0,0 +1,14 @@
+#!/bin/bash
+# Generates the list of all the symbols
+# defined in the grub kernel. This is used
+# to print a stack trace in case of trouble
+
+
+OBJECT=$1
+
+if (test -e ${OBJECT}) ; then
+ objdump -t ${OBJECT} | grep -v 00000000 | awk '/.text/ {print
"{\""$6"\",","0x"$1",","0x"$5 "},"}' ;
+else
+ echo [0 ... MAX_BTSYMBOLS-2 ] = {"symbol", 0, 0},
+fi
+
diff -ru -N -b -B grub2/genmk.rb grub2-backtrace/genmk.rb
--- grub2/genmk.rb 2005-08-07 19:12:51.000000000 +0200
+++ grub2-backtrace/genmk.rb 2005-08-18 18:43:05.000000000 +0200
@@ -119,7 +119,9 @@
address@hidden: #{pre_obj} #{mod_obj}
-rm -f $@
$(LD) -r -d -o $@ $^
- $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R
.comment $@
+ cat config.h | grep define | grep BACKTRACE \
+ && $(STRIP) --strip-debug -R .note -R .comment $@ \
+ || $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R
.note -R .comment $@
#{pre_obj}: #{objs_str}
-rm -f $@
diff -ru -N -b -B grub2/include/grub/kernel.h
grub2-backtrace/include/grub/kernel.h
--- grub2/include/grub/kernel.h 2005-02-15 01:07:01.000000000 +0100
+++ grub2-backtrace/include/grub/kernel.h 2005-08-18 20:49:57.000000000
+0200
@@ -21,6 +21,7 @@
#define GRUB_KERNEL_HEADER 1
#include <grub/types.h>
+#include <grub/symbol.h>
/* The module header. */
struct grub_module_header
@@ -58,4 +59,11 @@
/* Register all the exported symbols. This is automatically generated. */
void grub_register_exported_symbols (void);
+/* backtrace support for i386 */
+void EXPORT_FUNC(grub_backtrace) (void);
+void EXPORT_FUNC(grub_btregister_symbol) (const char*,void*,grub_size_t);
+void EXPORT_FUNC(grub_btunregister_symbol) (void *);
+void EXPORT_FUNC(grub_init_btsym) (void);
+
+
#endif /* ! GRUB_KERNEL_HEADER */
diff -ru -N -b -B grub2/kern/dl.c grub2-backtrace/kern/dl.c
--- grub2/kern/dl.c 2005-02-14 19:41:33.000000000 +0100
+++ grub2-backtrace/kern/dl.c 2005-08-18 20:51:51.000000000 +0200
@@ -29,6 +29,7 @@
#include <grub/file.h>
#include <grub/env.h>
#include <grub/cache.h>
+#include <grub/kernel.h>
#if GRUB_HOST_SIZEOF_VOID_P == 4
@@ -216,6 +217,7 @@
if (sym->mod == mod)
{
*p = q;
+ grub_btunregister_symbol(sym->addr);
grub_free ((void *) sym->name);
grub_free (sym);
}
@@ -375,6 +377,7 @@
case STT_FUNC:
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
sym->st_shndx);
+ grub_btregister_symbol(name,(void *) sym->st_value,
sym->st_size);
if (bind != STB_LOCAL)
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
return grub_errno;
@@ -654,6 +657,7 @@
grub_dl_remove (mod);
grub_dl_unregister_symbols (mod);
+
for (dep = mod->dep; dep; dep = depn)
{
depn = dep->next;
diff -ru -N -b -B grub2/kern/err.c grub2-backtrace/kern/err.c
--- grub2/kern/err.c 2004-04-04 15:46:01.000000000 +0200
+++ grub2-backtrace/kern/err.c 2005-08-15 16:22:37.000000000 +0200
@@ -20,6 +20,7 @@
#include <grub/err.h>
#include <grub/misc.h>
+#include <grub/kernel.h>
#include <stdarg.h>
#define GRUB_MAX_ERRMSG 256
@@ -50,6 +51,9 @@
grub_vprintf (fmt, ap);
va_end (ap);
+#ifndef GRUB_UTIL
+ grub_backtrace();
+#endif
grub_stop ();
}
diff -ru -N -b -B grub2/kern/i386/pc/backtrace.c
grub2-backtrace/kern/i386/pc/backtrace.c
--- grub2/kern/i386/pc/backtrace.c 1970-01-01 01:00:00.000000000 +0100
+++ grub2-backtrace/kern/i386/pc/backtrace.c 2005-08-18 21:04:31.000000000
+0200
@@ -0,0 +1,150 @@
+#include <grub/kernel.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <config.h>
+
+#ifdef GRUB_BACKTRACE
+
+#define MAX_BTSYMBOLS 512
+#define BTSYM_DISPLAY 10
+#define MAX_SYMNAME_L 80
+
+static struct btsym {
+ char name[MAX_SYMNAME_L+1];
+ grub_addr_t address;
+ grub_size_t size;
+} btsym_list[MAX_BTSYMBOLS] = {
+#include "grub_btsym_list.txt"
+};
+
+static struct btsym_l {
+ struct btsym_l * next;
+ struct btsym * entry;
+} * btsym_l = 0;
+
+static int get_btsymbol(grub_addr_t a) {
+ struct btsym_l * it = btsym_l;
+ struct btsym * entry;
+
+ while( it ) {
+ entry = it->entry;
+ if ((entry->address <= a) &&
+
(entry->address +
+
entry->size > a)) {
+ grub_printf("0x%lx+%lx : %s \n",
+
(long int)entry->address,
+
(long int)(a-entry->address),
+
entry->name);
+ return 1;
+ }
+ it = it->next;
+ }
+ return 0;
+}
+/*
+static void print_btsymbol(void) {
+ struct btsym_l * it = btsym_l;
+ struct btsym * entry;
+ int i=1;
+
+ while( it ) {
+ entry = it->entry;
+ if (grub_strcmp(entry->name,"grub_cmd_hello") == 0)
+ grub_printf("0x%lx sz=0x%lx: %s \n",
+ (long
int)entry->address,(long int)entry->size,
+
entry->name);
+ it = it->next;
+ i++;
+ }
+}
+*/
+static grub_addr_t * get_fp(void) {
+ grub_addr_t * a;
+ asm ("movl %%ebp, %0;"
+ :"=r"(a) /* output */
+ );
+ return a;
+}
+
+
+void grub_backtrace (void) {
+ grub_addr_t * a;
+ int i =1;
+
+ grub_printf("\nBacktrace:\n");
+ a = get_fp();
+
+ while ( (i <= BTSYM_DISPLAY) && get_btsymbol(*(a+1)) ) {
+ a= (grub_addr_t *)(*a);
+ i++;
+ }
+}
+
+
+void grub_btregister_symbol (const char* name ,void * addr,grub_size_t sz) {
+
+ struct btsym_l * new_entry;
+ struct btsym * new_symbol;
+
+ if (addr) {
+ new_symbol = (struct btsym *) grub_malloc(sizeof(*new_symbol));
+ grub_strncpy(new_symbol->name,name,MAX_SYMNAME_L);
+ new_symbol->name[MAX_SYMNAME_L] = '\0';
+ new_symbol->address = (grub_addr_t) addr;
+ new_symbol->size = sz;
+
+ new_entry = (struct btsym_l *) grub_malloc(sizeof(*new_entry));
+ new_entry->entry = new_symbol;
+ new_entry->next = btsym_l;
+ btsym_l = new_entry;
+ }
+}
+// Don't unregister a kernel symbol !
+void grub_btunregister_symbol (void * address) {
+ struct btsym_l * next_entry, * entry = btsym_l;
+ grub_addr_t addr = (grub_addr_t) address;
+
+ if (! entry)
+ return;
+
+ if (entry->entry->address == addr ) {
+ btsym_l = entry->next;
+ grub_free(entry->entry);
+ grub_free(entry);
+ return;
+ }
+
+ next_entry = entry->next;
+
+ while (next_entry) {
+ if (next_entry->entry->address == addr ) {
+ entry->next=next_entry->next;
+ grub_free(next_entry->entry);
+ grub_free(next_entry);
+ return;
+ }
+ entry = next_entry;
+ next_entry=next_entry->next;
+ }
+
+}
+
+void grub_init_btsym (void) {
+
+ struct btsym_l * new_entry;
+ int i=0;
+
+ if (btsym_l)
+ return;
+
+ while (btsym_list[i].address) {
+ new_entry = (struct btsym_l *) grub_malloc(sizeof(*new_entry));
+ new_entry->entry = &(btsym_list[i]);
+ new_entry->next = btsym_l;
+ btsym_l = new_entry;
+ i++;
+ }
+}
+
+#endif
diff -ru -N -b -B grub2/kern/main.c grub2-backtrace/kern/main.c
--- grub2/kern/main.c 2005-08-12 21:53:32.000000000 +0200
+++ grub2-backtrace/kern/main.c 2005-08-18 21:31:30.089464136 +0200
@@ -28,6 +28,19 @@
#include <grub/file.h>
#include <grub/device.h>
#include <grub/env.h>
+#include <config.h>
+
+#ifndef GRUB_BACKTRACE
+/* if GRUB_BACKTRACE is defined the backtrace functions
+ * are defined in kern/i386/pc/backtrace.c */
+#define NOOP {do {} while (0);}
+void grub_backtrace(void) NOOP;
+void grub_btregister_symbol(const char* name __attribute__ ((unused)),
+
void* ad __attribute__ ((unused)),
+
grub_size_t s __attribute__ ((unused))) NOOP;
+void grub_init_btsym (void) NOOP;
+void grub_btunregister_symbol (void * addr __attribute__((unused))) NOOP;
+#endif
/* Load all modules in core. */
static void
@@ -112,6 +125,7 @@
{
/* First of all, initialize the machine. */
grub_machine_init ();
+ grub_init_btsym ();
/* Hello. */
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
diff -ru -N -b -B grub2/Makefile.in grub2-backtrace/Makefile.in
--- grub2/Makefile.in 2005-08-09 01:15:21.000000000 +0200
+++ grub2-backtrace/Makefile.in 2005-08-18 21:48:25.675071656 +0200
@@ -82,7 +82,7 @@
CLEANFILES =
MOSTLYCLEANFILES =
DISTCLEANFILES = config.status config.cache config.log config.h \
- Makefile stamp-h include/grub/cpu include/grub/machine
+ Makefile stamp-h include/grub/cpu include/grub/machine tags
MAINTAINER_CLEANFILES = $(srcdir)/configure $(addprefix $(srcdir)/,$(MKFILES))
# The default target.
@@ -212,6 +212,10 @@
@echo "$(distdir).tar.gz is ready for distribution" | \
sed 'h;s/./=/g;p;x;p;x'
+tags:
+ CTAGSF=`ctags --version | grep -i exuberant >/dev/null || echo "-T -w
-d"`
+ find . -name \*.[hcS] | xargs ctags -a --typedefs $(CTAGSF)
+
check:
.SUFFIX:
- backtrace support,
Vincent Guffens <=