[Top][All Lists]
[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: