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: Mon, 22 Aug 2005 23:23:47 +0200
User-agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)

Here is a new version of the backtrace support. I have written the ChangeLog and modified the code according to your advices.

To compile with the backtrace support use ./configure --with-debug and load grub2 with the kern_debug module. The kern module will be unloaded automatically after having registered all the kernel symbols in a linked list that also contains the module symbols. Any files that includes <grub/backtrace.h> can now call grub_backtrace().

The functions that handle the linked list with the debug symbols are generic and are put in kern/backtrace.c. The function grub_backtrace() however is architecture dependant and is put in kern/i386/pc/backtrace.c.

This is a problem because I would say that it breaks compilation for other architectures. I think that the other architectures should have a function grub_backtrace() that does nothing, or even better that really does print a backtrace(). However, I don't know how to do it and I can't test it anyway.

I have also slightly modified the way genmk.rb generates the rule to create the modules. I hope this slight change does not do anything silly that I missed.

I hope this backtrace will be usefull, but not too much !


--
                                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/ChangeLog grub2-backtrace/ChangeLog
--- grub2/ChangeLog     2005-08-20 10:25:51.000000000 +0200
+++ grub2-backtrace/ChangeLog   2005-08-22 22:52:47.934165416 +0200
@@ -1,3 +1,45 @@
+2005-08-22     Vincent Guffens <address@hidden>
+
+       * conf/i386-pc.rmk : Added kern/backtrace.c, kern/i386/pc/backtrace.c 
+       in the kernel dependancy list and backtrace.h in the header list. Added 
a
+       new module kern_debug.mod.
+
+       * grub2/configure.ac : Added a configure switch : --with-debug. 
+       Turn the gcc optimization flag to -O0 and define a variable 
GRUB_DEBUG=1 
+       in Makefile.in if this switch is used. 
+
+       * gendebugkern.sh : New file : shell script which generates the debug
+       symbols for the kernel.
+
+       * genmk.rb : Do not strip the uneeded symbols from the objects if 
+       GRUB_DEBUG=1. Add a variable $(#{prefix}_OTHERDEP) in the dependancy 
list 
+       of the modules. This variable can be set to something useful in 
i386-pc.rmk.
+       Do not compile the module with all the dependances, just use the 
sources.
+
+       * include/grub/backtrace.h : New file
+
+       * kern/backtrace.c : New file 
+       (grub_register_debug_sym): New function
+       (grub_unregister_debug_sym): Likewise
+       (grub_print_debug_sym) : Likewise
+
+       * kern/dl.c : (Un)Register the debug symbols when a module is 
(un)loaded.
+
+       * kern/err.c (grub_fatal) : Call grub_backtrace()
+
+       * kern/i386/pc/backtrace.c : New file
+       (get_fp) : New function
+       (grub_backtrace) : likewise
+
+       * kern/kern_debug.c : New file : This is the source for the new module
+       kern_debug. It registers the kernel symbol during its initialisation and
+       does nothing else. It is automatically removed  later.
+
+       * kern/main.c  (grub_load_modules) : Try to unregister the kern_debug 
module.
+
+       * Makefile.in : Add a new variable GRUB_DEBUG which is set by 
configure. Add 
+       the rule to create the kernel symbol list in kern/grub_debug_kern.sym.
+       
 2005-08-20  Yoshinori K. Okuji  <address@hidden>
 
        * loader/powerpc/ieee1275/linux.c (grub_rescue_cmd_linux): Specify
diff -ru -N -b -B grub2/conf/i386-pc.rmk grub2-backtrace/conf/i386-pc.rmk
--- grub2/conf/i386-pc.rmk      2005-08-20 09:49:01.000000000 +0200
+++ grub2-backtrace/conf/i386-pc.rmk    2005-08-22 20:54:51.000000000 +0200
@@ -28,13 +28,13 @@
        kern/i386/dl.c kern/i386/pc/init.c kern/partition.c \
        kern/env.c disk/i386/pc/biosdisk.c \
        term/i386/pc/console.c \
-       symlist.c
+       symlist.c kern/backtrace.c kern/i386/pc/backtrace.c
 kernel_img_HEADERS = arg.h boot.h device.h disk.h dl.h elf.h env.h err.h \
        file.h fs.h kernel.h loader.h misc.h mm.h net.h partition.h \
        pc_partition.h rescue.h symbol.h term.h types.h \
        machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \
        machine/memory.h machine/loader.h machine/time.h machine/vga.h \
-       machine/vbe.h
+       machine/vbe.h backtrace.h
 kernel_img_CFLAGS = $(COMMON_CFLAGS)
 kernel_img_ASFLAGS = $(COMMON_ASFLAGS)
 kernel_img_LDFLAGS = -nostdlib -Wl,-N,-Ttext,8200
@@ -93,7 +93,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/backtrace.c kern/i386/pc/backtrace.c
 
 grub_emu_LDFLAGS = $(LIBCURSES)
 
@@ -113,7 +113,7 @@
        terminal.mod fshelp.mod chain.mod multiboot.mod amiga.mod       \
        apple.mod pc.mod sun.mod loopback.mod reboot.mod halt.mod       \
        help.mod default.mod timeout.mod configfile.mod vbe.mod         \
-       vesafb.mod vbetest.mod vbeinfo.mod search.mod
+       vesafb.mod vbetest.mod vbeinfo.mod search.mod kern_debug.mod
 
 # For _chain.mod.
 _chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -274,3 +274,8 @@
 # For search.mod.
 search_mod_SOURCES = commands/search.c
 search_mod_CFLAGS = $(COMMON_CFLAGS)
+
+# For kern_debug.mod
+kern_debug_mod_OTHERDEP = kern/grub_debug_kern.sym
+kern_debug_mod_SOURCES = kern/kern_debug.c
+kern_debug_mod_CFLAGS = $(COMMON_CFLAGS) 
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-20 18:02:14.000000000 +0200
@@ -16,6 +16,9 @@
 /* Define it to either end or _end */
 #undef END_SYMBOL
 
+/* enable some debug mechanisms */
+#undef GRUB_DEBUG
+
 /* 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-22 18:11:06.000000000 +0200
@@ -57,10 +57,20 @@
     AC_TRY_COMPILE(, , size_flag=yes, size_flag=no)
   ])
   if test "x$size_flag" = xyes; then
+               if test "$with_debug" == "yes"
+               then
+       tmp_CFLAGS="$tmp_CFLAGS -O0"
+               else
     tmp_CFLAGS="$tmp_CFLAGS -Os"
+               fi
+  else
+               if test "$with_debug" == "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"
   fi
+       fi
 
   # Force no alignment to save space on i386.
   if test "x$host_cpu" = xi386; then
@@ -108,6 +118,16 @@
 # This is not a "must".
 AC_PATH_PROG(RUBY, ruby)
 
+# take care of the configure arguments
+
+AC_ARG_WITH(debug, [  --with-debug            enable some debug mechanisms])
+if test "$with_debug" == "yes"; then
+       AC_DEFINE([GRUB_DEBUG], [], [enable some debug mechanisms]) 
+       AC_SUBST(GRUB_DEBUG,1)
+else
+       AC_SUBST(GRUB_DEBUG,0)
+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/gendebugkern.sh grub2-backtrace/gendebugkern.sh
--- grub2/gendebugkern.sh       1970-01-01 01:00:00.000000000 +0100
+++ grub2-backtrace/gendebugkern.sh     2005-08-22 18:47:48.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-22 21:46:23.000000000 +0200
@@ -119,14 +119,18 @@
 address@hidden: #{pre_obj} #{mod_obj}
        -rm -f $@
        $(LD) -r -d -o $@ $^
+ifeq ($(GRUB_DEBUG),1)
+       $(STRIP) --strip-debug -K grub_mod_init -K grub_mod_fini -R .note -R 
.comment $@
+else
        $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R 
.comment $@
+endif
 
 #{pre_obj}: #{objs_str}
        -rm -f $@
        $(LD) -r -d -o $@ $^
 
-#{mod_obj}: #{mod_src}
-       $(CC) $(CPPFLAGS) $(CFLAGS) $(#{prefix}_CFLAGS) -c -o $@ $<
+#{mod_obj}: $(#{prefix}_OTHERDEP) #{mod_src} 
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(#{prefix}_CFLAGS) -c -o $@ #{mod_src}
 
 #{mod_src}: moddep.lst genmodsrc.sh
        sh $(srcdir)/genmodsrc.sh '#{mod_name}' $< > $@ || (rm -f $@; exit 1)
@@ -147,8 +151,8 @@
       flag = if /\.c$/ =~ src then 'CFLAGS' else 'ASFLAGS' end
       dir = File.dirname(src)
 
-      "#{obj}: #{src}
-       $(CC) -I#{dir} -I$(srcdir)/#{dir} $(CPPFLAGS) $(#{flag}) 
$(#{prefix}_#{flag}) -c -o $@ $<
+      "#{obj}: $(#{prefix}_OTHERDEP) #{src}
+       $(CC) -I#{dir} -I$(srcdir)/#{dir} $(CPPFLAGS) $(#{flag}) 
$(#{prefix}_#{flag}) -c -o $@ #{src}
 
 #{dep}: #{src}
        set -e; \
Les fichiers binaires grub2/grub_disk et grub2-backtrace/grub_disk sont 
différents.
diff -ru -N -b -B grub2/include/grub/backtrace.h 
grub2-backtrace/include/grub/backtrace.h
--- grub2/include/grub/backtrace.h      1970-01-01 01:00:00.000000000 +0100
+++ grub2-backtrace/include/grub/backtrace.h    2005-08-20 18:46:33.000000000 
+0200
@@ -0,0 +1,12 @@
+#ifndef GRUB_BACKTRACE_H
+#define GRUB_BACKTRACE_H
+
+#include <grub/types.h>
+#include <grub/symbol.h>
+
+void EXPORT_FUNC(grub_register_debug_sym) (const char*, void*, grub_size_t);
+void EXPORT_FUNC(grub_unregister_debug_sym) (void *);
+int EXPORT_FUNC(grub_print_debug_sym) (grub_addr_t);
+void EXPORT_FUNC(grub_backtrace) (void);
+
+#endif
diff -ru -N -b -B grub2/kern/backtrace.c grub2-backtrace/kern/backtrace.c
--- grub2/kern/backtrace.c      1970-01-01 01:00:00.000000000 +0100
+++ grub2-backtrace/kern/backtrace.c    2005-08-20 18:42:11.000000000 +0200
@@ -0,0 +1,87 @@
+#include <grub/backtrace.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <config.h>
+
+#ifdef GRUB_DEBUG
+
+static struct grub_debug_sym {
+       struct grub_debug_sym * next;
+       char * name;
+       grub_addr_t addr;
+       grub_size_t size;
+} * grub_debug_sym = 0;
+
+int grub_print_debug_sym (grub_addr_t a) {
+       struct grub_debug_sym * entry = grub_debug_sym;
+
+       while( entry ) {
+               if ((entry->addr <= a) && 
+                               (entry->addr + entry->size > a)) {
+                       grub_printf("0x%lx+%lx : %s \n",
+                                                                               
        (long int)entry->addr,
+                                                                               
        (long int)(a-entry->addr), 
+                                                                               
        entry->name);
+                       return 1;
+               }
+               entry = entry->next;
+       }
+       return 0;
+}
+
+void grub_register_debug_sym (const char* name ,void * addr,grub_size_t sz) {
+
+       struct grub_debug_sym * new_entry;
+
+       if (addr) {
+               new_entry = (struct grub_debug_sym *) 
grub_malloc(sizeof(*new_entry));
+               if (! new_entry)
+                       return;
+               new_entry->name = grub_strdup(name);
+               new_entry->addr = (grub_addr_t) addr;
+               new_entry->size = sz;
+
+               new_entry->next = grub_debug_sym;
+               grub_debug_sym = new_entry;
+       }
+}
+
+void grub_unregister_debug_sym (void * address) {
+       struct grub_debug_sym * next_entry, * entry = grub_debug_sym;
+       grub_addr_t addr = (grub_addr_t) address;
+       
+       if (! entry)
+               return;
+       
+       if (entry->addr == addr ) {
+               grub_debug_sym = entry->next;
+               grub_free(entry->name);
+               grub_free(entry);
+               return;
+       }
+       
+       next_entry = entry->next;
+       
+       while (next_entry) {
+               if (next_entry->addr == addr ) {
+                       entry->next=next_entry->next;
+                       grub_free(next_entry->name);
+                       grub_free(next_entry);
+                       return;
+               }
+               entry = next_entry;
+               next_entry=next_entry->next;
+       }
+       
+}
+#else
+
+#define NOOP {do {} while (0);}
+inline void grub_register_debug_sym (const char* name  __attribute__ 
((unused)),
+                                         void* ad  __attribute__ ((unused)),
+                                                                               
                                        grub_size_t s __attribute__ ((unused))) 
NOOP;
+inline void grub_unregister_debug_sym (void * addr __attribute__((unused))) 
NOOP;
+inline int grub_print_debug_sym (grub_addr_t a __attribute__((unused))) 
{return 0;};
+
+#endif
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-20 18:48:30.000000000 +0200
@@ -29,6 +29,7 @@
 #include <grub/file.h>
 #include <grub/env.h>
 #include <grub/cache.h>
+#include <grub/backtrace.h>
 
 #if GRUB_HOST_SIZEOF_VOID_P == 4
 
@@ -216,6 +217,7 @@
          if (sym->mod == mod)
            {
              *p = q;
+                               grub_unregister_debug_sym (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_register_debug_sym (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;
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-20 18:35:16.000000000 +0200
@@ -20,6 +20,7 @@
 
 #include <grub/err.h>
 #include <grub/misc.h>
+#include <grub/backtrace.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-20 18:42:19.000000000 
+0200
@@ -0,0 +1,35 @@
+#include <grub/backtrace.h>
+#include <grub/types.h>
+#include <grub/misc.h> 
+
+#ifdef GRUB_DEBUG
+
+#define BTSYM_DISPLAY 12
+
+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) && grub_print_debug_sym (*(a+1)) ) {
+    a= (grub_addr_t *)(*a);
+    i++;
+  }
+}
+
+
+#else
+
+inline void grub_backtrace (void)  {do {} while (0);};
+
+#endif
diff -ru -N -b -B grub2/kern/kern_debug.c grub2-backtrace/kern/kern_debug.c
--- grub2/kern/kern_debug.c     1970-01-01 01:00:00.000000000 +0100
+++ grub2-backtrace/kern/kern_debug.c   2005-08-22 22:01:15.000000000 +0200
@@ -0,0 +1,47 @@
+#include <grub/symbol.h>
+#include <grub/types.h>
+#include <grub/backtrace.h>
+#include <grub/dl.h>
+#include <config.h>
+
+#ifdef GRUB_DEBUG
+
+#define MAX_SYMNAME_L 80
+#define MAX_BTSYMBOLS 512
+
+
+static struct kern_debug_sym {
+  char name[MAX_SYMNAME_L+1];
+  grub_addr_t addr;
+  grub_size_t size;
+} kern_debug_sym[MAX_BTSYMBOLS] = {
+#include "grub_debug_kern.sym"
+};
+
+
+GRUB_MOD_INIT
+{
+  (void)mod;                   /* To stop warning. */
+       int i=0;
+
+       while (kern_debug_sym[i].addr) {
+               grub_register_debug_sym(kern_debug_sym[i].name,
+                                                                               
                          (void *)kern_debug_sym[i].addr,
+                                                                               
                                kern_debug_sym[i].size);
+               i++;
+       }
+       /* This module is not needed anymore */
+
+}
+
+
+#else
+
+GRUB_MOD_INIT
+{
+  (void)mod;
+       /* Nothing to do */
+}
+
+
+#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-22 22:08:16.000000000 +0200
@@ -35,6 +35,7 @@
 {
   struct grub_module_info *modinfo;
   struct grub_module_header *header;
+       grub_dl_t mod;
   grub_addr_t modbase;
 
   modbase = grub_arch_modules_addr ();
@@ -55,6 +56,13 @@
 
   /* Add the region where modules reside into dynamic memory.  */
   grub_mm_init_region ((void *) modinfo, modinfo->size);
+       
+       /* remove the kern_debug module */
+       mod = grub_dl_get("kern_debug");
+       if (mod && ( grub_dl_unref (mod) <= 0  ))
+               grub_dl_unload (mod);
+       
+
 }
 
 /* Write hook for the environment variables of root. Remove surrounding
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-22 21:40:21.000000000 +0200
@@ -69,6 +69,8 @@
 LIBCURSES = @LIBCURSES@
 LIBLZO = @LIBLZO@
 
+### Debug variable
+GRUB_DEBUG = @GRUB_DEBUG@
 ### General variables.
 
 RMKFILES = $(addprefix conf/,i386-pc.rmk powerpc-ieee1275.rmk)
@@ -239,5 +240,8 @@
 .PHONY: all install install-strip uninstall clean mostlyclean distclean
 .PHONY: maintainer-clean info dvi dist check
 
+kern/grub_debug_kern.sym: kernel.exec
+       ./gendebugkern.sh kernel.exec > $@
+       
 # Prevent an overflow.
 .NOEXPORT:

reply via email to

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