grub-devel
[Top][All Lists]
Advanced

[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

JPEG image

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:

reply via email to

[Prev in Thread] Current Thread [Next in Thread]