linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
@ 2002-09-25  9:02 Ingo Molnar
  2002-09-25  9:32 ` [re-ANNOUNCE] " Ingo Molnar
  2002-09-25 18:16 ` [ANNOUNCE] " Linus Torvalds
  0 siblings, 2 replies; 23+ messages in thread
From: Ingo Molnar @ 2002-09-25  9:02 UTC (permalink / raw)
  To: linux-kernel
  Cc: Linus Torvalds, Kai Germaschewski, Rusty Russell, Arjan van de Ven


the attached patch is the latest version of 'kksymoops' for the 2.5
kernel. Kksymoops is an in-kernel symbol resolver, which enables nifty
things like:

 - in-kernel symbolic oopses, symbolic show_stack() and symbolic
   show_trace(). Finally correct symbolic oopses over serial consoles or
   netdump.

 - module symbols are correctly decoded as well. Ie. all the userspace
   oops decoding mismatches are solved, which can arise if a kernel
   crashes and another kernel (with different module symbols) is booted.
   How do you find out the symbols that a particular crashed kernel had?

 - list of modules are printed upon oopsing - this clearly puts every
   crash into perspective - exactly which modules were loaded ...

a sample kksym-oops as it goes straight into the kernel log:

------------[ cut here ]------------
kernel BUG at time.c:100!
invalid operand: 0000
CPU:    1
EIP:    0060:[<c011bc64>]    Not tainted
EFLAGS: 00010246
EIP is at sys_gettimeofday [kernel] 0x84
eax: 0000004e   ebx: ceea0000   ecx: 00000000   edx: 00000068
esi: 00000000   edi: 00000000   ebp: bffffad8   esp: ceea1fa0
ds: 0068   es: 0068   ss: 0068
Process gettimeofday (pid: 547, threadinfo=ceea0000 task=cef2b0c0)
Stack: 00000001 00000004 40156154 00000004 c0112a40 ceea0000 400168e4 bffffb44
       c0107973 00000000 00000000 40156154 400168e4 bffffb44 bffffad8 0000004e
       0000002b 0000002b 0000004e 400cecc1 00000023 00000246 bffffacc 0000002b
Call Trace: [<c0112a40>] do_page_fault [kernel] 0x0
[<c0107973>] syscall_call [kernel] 0x7
Code: 0f 0b 64 00 67 b4 26 c0 eb b6 89 f6 83 ec 0c 89 5c 24 04 8b

ie. all symbols resolved properly.

i believe it's all for the better, much of the above featureset is also
based on distributors' daily experience of how users report crashes and
how it can be made sense of post-mortem. Tester feedback is often a scarce
resource for distributors, so improving the quality of individual reports
is of high importance. Even here on lkml the quality of oops reporting is
often surprisingly low, especially taking the many years of education into
account.

the cost of the feature is an in-kernel copy of the symbol table - most
testers will not care, and it's default-disabled in the .config. This
patch has proven to be very useful in my daily kernel development
activities, hopefully others will find this just as useful.

I've tested the patch on x86, building and oopsing works both with
kksymoops enabled and disabled.

The line of credit for kksymoops goes like this: Arjan took Keith's
original kallsyms work and extended it to the area of kernel oopsing and
stack trace printing - this was the 2.4 kksymoops patch. Which i ported to
2.5 and added some minor fixes, which Kai improved significantly -
essencially Kai rewrote much of the original patch - it's now a nice patch
that fits into the 2.5 build system properly.

Here's an (incomplete) list of Kai's changes:

o switched from a four-stage to a two-stage process.

o moved the new __kallsyms section to the end of vmlinux, so adding this
  section it shouldn't affect the addresses of the other symbols, which
  are lower.

o only zero out the actual .bss

o move print_modules() into module.c - it doesn't really have anything 
  to do with kallsyms. Also, since it provides a large buffer, I made it
  actually use it, not truncate to 80 chars (maybe truncating makes sense,
  but then one should resize the buffer)

o move lookup_symbol() into module.c - it's also useful when 
  CONFIG_KALLSYMS is not set (and I killed the ifdefs from kallsyms.c, we
  now only compile it depending on CONFIG_KALLSYMS). When it cannot
  resolve symbols using kallsyms, it still tries to use the list of 
  exported symbols (that's  somewhat better than nothing, but not sure 
  if really useful)

o kallsyms.c used some rather twisted way to get the list of modules
  ("module_list") instead of just using the global symbol defined in
  kernel/module.c, so I threw that code out.
  kallsyms.c provides three functions, only one of which is actually used
  for kksymoops - I left them all in unconditionally, though, I think
  kdb or sth uses them.

o __{start,stop}___kallsyms needs to be exported, since insmod looks
  for these symbols to determine if the kernel has kallsyms support
  (and if so, automatically adds the information to the module inserted)

--- linux/arch/i386/kernel/head.S.orig	Fri Sep 20 17:20:16 2002
+++ linux/arch/i386/kernel/head.S	Wed Sep 25 10:49:32 2002
@@ -121,7 +121,7 @@
  */
 	xorl %eax,%eax
 	movl $__bss_start,%edi
-	movl $_end,%ecx
+	movl $__bss_stop,%ecx
 	subl %edi,%ecx
 	rep
 	stosb
--- linux/arch/i386/kernel/process.c.orig	Wed Sep 25 10:49:32 2002
+++ linux/arch/i386/kernel/process.c	Wed Sep 25 10:49:32 2002
@@ -159,14 +159,12 @@
 void show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
-	static char buffer[MAX_SYMBOL_SIZE];
 
 	printk("\n");
 	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
 	printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
+	print_symbol("EIP is at %s\n", regs->eip);
 
-	lookup_symbol(regs->eip, buffer, MAX_SYMBOL_SIZE);
-	printk("\nEIP is at %s \n", buffer);
 	if (regs->xcs & 3)
 		printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
 	printk(" EFLAGS: %08lx    %s\n",regs->eflags, print_tainted());
--- linux/arch/i386/kernel/traps.c.orig	Wed Sep 25 10:49:32 2002
+++ linux/arch/i386/kernel/traps.c	Wed Sep 25 10:49:32 2002
@@ -132,8 +132,6 @@
 {
 	int i;
 	unsigned long addr;
-	/* static to not take up stackspace; if we race here too bad */
-	static char buffer[MAX_SYMBOL_SIZE];
 
 	if (!stack)
 		stack = (unsigned long*)&stack;
@@ -143,9 +141,12 @@
 	while (((long) stack & (THREAD_SIZE-1)) != 0) {
 		addr = *stack++;
 		if (kernel_text_address(addr)) {
-			lookup_symbol(addr, buffer, MAX_SYMBOL_SIZE);
-			printk("[<%08lx>] %s \n", addr,buffer);
-			i++;
+			printk("[<%08lx>] ", addr);
+			if (print_symbol("%s\n", addr)) {
+				/* save screen space */
+				if ((i++ % 6) == 0)
+					printk("\n   ");
+			}
 		}
 	}
 	printk("\n");
@@ -198,7 +199,6 @@
 	int in_kernel = 1;
 	unsigned long esp;
 	unsigned short ss;
-	static char buffer[MAX_SYMBOL_SIZE];
 
 	esp = (unsigned long) (&regs->esp);
 	ss = __KERNEL_DS;
@@ -207,12 +207,11 @@
 		esp = regs->esp;
 		ss = regs->xss & 0xffff;
 	}
-
 	print_modules();
-	lookup_symbol(regs->eip, buffer, MAX_SYMBOL_SIZE);
 	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx\n",
 		smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
-	printk("\nEIP is at %s \n",buffer);
+
+	print_symbol("EIP is at %s\n", regs->eip);
 	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
 		regs->eax, regs->ebx, regs->ecx, regs->edx);
 	printk("esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
--- linux/arch/i386/Config.help.orig	Fri Sep 20 17:20:16 2002
+++ linux/arch/i386/Config.help	Wed Sep 25 10:49:32 2002
@@ -946,6 +946,11 @@
   of the BUG call as well as the EIP and oops trace.  This aids
   debugging but costs about 70-100K of memory.
 
+CONFIG_KALLSYMS
+  Say Y here to let the kernel print out symbolic crash information and
+  symbolic stack backtraces. This increases the size of the kernel
+  somewhat, as all symbols have to be loaded into the kernel image.
+
 CONFIG_DEBUG_OBSOLETE
   Say Y here if you want to reduce the chances of the tree compiling,
   and are prepared to dig into driver internals to fix compile errors.
--- linux/arch/i386/config.in.orig	Wed Sep 25 10:28:11 2002
+++ linux/arch/i386/config.in	Wed Sep 25 10:49:32 2002
@@ -435,6 +435,7 @@
    if [ "$CONFIG_HIGHMEM" = "y" ]; then
       bool '  Highmem debugging' CONFIG_DEBUG_HIGHMEM
    fi
+   bool '  Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS
 fi
 
 if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then
--- linux/arch/i386/vmlinux.lds.S.orig	Fri Sep 20 17:20:19 2002
+++ linux/arch/i386/vmlinux.lds.S	Wed Sep 25 10:49:32 2002
@@ -78,9 +78,13 @@
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
   __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
+  .bss : { *(.bss) }
+  __bss_stop = .; 
+
+  __start___kallsyms = .;     /* All kernel symbols */
+  __kallsyms : { *(__kallsyms) }
+  __stop___kallsyms = .;
+
   _end = . ;
 
   /* Sections to be discarded */
--- linux/include/linux/kallsyms.h.orig	Wed Sep 25 10:49:32 2002
+++ linux/include/linux/kallsyms.h	Wed Sep 25 10:49:32 2002
@@ -0,0 +1,163 @@
+/* kallsyms headers
+   Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+   This file is part of the Linux modutils.  It is exported to kernel
+   space so debuggers can access the kallsyms data.
+
+   The kallsyms data contains all the non-stack symbols from a kernel
+   or a module.  The kernel symbols are held between __start___kallsyms
+   and __stop___kallsyms.  The symbols for a module are accessed via
+   the struct module chain which is based at module_list.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ident "$Id: linux-2.4.9-kallsyms.patch,v 1.8 2002/02/11 18:34:53 arjanv Exp $"
+
+#ifndef MODUTILS_KALLSYMS_H
+#define MODUTILS_KALLSYMS_H 1
+
+/* Have to (re)define these ElfW entries here because external kallsyms
+ * code does not have access to modutils/include/obj.h.  This code is
+ * included from user spaces tools (modutils) and kernel, they need
+ * different includes.
+ */
+
+#ifndef ELFCLASS32
+#ifdef __KERNEL__
+#include <linux/elf.h>
+#else	/* __KERNEL__ */
+#include <elf.h>
+#endif	/* __KERNEL__ */
+#endif	/* ELFCLASS32 */
+
+#ifndef ELFCLASSM
+#define ELFCLASSM ELF_CLASS
+#endif
+
+#ifndef ElfW
+# if ELFCLASSM == ELFCLASS32
+#  define ElfW(x)  Elf32_ ## x
+#  define ELFW(x)  ELF32_ ## x
+# else
+#  define ElfW(x)  Elf64_ ## x
+#  define ELFW(x)  ELF64_ ## x
+# endif
+#endif
+
+/* Format of data in the kallsyms section.
+ * Most of the fields are small numbers but the total size and all
+ * offsets can be large so use the 32/64 bit types for these fields.
+ *
+ * Do not use sizeof() on these structures, modutils may be using extra
+ * fields.  Instead use the size fields in the header to access the
+ * other bits of data.
+ */  
+
+struct kallsyms_header {
+	int		size;		/* Size of this header */
+	ElfW(Word)	total_size;	/* Total size of kallsyms data */
+	int		sections;	/* Number of section entries */
+	ElfW(Off)	section_off;	/* Offset to first section entry */
+	int		section_size;	/* Size of one section entry */
+	int		symbols;	/* Number of symbol entries */
+	ElfW(Off)	symbol_off;	/* Offset to first symbol entry */
+	int		symbol_size;	/* Size of one symbol entry */
+	ElfW(Off)	string_off;	/* Offset to first string */
+	ElfW(Addr)	start;		/* Start address of first section */
+	ElfW(Addr)	end;		/* End address of last section */
+};
+
+struct kallsyms_section {
+	ElfW(Addr)	start;		/* Start address of section */
+	ElfW(Word)	size;		/* Size of this section */
+	ElfW(Off)	name_off;	/* Offset to section name */
+	ElfW(Word)	flags;		/* Flags from section */
+};
+
+struct kallsyms_symbol {
+	ElfW(Off)	section_off;	/* Offset to section that owns this symbol */
+	ElfW(Addr)	symbol_addr;	/* Address of symbol */
+	ElfW(Off)	name_off;	/* Offset to symbol name */
+};
+
+#define KALLSYMS_SEC_NAME "__kallsyms"
+#define KALLSYMS_IDX 2			/* obj_kallsyms creates kallsyms as section 2 */
+
+#define kallsyms_next_sec(h,s) \
+	((s) = (struct kallsyms_section *)((char *)(s) + (h)->section_size))
+#define kallsyms_next_sym(h,s) \
+	((s) = (struct kallsyms_symbol *)((char *)(s) + (h)->symbol_size))
+
+#ifdef CONFIG_KALLSYMS
+
+int kallsyms_symbol_to_address(
+	const char       *name,			/* Name to lookup */
+	unsigned long    *token,		/* Which module to start with */
+	const char      **mod_name,		/* Set to module name or "kernel" */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	);
+
+int kallsyms_address_to_symbol(
+	unsigned long     address,		/* Address to lookup */
+	const char      **mod_name,		/* Set to module name */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	);
+
+int kallsyms_sections(void *token,
+		      int (*callback)(void *,	/* token */
+		      	const char *,		/* module name */
+			const char *,		/* section name */
+			ElfW(Addr),		/* Section start */
+			ElfW(Addr),		/* Section end */
+			ElfW(Word)		/* Section flags */
+		      )
+		);
+
+#else
+
+static inline int kallsyms_address_to_symbol(
+	unsigned long     address,		/* Address to lookup */
+	const char      **mod_name,		/* Set to module name */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	)
+{
+	return -ESRCH;
+}
+
+#endif
+
+#endif /* kallsyms.h */
--- linux/include/linux/module.h.orig	Wed Sep 25 10:49:32 2002
+++ linux/include/linux/module.h	Wed Sep 25 10:49:32 2002
@@ -504,19 +504,26 @@
 #define SET_MODULE_OWNER(some_struct) do { } while (0)
 #endif
 
+extern void print_modules(void);
+
 #if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
 
 extern struct module *module_list;
 
-extern int lookup_symbol(unsigned long address, char *buffer, int buflen);
+/*
+ * print_symbols takes a format string containing one %s.
+ * If support for resolving symbols is compiled in, the %s will
+ * be replaced by the closest symbol to the address and the entire
+ * string is printk()ed. Otherwise, nothing is printed.
+ */
+extern int print_symbol(const char *fmt, unsigned long address);
 
 #else
 
 static inline int
-lookup_symbol(unsigned long address, char *buffer, int buflen)
+print_symbol(const char *fmt, unsigned long address)
 {
-	buffer[0] = 0;
-	return 0;
+	return -ESRCH;
 }
 
 #endif
--- linux/include/linux/sched.h.orig	Wed Sep 25 10:49:32 2002
+++ linux/include/linux/sched.h	Wed Sep 25 10:49:32 2002
@@ -152,12 +152,9 @@
 extern void sched_init(void);
 extern void init_idle(task_t *idle, int cpu);
 
-#define MAX_SYMBOL_SIZE 512
-
 extern void show_state(void);
 extern void show_trace(unsigned long *stack);
 extern void show_stack(unsigned long *stack);
-extern void print_modules(void);
 extern void show_regs(struct pt_regs *);
 
 
--- linux/include/asm-i386/hardirq.h.orig	Fri Sep 20 17:20:32 2002
+++ linux/include/asm-i386/hardirq.h	Wed Sep 25 10:49:32 2002
@@ -97,6 +97,4 @@
   extern void synchronize_irq(unsigned int irq);
 #endif /* CONFIG_SMP */
 
-extern void show_stack(unsigned long * esp);
-
 #endif /* __ASM_HARDIRQ_H */
--- linux/include/asm-i386/ptrace.h.orig	Fri Sep 20 17:20:16 2002
+++ linux/include/asm-i386/ptrace.h	Wed Sep 25 10:49:32 2002
@@ -57,7 +57,6 @@
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
 #define instruction_pointer(regs) ((regs)->eip)
-extern void show_regs(struct pt_regs *);
 #endif
 
 #endif
--- linux/kernel/Makefile.orig	Fri Sep 20 17:20:19 2002
+++ linux/kernel/Makefile	Wed Sep 25 10:49:32 2002
@@ -3,7 +3,7 @@
 #
 
 export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
-		printk.o platform.o suspend.o dma.o
+	      printk.o platform.o suspend.o dma.o module.o
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o time.o softirq.o resource.o \
@@ -14,6 +14,7 @@
 obj-$(CONFIG_SMP) += cpu.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
+obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += pm.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
--- linux/kernel/kallsyms.c.orig	Wed Sep 25 10:49:32 2002
+++ linux/kernel/kallsyms.c	Wed Sep 25 10:49:32 2002
@@ -0,0 +1,227 @@
+/*
+ * kksymoops.c: in-kernel printing of symbolic oopses and stack traces.
+ *
+ *  Copyright 2000 Keith Owens <kaos@ocs.com.au> April 2000
+ *  Copyright 2002 Arjan van de Ven <arjanv@redhat.com>
+ *
+   This code uses the list of all kernel and module symbols to :-
+
+   * Find any non-stack symbol in a kernel or module.  Symbols do
+     not have to be exported for debugging.
+
+   * Convert an address to the module (or kernel) that owns it, the
+     section it is in and the nearest symbol.  This finds all non-stack
+     symbols, not just exported ones.
+
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+
+/* A symbol can appear in more than one module.  A token is used to
+ * restart the scan at the next module, set the token to 0 for the
+ * first scan of each symbol.
+ */
+
+int kallsyms_symbol_to_address(
+	const char	 *name,		/* Name to lookup */
+	unsigned long 	 *token,	/* Which module to start at */
+	const char	**mod_name,	/* Set to module name */
+	unsigned long 	 *mod_start,	/* Set to start address of module */
+	unsigned long 	 *mod_end,	/* Set to end address of module */
+	const char	**sec_name,	/* Set to section name */
+	unsigned long 	 *sec_start,	/* Set to start address of section */
+	unsigned long 	 *sec_end,	/* Set to end address of section */
+	const char	**sym_name,	/* Set to full symbol name */
+	unsigned long 	 *sym_start,	/* Set to start address of symbol */
+	unsigned long 	 *sym_end	/* Set to end address of symbol */
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec;
+	const struct kallsyms_symbol	*ka_sym = NULL;
+	const char			*ka_str = NULL;
+	const struct module *m;
+	int i = 0, l;
+	const char *p, *pt_R;
+	char *p2;
+
+	/* Restart? */
+	m = module_list;
+	if (token && *token) {
+		for (; m; m = m->next)
+			if ((unsigned long)m == *token)
+				break;
+		if (m)
+			m = m->next;
+	}
+
+	for (; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sym = (struct kallsyms_symbol *)
+			((char *)(ka_hdr) + ka_hdr->symbol_off);
+		ka_str = 
+			((char *)(ka_hdr) + ka_hdr->string_off);
+		for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+			p = ka_str + ka_sym->name_off;
+			if (strcmp(p, name) == 0)
+				break;
+			/* Unversioned requests match versioned names */
+			if (!(pt_R = strstr(p, "_R")))
+				continue;
+			l = strlen(pt_R);
+			if (l < 10)
+				continue;	/* Not _R.*xxxxxxxx */
+			(void)simple_strtoul(pt_R+l-8, &p2, 16);
+			if (*p2)
+				continue;	/* Not _R.*xxxxxxxx */
+			if (strncmp(p, name, pt_R-p) == 0)
+				break;	/* Match with version */
+		}
+		if (i < ka_hdr->symbols)
+			break;
+	}
+
+	if (token)
+		*token = (unsigned long)m;
+	if (!m)
+		return(0);	/* not found */
+
+	ka_sec = (const struct kallsyms_section *)
+		((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off);
+	*mod_name = *(m->name) ? m->name : "kernel";
+	*mod_start = ka_hdr->start;
+	*mod_end = ka_hdr->end;
+	*sec_name = ka_sec->name_off + ka_str;
+	*sec_start = ka_sec->start;
+	*sec_end = ka_sec->start + ka_sec->size;
+	*sym_name = ka_sym->name_off + ka_str;
+	*sym_start = ka_sym->symbol_addr;
+	if (i < ka_hdr->symbols-1) {
+		const struct kallsyms_symbol *ka_symn = ka_sym;
+		kallsyms_next_sym(ka_hdr, ka_symn);
+		*sym_end = ka_symn->symbol_addr;
+	}
+	else
+		*sym_end = *sec_end;
+	return(1);
+}
+
+int kallsyms_address_to_symbol(
+	unsigned long	  address,	/* Address to lookup */
+	const char	**mod_name,	/* Set to module name */
+	unsigned long 	 *mod_start,	/* Set to start address of module */
+	unsigned long 	 *mod_end,	/* Set to end address of module */
+	const char	**sec_name,	/* Set to section name */
+	unsigned long 	 *sec_start,	/* Set to start address of section */
+	unsigned long 	 *sec_end,	/* Set to end address of section */
+	const char	**sym_name,	/* Set to full symbol name */
+	unsigned long 	 *sym_start,	/* Set to start address of symbol */
+	unsigned long 	 *sym_end	/* Set to end address of symbol */
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec = NULL;
+	const struct kallsyms_symbol	*ka_sym;
+	const char			*ka_str;
+	const struct module *m;
+	int i;
+	unsigned long end;
+
+	for (m = module_list; m; m = m->next) {
+	  
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sec = (const struct kallsyms_section *)
+			((char *)ka_hdr + ka_hdr->section_off);
+		/* Is the address in any section in this module? */
+		for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) {
+			if (ka_sec->start <= address &&
+			    (ka_sec->start + ka_sec->size) > address)
+				break;
+		}
+		if (i < ka_hdr->sections)
+			break;	/* Found a matching section */
+	}
+
+	if (!m)
+		return(0);	/* not found */
+
+	ka_sym = (struct kallsyms_symbol *)
+		((char *)(ka_hdr) + ka_hdr->symbol_off);
+	ka_str = 
+		((char *)(ka_hdr) + ka_hdr->string_off);
+	*mod_name = m->name;
+	*mod_start = ka_hdr->start;
+	*mod_end = ka_hdr->end;
+	*sec_name = ka_sec->name_off + ka_str;
+	*sec_start = ka_sec->start;
+	*sec_end = ka_sec->start + ka_sec->size;
+	*sym_name = *sec_name;		/* In case we find no matching symbol */
+	*sym_start = *sec_start;
+	*sym_end = *sec_end;
+
+	for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+		if (ka_sym->symbol_addr > address)
+			continue;
+		if (i < ka_hdr->symbols-1) {
+			const struct kallsyms_symbol *ka_symn = ka_sym;
+			kallsyms_next_sym(ka_hdr, ka_symn);
+			end = ka_symn->symbol_addr;
+		}
+		else
+			end = *sec_end;
+		if (end <= address)
+			continue;
+		if ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off
+		    != (char *)ka_sec)
+			continue;	/* wrong section */
+		*sym_name = ka_str + ka_sym->name_off;
+		*sym_start = ka_sym->symbol_addr;
+		*sym_end = end;
+		break;
+	}
+	return(1);
+}
+
+/* List all sections in all modules.  The callback routine is invoked with
+ * token, module name, section name, section start, section end, section flags.
+ */
+int kallsyms_sections(void *token,
+		      int (*callback)(void *, const char *, const char *, ElfW(Addr), ElfW(Addr), ElfW(Word)))
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec = NULL;
+	const char			*ka_str;
+	const struct module *m;
+	int i;
+
+	for (m = module_list; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sec = (const struct kallsyms_section *) ((char *)ka_hdr + ka_hdr->section_off);
+		ka_str = ((char *)(ka_hdr) + ka_hdr->string_off);
+		for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) {
+			if (callback(
+				token,
+				*(m->name) ? m->name : "kernel",
+				ka_sec->name_off + ka_str,
+				ka_sec->start,
+				ka_sec->start + ka_sec->size,
+				ka_sec->flags))
+				return(0);
+		}
+	}
+	return(1);
+}
--- linux/kernel/module.c.orig	Wed Sep 25 10:49:32 2002
+++ linux/kernel/module.c	Wed Sep 25 10:49:32 2002
@@ -1305,51 +1305,51 @@
 
 #if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
 
-int lookup_symbol(unsigned long address, char *buffer, int buflen)
+#define MAX_SYMBOL_SIZE 512
+
+int print_symbol(const char *fmt, unsigned long address)
 {
 	struct module *this_mod;
 	unsigned long bestsofar;
+	/* static to not take up stackspace; if we race here too bad */
+	static char buffer[MAX_SYMBOL_SIZE];
 
 	const char *mod_name = NULL, *sec_name = NULL, *sym_name = NULL;
 	unsigned long mod_start, mod_end, sec_start, sec_end,
 							sym_start, sym_end;
 	
-	if (!buffer)
-		return -EFAULT;
-	
-	if (buflen < 256)
-		return -ENOMEM;
-	
-	memset(buffer, 0, buflen);
+	memset(buffer, 0, MAX_SYMBOL_SIZE);
 
 	if (!kallsyms_address_to_symbol(address,&mod_name,&mod_start,&mod_end,&sec_name, &sec_start, &sec_end, &sym_name, &sym_start, &sym_end)) {
-		/* kallsyms doesn't have a clue; lets try harder */
+		/* kallsyms doesn't have a clue; lets try our list 
+		 * of exported symbols */
 		bestsofar = 0;
-		snprintf(buffer, buflen-1, "[unresolved]");
+		sprintf(buffer, "[unresolved]");
 		
-		this_mod = module_list;
-
-		while (this_mod != NULL) {
+		for (this_mod = module_list; this_mod; this_mod = this_mod->next) {
 			int i;
 			/* walk the symbol list of this module. Only symbols
 			   who's address is smaller than the searched for address
 			   are relevant; and only if it's better than the best so far */
 			for (i = 0; i < this_mod->nsyms; i++)
 				if ((this_mod->syms[i].value <= address) &&
-					(bestsofar<this_mod->syms[i].value)) {
-					snprintf(buffer,buflen-1,"%s [%s] 0x%x",
+				    (bestsofar < this_mod->syms[i].value)) {
+					snprintf(buffer, MAX_SYMBOL_SIZE - 1,
+						 "%s [%s] 0x%x",
 						this_mod->syms[i].name,
 						this_mod->name,
 						(unsigned int)(address - this_mod->syms[i].value));
 					bestsofar = this_mod->syms[i].value;
 				}
-			this_mod = this_mod->next;
 		}
 
-	} else /* kallsyms success */
-		snprintf(buffer,buflen-1,"%s [%s] 0x%x",sym_name,mod_name,(unsigned int)(address-sym_start));
-
-	return strlen(buffer);
+	} else { /* kallsyms success */
+		snprintf(buffer,MAX_SYMBOL_SIZE - 1, "%s [%s] 0x%x",
+			 sym_name, mod_name,
+			 (unsigned int)(address - sym_start));
+	}
+	printk(fmt, buffer);
+	return 0;
 }
 
 #endif
--- linux/Makefile.orig	Wed Sep 25 10:49:32 2002
+++ linux/Makefile	Wed Sep 25 10:49:32 2002
@@ -331,9 +331,13 @@
 .tmp_kallsyms.o: .tmp_vmlinux
 	$(call cmd,kallsyms)
 
+# 	After generating .tmp_vmlinux just like vmlinux, decrement the version
+#	number again, so the final vmlinux gets the same one.
+#	Ignore return value of 'expr'.
+
 define rule_.tmp_vmlinux
 	$(rule_vmlinux)
-	expr 0`cat .version` - 1 > .tmp_version
+	if expr 0`cat .version` - 1 > .tmp_version; then true; fi
 	mv -f .tmp_version .version
 endef
 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [re-ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25  9:02 [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0 Ingo Molnar
@ 2002-09-25  9:32 ` Ingo Molnar
  2002-09-25  9:51   ` Arnaldo Carvalho de Melo
  2002-09-25 18:16 ` [ANNOUNCE] " Linus Torvalds
  1 sibling, 1 reply; 23+ messages in thread
From: Ingo Molnar @ 2002-09-25  9:32 UTC (permalink / raw)
  To: linux-kernel
  Cc: Linus Torvalds, Kai Germaschewski, Rusty Russell, Arjan van de Ven


okay, this time the correct patch against BK-curr is included:

diff -rNu linux.orig/Makefile linux/Makefile
--- linux.orig/Makefile	Wed Sep 25 11:30:13 2002
+++ linux/Makefile	Wed Sep 25 11:26:11 2002
@@ -138,6 +138,7 @@
 MAKEFILES	= $(TOPDIR)/.config
 GENKSYMS	= /sbin/genksyms
 DEPMOD		= /sbin/depmod
+KALLSYMS	= /sbin/kallsyms
 PERL		= perl
 MODFLAGS	= -DMODULE
 CFLAGS_MODULE   = $(MODFLAGS)
@@ -291,32 +292,64 @@
 vmlinux-objs := $(HEAD) $(INIT) $(CORE_FILES) $(LIBS) $(DRIVERS) $(NETWORKS)
 
 quiet_cmd_link_vmlinux = LD      $@
-cmd_link_vmlinux = $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $(HEAD) $(INIT) \
-		--start-group \
-		$(CORE_FILES) \
-		$(LIBS) \
-		$(DRIVERS) \
-		$(NETWORKS) \
-		--end-group \
-		-o vmlinux
+define cmd_link_vmlinux
+	$(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) $(HEAD) $(INIT) \
+	--start-group \
+	$(CORE_FILES) \
+	$(LIBS) \
+	$(DRIVERS) \
+	$(NETWORKS) \
+	--end-group \
+	$(filter $(kallsyms.o),$^) \
+	-o $@
+endef
 
 #	set -e makes the rule exit immediately on error
 
-define rule_link_vmlinux
+define rule_vmlinux
 	set -e
 	echo '  Generating build number'
-	. scripts/mkversion > .tmpversion
-	mv -f .tmpversion .version
+	. scripts/mkversion > .tmp_version
+	mv -f .tmp_version .version
 	+$(MAKE) -C init
 	$(call cmd,link_vmlinux)
 	echo 'cmd_$@ := $(cmd_link_vmlinux)' > $(@D)/.$(@F).cmd
-	$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
+	$(NM) $@ | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
 endef
 
 LDFLAGS_vmlinux += -T arch/$(ARCH)/vmlinux.lds.s
 
-vmlinux: $(vmlinux-objs) arch/$(ARCH)/vmlinux.lds.s FORCE
-	$(call if_changed_rule,link_vmlinux)
+#	Generate section listing all symbols and add it into vmlinux
+
+ifdef CONFIG_KALLSYMS
+
+kallsyms.o := .tmp_kallsyms.o
+
+quiet_cmd_kallsyms = KSYM    $@
+cmd_kallsyms = $(KALLSYMS) $< > $@
+
+.tmp_kallsyms.o: .tmp_vmlinux
+	$(call cmd,kallsyms)
+
+# 	After generating .tmp_vmlinux just like vmlinux, decrement the version
+#	number again, so the final vmlinux gets the same one.
+#	Ignore return value of 'expr'.
+
+define rule_.tmp_vmlinux
+	$(rule_vmlinux)
+	if expr 0`cat .version` - 1 > .tmp_version; then true; fi
+	mv -f .tmp_version .version
+endef
+
+.tmp_vmlinux: $(vmlinux-objs) arch/$(ARCH)/vmlinux.lds.s FORCE
+	$(call if_changed_rule,.tmp_vmlinux)
+
+endif
+
+#	Finally the vmlinux rule
+
+vmlinux: $(vmlinux-objs) $(kallsyms.o) arch/$(ARCH)/vmlinux.lds.s FORCE
+	$(call if_changed_rule,vmlinux)
 
 #	The actual objects are generated when descending, 
 #	make sure no implicit rule kicks in
@@ -820,7 +853,7 @@
 
 # FIXME Should go into a make.lib or something 
 # ===========================================================================
-echo_target = $(RELDIR)/$@
+echo_target = $@
 
 a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(NOSTDINC_FLAGS) \
 	  $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
diff -rNu linux.orig/arch/i386/Config.help linux/arch/i386/Config.help
--- linux.orig/arch/i386/Config.help	Fri Sep 20 17:20:16 2002
+++ linux/arch/i386/Config.help	Wed Sep 25 11:26:11 2002
@@ -946,6 +946,11 @@
   of the BUG call as well as the EIP and oops trace.  This aids
   debugging but costs about 70-100K of memory.
 
+CONFIG_KALLSYMS
+  Say Y here to let the kernel print out symbolic crash information and
+  symbolic stack backtraces. This increases the size of the kernel
+  somewhat, as all symbols have to be loaded into the kernel image.
+
 CONFIG_DEBUG_OBSOLETE
   Say Y here if you want to reduce the chances of the tree compiling,
   and are prepared to dig into driver internals to fix compile errors.
diff -rNu linux.orig/arch/i386/config.in linux/arch/i386/config.in
--- linux.orig/arch/i386/config.in	Wed Sep 25 11:30:13 2002
+++ linux/arch/i386/config.in	Wed Sep 25 11:26:11 2002
@@ -435,6 +435,7 @@
    if [ "$CONFIG_HIGHMEM" = "y" ]; then
       bool '  Highmem debugging' CONFIG_DEBUG_HIGHMEM
    fi
+   bool '  Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS
 fi
 
 if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then
diff -rNu linux.orig/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- linux.orig/arch/i386/kernel/head.S	Fri Sep 20 17:20:16 2002
+++ linux/arch/i386/kernel/head.S	Wed Sep 25 11:26:11 2002
@@ -121,7 +121,7 @@
  */
 	xorl %eax,%eax
 	movl $__bss_start,%edi
-	movl $_end,%ecx
+	movl $__bss_stop,%ecx
 	subl %edi,%ecx
 	rep
 	stosb
diff -rNu linux.orig/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- linux.orig/arch/i386/kernel/process.c	Fri Sep 20 17:20:12 2002
+++ linux/arch/i386/kernel/process.c	Wed Sep 25 11:26:11 2002
@@ -33,6 +33,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/mc146818rtc.h>
+#include <linux/module.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -155,8 +156,6 @@
 
 __setup("idle=", idle_setup);
 
-extern void show_trace(unsigned long* esp);
-
 void show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
@@ -164,6 +163,8 @@
 	printk("\n");
 	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
 	printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
+	print_symbol("EIP is at %s\n", regs->eip);
+
 	if (regs->xcs & 3)
 		printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
 	printk(" EFLAGS: %08lx    %s\n",regs->eflags, print_tainted());
diff -rNu linux.orig/arch/i386/kernel/process.c.rej linux/arch/i386/kernel/process.c.rej
--- linux.orig/arch/i386/kernel/process.c.rej	Thu Jan  1 01:00:00 1970
+++ linux/arch/i386/kernel/process.c.rej	Wed Sep 25 11:25:33 2002
@@ -0,0 +1,29 @@
+***************
+*** 159,172 ****
+  void show_regs(struct pt_regs * regs)
+  {
+  	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
+- 	static char buffer[MAX_SYMBOL_SIZE];
+  
+  	printk("\n");
+  	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
+  	printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
+  
+- 	lookup_symbol(regs->eip, buffer, MAX_SYMBOL_SIZE);
+- 	printk("\nEIP is at %s \n", buffer);
+  	if (regs->xcs & 3)
+  		printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
+  	printk(" EFLAGS: %08lx    %s\n",regs->eflags, print_tainted());
+--- 159,170 ----
+  void show_regs(struct pt_regs * regs)
+  {
+  	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
+  
+  	printk("\n");
+  	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
+  	printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
++ 	print_symbol("EIP is at %s\n", regs->eip);
+  
+  	if (regs->xcs & 3)
+  		printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
+  	printk(" EFLAGS: %08lx    %s\n",regs->eflags, print_tainted());
diff -rNu linux.orig/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- linux.orig/arch/i386/kernel/traps.c	Fri Sep 20 17:20:19 2002
+++ linux/arch/i386/kernel/traps.c	Wed Sep 25 11:26:11 2002
@@ -94,7 +94,6 @@
 
 #ifdef CONFIG_MODULES
 
-extern struct module *module_list;
 extern struct module kernel_module;
 
 static inline int kernel_text_address(unsigned long addr)
@@ -142,10 +141,12 @@
 	while (((long) stack & (THREAD_SIZE-1)) != 0) {
 		addr = *stack++;
 		if (kernel_text_address(addr)) {
-			if (i && ((i % 6) == 0))
-				printk("\n   ");
 			printk("[<%08lx>] ", addr);
-			i++;
+			if (print_symbol("%s\n", addr)) {
+				/* save screen space */
+				if ((i++ % 6) == 0)
+					printk("\n   ");
+			}
 		}
 	}
 	printk("\n");
@@ -206,8 +207,11 @@
 		esp = regs->esp;
 		ss = regs->xss & 0xffff;
 	}
+	print_modules();
 	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx\n",
 		smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
+
+	print_symbol("EIP is at %s\n", regs->eip);
 	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
 		regs->eax, regs->ebx, regs->ecx, regs->edx);
 	printk("esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
@@ -268,6 +272,7 @@
 		(unsigned long)file < PAGE_OFFSET || __get_user(c, file))
 		file = "<bad filename>";
 
+	printk("------------[ cut here ]------------\n");
 	printk("kernel BUG at %s:%d!\n", file, line);
 
 no_bug:
diff -rNu linux.orig/arch/i386/vmlinux.lds.S linux/arch/i386/vmlinux.lds.S
--- linux.orig/arch/i386/vmlinux.lds.S	Fri Sep 20 17:20:19 2002
+++ linux/arch/i386/vmlinux.lds.S	Wed Sep 25 11:26:11 2002
@@ -78,9 +78,13 @@
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
   __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
+  .bss : { *(.bss) }
+  __bss_stop = .; 
+
+  __start___kallsyms = .;     /* All kernel symbols */
+  __kallsyms : { *(__kallsyms) }
+  __stop___kallsyms = .;
+
   _end = . ;
 
   /* Sections to be discarded */
diff -rNu linux.orig/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h
--- linux.orig/include/asm-i386/hardirq.h	Fri Sep 20 17:20:32 2002
+++ linux/include/asm-i386/hardirq.h	Wed Sep 25 11:26:11 2002
@@ -97,6 +97,4 @@
   extern void synchronize_irq(unsigned int irq);
 #endif /* CONFIG_SMP */
 
-extern void show_stack(unsigned long * esp);
-
 #endif /* __ASM_HARDIRQ_H */
diff -rNu linux.orig/include/asm-i386/ptrace.h linux/include/asm-i386/ptrace.h
--- linux.orig/include/asm-i386/ptrace.h	Fri Sep 20 17:20:16 2002
+++ linux/include/asm-i386/ptrace.h	Wed Sep 25 11:26:11 2002
@@ -57,7 +57,6 @@
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
 #define instruction_pointer(regs) ((regs)->eip)
-extern void show_regs(struct pt_regs *);
 #endif
 
 #endif
diff -rNu linux.orig/include/linux/kallsyms.h linux/include/linux/kallsyms.h
--- linux.orig/include/linux/kallsyms.h	Thu Jan  1 01:00:00 1970
+++ linux/include/linux/kallsyms.h	Wed Sep 25 11:26:11 2002
@@ -0,0 +1,163 @@
+/* kallsyms headers
+   Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+   This file is part of the Linux modutils.  It is exported to kernel
+   space so debuggers can access the kallsyms data.
+
+   The kallsyms data contains all the non-stack symbols from a kernel
+   or a module.  The kernel symbols are held between __start___kallsyms
+   and __stop___kallsyms.  The symbols for a module are accessed via
+   the struct module chain which is based at module_list.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ident "$Id: linux-2.4.9-kallsyms.patch,v 1.8 2002/02/11 18:34:53 arjanv Exp $"
+
+#ifndef MODUTILS_KALLSYMS_H
+#define MODUTILS_KALLSYMS_H 1
+
+/* Have to (re)define these ElfW entries here because external kallsyms
+ * code does not have access to modutils/include/obj.h.  This code is
+ * included from user spaces tools (modutils) and kernel, they need
+ * different includes.
+ */
+
+#ifndef ELFCLASS32
+#ifdef __KERNEL__
+#include <linux/elf.h>
+#else	/* __KERNEL__ */
+#include <elf.h>
+#endif	/* __KERNEL__ */
+#endif	/* ELFCLASS32 */
+
+#ifndef ELFCLASSM
+#define ELFCLASSM ELF_CLASS
+#endif
+
+#ifndef ElfW
+# if ELFCLASSM == ELFCLASS32
+#  define ElfW(x)  Elf32_ ## x
+#  define ELFW(x)  ELF32_ ## x
+# else
+#  define ElfW(x)  Elf64_ ## x
+#  define ELFW(x)  ELF64_ ## x
+# endif
+#endif
+
+/* Format of data in the kallsyms section.
+ * Most of the fields are small numbers but the total size and all
+ * offsets can be large so use the 32/64 bit types for these fields.
+ *
+ * Do not use sizeof() on these structures, modutils may be using extra
+ * fields.  Instead use the size fields in the header to access the
+ * other bits of data.
+ */  
+
+struct kallsyms_header {
+	int		size;		/* Size of this header */
+	ElfW(Word)	total_size;	/* Total size of kallsyms data */
+	int		sections;	/* Number of section entries */
+	ElfW(Off)	section_off;	/* Offset to first section entry */
+	int		section_size;	/* Size of one section entry */
+	int		symbols;	/* Number of symbol entries */
+	ElfW(Off)	symbol_off;	/* Offset to first symbol entry */
+	int		symbol_size;	/* Size of one symbol entry */
+	ElfW(Off)	string_off;	/* Offset to first string */
+	ElfW(Addr)	start;		/* Start address of first section */
+	ElfW(Addr)	end;		/* End address of last section */
+};
+
+struct kallsyms_section {
+	ElfW(Addr)	start;		/* Start address of section */
+	ElfW(Word)	size;		/* Size of this section */
+	ElfW(Off)	name_off;	/* Offset to section name */
+	ElfW(Word)	flags;		/* Flags from section */
+};
+
+struct kallsyms_symbol {
+	ElfW(Off)	section_off;	/* Offset to section that owns this symbol */
+	ElfW(Addr)	symbol_addr;	/* Address of symbol */
+	ElfW(Off)	name_off;	/* Offset to symbol name */
+};
+
+#define KALLSYMS_SEC_NAME "__kallsyms"
+#define KALLSYMS_IDX 2			/* obj_kallsyms creates kallsyms as section 2 */
+
+#define kallsyms_next_sec(h,s) \
+	((s) = (struct kallsyms_section *)((char *)(s) + (h)->section_size))
+#define kallsyms_next_sym(h,s) \
+	((s) = (struct kallsyms_symbol *)((char *)(s) + (h)->symbol_size))
+
+#ifdef CONFIG_KALLSYMS
+
+int kallsyms_symbol_to_address(
+	const char       *name,			/* Name to lookup */
+	unsigned long    *token,		/* Which module to start with */
+	const char      **mod_name,		/* Set to module name or "kernel" */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	);
+
+int kallsyms_address_to_symbol(
+	unsigned long     address,		/* Address to lookup */
+	const char      **mod_name,		/* Set to module name */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	);
+
+int kallsyms_sections(void *token,
+		      int (*callback)(void *,	/* token */
+		      	const char *,		/* module name */
+			const char *,		/* section name */
+			ElfW(Addr),		/* Section start */
+			ElfW(Addr),		/* Section end */
+			ElfW(Word)		/* Section flags */
+		      )
+		);
+
+#else
+
+static inline int kallsyms_address_to_symbol(
+	unsigned long     address,		/* Address to lookup */
+	const char      **mod_name,		/* Set to module name */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	)
+{
+	return -ESRCH;
+}
+
+#endif
+
+#endif /* kallsyms.h */
diff -rNu linux.orig/include/linux/module.h linux/include/linux/module.h
--- linux.orig/include/linux/module.h	Fri Sep 20 17:20:32 2002
+++ linux/include/linux/module.h	Wed Sep 25 11:26:11 2002
@@ -316,8 +316,6 @@
 #define MOD_DEC_USE_COUNT	do { } while (0)
 #define MOD_IN_USE		1
 
-extern struct module *module_list;
-
 #endif /* !__GENKSYMS__ */
 
 #endif /* MODULE */
@@ -504,6 +502,30 @@
 #define SET_MODULE_OWNER(some_struct) do { (some_struct)->owner = THIS_MODULE; } while (0)
 #else
 #define SET_MODULE_OWNER(some_struct) do { } while (0)
+#endif
+
+extern void print_modules(void);
+
+#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
+
+extern struct module *module_list;
+
+/*
+ * print_symbols takes a format string containing one %s.
+ * If support for resolving symbols is compiled in, the %s will
+ * be replaced by the closest symbol to the address and the entire
+ * string is printk()ed. Otherwise, nothing is printed.
+ */
+extern int print_symbol(const char *fmt, unsigned long address);
+
+#else
+
+static inline int
+print_symbol(const char *fmt, unsigned long address)
+{
+	return -ESRCH;
+}
+
 #endif
 
 #endif /* _LINUX_MODULE_H */
diff -rNu linux.orig/include/linux/sched.h linux/include/linux/sched.h
--- linux.orig/include/linux/sched.h	Wed Sep 25 11:30:14 2002
+++ linux/include/linux/sched.h	Wed Sep 25 11:26:11 2002
@@ -151,7 +151,13 @@
 
 extern void sched_init(void);
 extern void init_idle(task_t *idle, int cpu);
+
 extern void show_state(void);
+extern void show_trace(unsigned long *stack);
+extern void show_stack(unsigned long *stack);
+extern void show_regs(struct pt_regs *);
+
+
 extern void cpu_init (void);
 extern void trap_init(void);
 extern void update_process_times(int user);
diff -rNu linux.orig/kernel/Makefile linux/kernel/Makefile
--- linux.orig/kernel/Makefile	Fri Sep 20 17:20:19 2002
+++ linux/kernel/Makefile	Wed Sep 25 11:26:11 2002
@@ -3,7 +3,7 @@
 #
 
 export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
-		printk.o platform.o suspend.o dma.o
+	      printk.o platform.o suspend.o dma.o module.o
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o time.o softirq.o resource.o \
@@ -14,6 +14,7 @@
 obj-$(CONFIG_SMP) += cpu.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
+obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += pm.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
diff -rNu linux.orig/kernel/kallsyms.c linux/kernel/kallsyms.c
--- linux.orig/kernel/kallsyms.c	Thu Jan  1 01:00:00 1970
+++ linux/kernel/kallsyms.c	Wed Sep 25 11:26:11 2002
@@ -0,0 +1,227 @@
+/*
+ * kksymoops.c: in-kernel printing of symbolic oopses and stack traces.
+ *
+ *  Copyright 2000 Keith Owens <kaos@ocs.com.au> April 2000
+ *  Copyright 2002 Arjan van de Ven <arjanv@redhat.com>
+ *
+   This code uses the list of all kernel and module symbols to :-
+
+   * Find any non-stack symbol in a kernel or module.  Symbols do
+     not have to be exported for debugging.
+
+   * Convert an address to the module (or kernel) that owns it, the
+     section it is in and the nearest symbol.  This finds all non-stack
+     symbols, not just exported ones.
+
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+
+/* A symbol can appear in more than one module.  A token is used to
+ * restart the scan at the next module, set the token to 0 for the
+ * first scan of each symbol.
+ */
+
+int kallsyms_symbol_to_address(
+	const char	 *name,		/* Name to lookup */
+	unsigned long 	 *token,	/* Which module to start at */
+	const char	**mod_name,	/* Set to module name */
+	unsigned long 	 *mod_start,	/* Set to start address of module */
+	unsigned long 	 *mod_end,	/* Set to end address of module */
+	const char	**sec_name,	/* Set to section name */
+	unsigned long 	 *sec_start,	/* Set to start address of section */
+	unsigned long 	 *sec_end,	/* Set to end address of section */
+	const char	**sym_name,	/* Set to full symbol name */
+	unsigned long 	 *sym_start,	/* Set to start address of symbol */
+	unsigned long 	 *sym_end	/* Set to end address of symbol */
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec;
+	const struct kallsyms_symbol	*ka_sym = NULL;
+	const char			*ka_str = NULL;
+	const struct module *m;
+	int i = 0, l;
+	const char *p, *pt_R;
+	char *p2;
+
+	/* Restart? */
+	m = module_list;
+	if (token && *token) {
+		for (; m; m = m->next)
+			if ((unsigned long)m == *token)
+				break;
+		if (m)
+			m = m->next;
+	}
+
+	for (; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sym = (struct kallsyms_symbol *)
+			((char *)(ka_hdr) + ka_hdr->symbol_off);
+		ka_str = 
+			((char *)(ka_hdr) + ka_hdr->string_off);
+		for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+			p = ka_str + ka_sym->name_off;
+			if (strcmp(p, name) == 0)
+				break;
+			/* Unversioned requests match versioned names */
+			if (!(pt_R = strstr(p, "_R")))
+				continue;
+			l = strlen(pt_R);
+			if (l < 10)
+				continue;	/* Not _R.*xxxxxxxx */
+			(void)simple_strtoul(pt_R+l-8, &p2, 16);
+			if (*p2)
+				continue;	/* Not _R.*xxxxxxxx */
+			if (strncmp(p, name, pt_R-p) == 0)
+				break;	/* Match with version */
+		}
+		if (i < ka_hdr->symbols)
+			break;
+	}
+
+	if (token)
+		*token = (unsigned long)m;
+	if (!m)
+		return(0);	/* not found */
+
+	ka_sec = (const struct kallsyms_section *)
+		((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off);
+	*mod_name = *(m->name) ? m->name : "kernel";
+	*mod_start = ka_hdr->start;
+	*mod_end = ka_hdr->end;
+	*sec_name = ka_sec->name_off + ka_str;
+	*sec_start = ka_sec->start;
+	*sec_end = ka_sec->start + ka_sec->size;
+	*sym_name = ka_sym->name_off + ka_str;
+	*sym_start = ka_sym->symbol_addr;
+	if (i < ka_hdr->symbols-1) {
+		const struct kallsyms_symbol *ka_symn = ka_sym;
+		kallsyms_next_sym(ka_hdr, ka_symn);
+		*sym_end = ka_symn->symbol_addr;
+	}
+	else
+		*sym_end = *sec_end;
+	return(1);
+}
+
+int kallsyms_address_to_symbol(
+	unsigned long	  address,	/* Address to lookup */
+	const char	**mod_name,	/* Set to module name */
+	unsigned long 	 *mod_start,	/* Set to start address of module */
+	unsigned long 	 *mod_end,	/* Set to end address of module */
+	const char	**sec_name,	/* Set to section name */
+	unsigned long 	 *sec_start,	/* Set to start address of section */
+	unsigned long 	 *sec_end,	/* Set to end address of section */
+	const char	**sym_name,	/* Set to full symbol name */
+	unsigned long 	 *sym_start,	/* Set to start address of symbol */
+	unsigned long 	 *sym_end	/* Set to end address of symbol */
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec = NULL;
+	const struct kallsyms_symbol	*ka_sym;
+	const char			*ka_str;
+	const struct module *m;
+	int i;
+	unsigned long end;
+
+	for (m = module_list; m; m = m->next) {
+	  
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sec = (const struct kallsyms_section *)
+			((char *)ka_hdr + ka_hdr->section_off);
+		/* Is the address in any section in this module? */
+		for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) {
+			if (ka_sec->start <= address &&
+			    (ka_sec->start + ka_sec->size) > address)
+				break;
+		}
+		if (i < ka_hdr->sections)
+			break;	/* Found a matching section */
+	}
+
+	if (!m)
+		return(0);	/* not found */
+
+	ka_sym = (struct kallsyms_symbol *)
+		((char *)(ka_hdr) + ka_hdr->symbol_off);
+	ka_str = 
+		((char *)(ka_hdr) + ka_hdr->string_off);
+	*mod_name = m->name;
+	*mod_start = ka_hdr->start;
+	*mod_end = ka_hdr->end;
+	*sec_name = ka_sec->name_off + ka_str;
+	*sec_start = ka_sec->start;
+	*sec_end = ka_sec->start + ka_sec->size;
+	*sym_name = *sec_name;		/* In case we find no matching symbol */
+	*sym_start = *sec_start;
+	*sym_end = *sec_end;
+
+	for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+		if (ka_sym->symbol_addr > address)
+			continue;
+		if (i < ka_hdr->symbols-1) {
+			const struct kallsyms_symbol *ka_symn = ka_sym;
+			kallsyms_next_sym(ka_hdr, ka_symn);
+			end = ka_symn->symbol_addr;
+		}
+		else
+			end = *sec_end;
+		if (end <= address)
+			continue;
+		if ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off
+		    != (char *)ka_sec)
+			continue;	/* wrong section */
+		*sym_name = ka_str + ka_sym->name_off;
+		*sym_start = ka_sym->symbol_addr;
+		*sym_end = end;
+		break;
+	}
+	return(1);
+}
+
+/* List all sections in all modules.  The callback routine is invoked with
+ * token, module name, section name, section start, section end, section flags.
+ */
+int kallsyms_sections(void *token,
+		      int (*callback)(void *, const char *, const char *, ElfW(Addr), ElfW(Addr), ElfW(Word)))
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec = NULL;
+	const char			*ka_str;
+	const struct module *m;
+	int i;
+
+	for (m = module_list; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sec = (const struct kallsyms_section *) ((char *)ka_hdr + ka_hdr->section_off);
+		ka_str = ((char *)(ka_hdr) + ka_hdr->string_off);
+		for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) {
+			if (callback(
+				token,
+				*(m->name) ? m->name : "kernel",
+				ka_sec->name_off + ka_str,
+				ka_sec->start,
+				ka_sec->start + ka_sec->size,
+				ka_sec->flags))
+				return(0);
+		}
+	}
+	return(1);
+}
diff -rNu linux.orig/kernel/module.c linux/kernel/module.c
--- linux.orig/kernel/module.c	Fri Sep 20 17:20:19 2002
+++ linux/kernel/module.c	Wed Sep 25 11:26:11 2002
@@ -3,6 +3,7 @@
 #include <linux/module.h>
 #include <asm/module.h>
 #include <asm/uaccess.h>
+#include <linux/kallsyms.h>
 #include <linux/vmalloc.h>
 #include <linux/smp_lock.h>
 #include <asm/pgalloc.h>
@@ -39,13 +40,19 @@
 extern const struct exception_table_entry __start___ex_table[];
 extern const struct exception_table_entry __stop___ex_table[];
 
-extern const char __start___kallsyms[] __attribute__ ((weak));
-extern const char __stop___kallsyms[] __attribute__ ((weak));
+extern const char __start___kallsyms[] __attribute__((weak));
+extern const char __stop___kallsyms[] __attribute__((weak));
+
+/* modutils uses these exported symbols to figure out if
+   kallsyms support is present */
+
+EXPORT_SYMBOL(__start___kallsyms);
+EXPORT_SYMBOL(__stop___kallsyms);
 
 struct module kernel_module =
 {
 	.size_of_struct		= sizeof(struct module),
-	.name 			= "",
+	.name 			= "kernel",
 	.uc	 		= {ATOMIC_INIT(1)},
 	.flags			= MOD_RUNNING,
 	.syms			= __start___ksymtab,
@@ -1220,6 +1227,30 @@
 	.show	= s_show
 };
 
+#define MODLIST_SIZE 4096
+
+/*
+ * this function isn't smp safe but that's not really a problem; it's
+ * called from oops context only and any locking could actually prevent
+ * the oops from going out; the line that is generated is informational
+ * only and should NEVER prevent the real oops from going out. 
+ */
+void print_modules(void)
+{
+	static char modlist[MODLIST_SIZE];
+	struct module *this_mod;
+	int pos = 0;
+
+	this_mod = module_list;
+	while (this_mod) {
+		if (this_mod->name)
+			pos += snprintf(modlist+pos, MODLIST_SIZE-pos-1, 
+					"%s ", this_mod->name);
+		this_mod = this_mod->next;
+	}
+	printk("%s\n",modlist);
+}
+
 #else		/* CONFIG_MODULES */
 
 /* Dummy syscalls for people who don't want modules */
@@ -1265,4 +1296,60 @@
 	return 1;
 }
 
+void print_modules(void)
+{
+}
+
 #endif	/* CONFIG_MODULES */
+
+
+#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
+
+#define MAX_SYMBOL_SIZE 512
+
+int print_symbol(const char *fmt, unsigned long address)
+{
+	struct module *this_mod;
+	unsigned long bestsofar;
+	/* static to not take up stackspace; if we race here too bad */
+	static char buffer[MAX_SYMBOL_SIZE];
+
+	const char *mod_name = NULL, *sec_name = NULL, *sym_name = NULL;
+	unsigned long mod_start, mod_end, sec_start, sec_end,
+							sym_start, sym_end;
+	
+	memset(buffer, 0, MAX_SYMBOL_SIZE);
+
+	if (!kallsyms_address_to_symbol(address,&mod_name,&mod_start,&mod_end,&sec_name, &sec_start, &sec_end, &sym_name, &sym_start, &sym_end)) {
+		/* kallsyms doesn't have a clue; lets try our list 
+		 * of exported symbols */
+		bestsofar = 0;
+		sprintf(buffer, "[unresolved]");
+		
+		for (this_mod = module_list; this_mod; this_mod = this_mod->next) {
+			int i;
+			/* walk the symbol list of this module. Only symbols
+			   who's address is smaller than the searched for address
+			   are relevant; and only if it's better than the best so far */
+			for (i = 0; i < this_mod->nsyms; i++)
+				if ((this_mod->syms[i].value <= address) &&
+				    (bestsofar < this_mod->syms[i].value)) {
+					snprintf(buffer, MAX_SYMBOL_SIZE - 1,
+						 "%s [%s] 0x%x",
+						this_mod->syms[i].name,
+						this_mod->name,
+						(unsigned int)(address - this_mod->syms[i].value));
+					bestsofar = this_mod->syms[i].value;
+				}
+		}
+
+	} else { /* kallsyms success */
+		snprintf(buffer,MAX_SYMBOL_SIZE - 1, "%s [%s] 0x%x",
+			 sym_name, mod_name,
+			 (unsigned int)(address - sym_start));
+	}
+	printk(fmt, buffer);
+	return 0;
+}
+
+#endif


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [re-ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25  9:32 ` [re-ANNOUNCE] " Ingo Molnar
@ 2002-09-25  9:51   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 23+ messages in thread
From: Arnaldo Carvalho de Melo @ 2002-09-25  9:51 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Linus Torvalds, Kai Germaschewski, Rusty Russell,
	Arjan van de Ven

Em Wed, Sep 25, 2002 at 11:32:24AM +0200, Ingo Molnar escreveu:
> 
> okay, this time the correct patch against BK-curr is included:

<SNIP>

> diff -rNu linux.orig/arch/i386/kernel/process.c.rej linux/arch/i386/kernel/process.c.rej
> --- linux.orig/arch/i386/kernel/process.c.rej	Thu Jan  1 01:00:00 1970
> +++ linux/arch/i386/kernel/process.c.rej	Wed Sep 25 11:25:33 2002
                                      ^^^^
                                      ^^^^
                                      ^^^^

Oops :-)

> @@ -0,0 +1,29 @@
> +***************
> +*** 159,172 ****
> +  void show_regs(struct pt_regs * regs)
> +  {
> +  	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25  9:02 [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0 Ingo Molnar
  2002-09-25  9:32 ` [re-ANNOUNCE] " Ingo Molnar
@ 2002-09-25 18:16 ` Linus Torvalds
  2002-09-25 19:23   ` Kai Germaschewski
  1 sibling, 1 reply; 23+ messages in thread
From: Linus Torvalds @ 2002-09-25 18:16 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Kai Germaschewski, Rusty Russell, Arjan van de Ven


On Wed, 25 Sep 2002, Ingo Molnar wrote:
>
> EIP is at sys_gettimeofday [kernel] 0x84
> Call Trace: [<c0112a40>] do_page_fault [kernel] 0x0
> [<c0107973>] syscall_call [kernel] 0x7

At a minimum, fix this to:

 - not print out that stupid "kernel" thing. Of _course_ it is the kernel. 
   Modules can put their module name to clarify, but the core kernel 
   certainly doesn't "clarify" anything by putting "kernel" there.

 - print out offset/length like the user-space ksymoops does. Without the 
   offset the thing is useless, since you still need the real address to 
   actually look up which instruction faulted.

		Linus


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:53       ` Ingo Molnar
@ 2002-09-25 19:04         ` Cort Dougan
  2002-09-25 20:14           ` Ingo Molnar
  0 siblings, 1 reply; 23+ messages in thread
From: Cort Dougan @ 2002-09-25 19:04 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Linus Torvalds, Kai Germaschewski, linux-kernel, Rusty Russell,
	Arjan van de Ven

How does this change differ from the one I sent a month ago?

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 18:16 ` [ANNOUNCE] " Linus Torvalds
@ 2002-09-25 19:23   ` Kai Germaschewski
  2002-09-25 19:42     ` Ingo Molnar
  2002-09-25 19:45     ` Linus Torvalds
  0 siblings, 2 replies; 23+ messages in thread
From: Kai Germaschewski @ 2002-09-25 19:23 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Ingo Molnar, linux-kernel, Rusty Russell, Arjan van de Ven

On Wed, 25 Sep 2002, Linus Torvalds wrote:

> On Wed, 25 Sep 2002, Ingo Molnar wrote:
> >
> > EIP is at sys_gettimeofday [kernel] 0x84
> > Call Trace: [<c0112a40>] do_page_fault [kernel] 0x0
> > [<c0107973>] syscall_call [kernel] 0x7
> 
> At a minimum, fix this to:
> 
>  - not print out that stupid "kernel" thing. Of _course_ it is the kernel. 
>    Modules can put their module name to clarify, but the core kernel 
>    certainly doesn't "clarify" anything by putting "kernel" there.
> 
>  - print out offset/length like the user-space ksymoops does. Without the 
>    offset the thing is useless, since you still need the real address to 
>    actually look up which instruction faulted.

Alright, I did these modifications (however, even the current version 
prints the offset, just not the length, which does not have too much 
meaning anyway)

So this patch converts the output to the more familiar

	sys_gettimeofday+0x84/0x108 [module-name]

format, where module-name is "" for the kernel. 

Ingo, could you test the modifications again, please? Also, I worked 
against my latest version, if you did additional changes after the last 
version I sent you, they need to be merged back in.

--Kai


Pull from http://linux-isdn.bkbits.net/linux-2.5.kallsyms

(Merging changesets omitted for clarity)

-----------------------------------------------------------------------------
ChangeSet@1.609, 2002-09-25 14:11:06-05:00, kai@tp1.ruhr-uni-bochum.de
  kksymoops: cosmetics
  
  Don't print "kernel" when a symbol is in the kernel.
  
  Change the output format to
  sys_gettimeofday+0x84/0x108 [module].

 ----------------------------------------------------------------------------
 module.c |   75 ++++++++++++++++++++++++++++++++++++---------------------------
 1 files changed, 44 insertions(+), 31 deletions(-)





=============================================================================
unified diffs follow for reference
=============================================================================


-----------------------------------------------------------------------------
ChangeSet@1.609, 2002-09-25 14:11:06-05:00, kai@tp1.ruhr-uni-bochum.de
  kksymoops: cosmetics
  
  Don't print "kernel" when a symbol is in the kernel.
  
  Change the output format to
  sys_gettimeofday+0x84/0x108 [module].

  ---------------------------------------------------------------------------

diff -Nru a/kernel/module.c b/kernel/module.c
--- a/kernel/module.c	Wed Sep 25 14:18:41 2002
+++ b/kernel/module.c	Wed Sep 25 14:18:41 2002
@@ -52,7 +52,7 @@
 struct module kernel_module =
 {
 	.size_of_struct		= sizeof(struct module),
-	.name 			= "kernel",
+	.name 			= "",
 	.uc	 		= {ATOMIC_INIT(1)},
 	.flags			= MOD_RUNNING,
 	.syms			= __start___ksymtab,
@@ -1307,48 +1307,61 @@
 
 #define MAX_SYMBOL_SIZE 512
 
-int print_symbol(const char *fmt, unsigned long address)
+static void
+address_to_exported_symbol(unsigned long address, const char **mod_name, 
+			   const char **sym_name, unsigned long *sym_start,
+			   unsigned long *sym_end)
 {
 	struct module *this_mod;
-	unsigned long bestsofar;
+	int i;
+
+	for (this_mod = module_list; this_mod; this_mod = this_mod->next) {
+		/* walk the symbol list of this module. Only symbols
+		   who's address is smaller than the searched for address
+		   are relevant; and only if it's better than the best so far */
+		for (i = 0; i < this_mod->nsyms; i++)
+			if ((this_mod->syms[i].value <= address) &&
+			    (*sym_start < this_mod->syms[i].value)) {
+				*sym_start = this_mod->syms[i].value;
+				*sym_name  = this_mod->syms[i].name;
+				*mod_name  = this_mod->name;
+				if (i + 1 < this_mod->nsyms)
+					*sym_end = this_mod->syms[i+1].value;
+				else
+					*sym_end = (unsigned long) this_mod + this_mod->size;
+			}
+	}
+}
+
+int
+print_symbol(const char *fmt, unsigned long address)
+{
 	/* static to not take up stackspace; if we race here too bad */
 	static char buffer[MAX_SYMBOL_SIZE];
 
 	const char *mod_name = NULL, *sec_name = NULL, *sym_name = NULL;
 	unsigned long mod_start, mod_end, sec_start, sec_end,
-							sym_start, sym_end;
+		sym_start, sym_end;
+	char *tag = "";
 	
 	memset(buffer, 0, MAX_SYMBOL_SIZE);
 
-	if (!kallsyms_address_to_symbol(address,&mod_name,&mod_start,&mod_end,&sec_name, &sec_start, &sec_end, &sym_name, &sym_start, &sym_end)) {
-		/* kallsyms doesn't have a clue; lets try our list 
-		 * of exported symbols */
-		bestsofar = 0;
-		sprintf(buffer, "[unresolved]");
-		
-		for (this_mod = module_list; this_mod; this_mod = this_mod->next) {
-			int i;
-			/* walk the symbol list of this module. Only symbols
-			   who's address is smaller than the searched for address
-			   are relevant; and only if it's better than the best so far */
-			for (i = 0; i < this_mod->nsyms; i++)
-				if ((this_mod->syms[i].value <= address) &&
-				    (bestsofar < this_mod->syms[i].value)) {
-					snprintf(buffer, MAX_SYMBOL_SIZE - 1,
-						 "%s [%s] 0x%x",
-						this_mod->syms[i].name,
-						this_mod->name,
-						(unsigned int)(address - this_mod->syms[i].value));
-					bestsofar = this_mod->syms[i].value;
-				}
-		}
+	sym_start = 0;
+	if (!kallsyms_address_to_symbol(address, &mod_name, &mod_start, &mod_end, &sec_name, &sec_start, &sec_end, &sym_name, &sym_start, &sym_end)) {
+		tag = "E ";
+		address_to_exported_symbol(address, &mod_name, &sym_name, &sym_start, &sym_end);
+	}
 
-	} else { /* kallsyms success */
-		snprintf(buffer,MAX_SYMBOL_SIZE - 1, "%s [%s] 0x%x",
-			 sym_name, mod_name,
-			 (unsigned int)(address - sym_start));
+	if (sym_start) {
+		snprintf(buffer, MAX_SYMBOL_SIZE - 1, "%s%s+%#x/%#x [%s]",
+			 tag, sym_name,
+			 (unsigned int)(address - sym_start),
+			 (unsigned int)(sym_end - sym_start),
+			 mod_name);
+		printk(fmt, buffer);
+	} else {
+		printk(fmt, "[unresolved]");
 	}
-	printk(fmt, buffer);
 	return 0;
 }
 





^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:42     ` Ingo Molnar
@ 2002-09-25 19:41       ` Kai Germaschewski
  2002-09-25 19:46       ` Linus Torvalds
  1 sibling, 0 replies; 23+ messages in thread
From: Kai Germaschewski @ 2002-09-25 19:41 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: Linus Torvalds, linux-kernel, Rusty Russell, Arjan van de Ven

On Wed, 25 Sep 2002, Ingo Molnar wrote:

> one unrelated build thing that doesnt work is arch/i386/defconfig. If i
> add a CONFIG_KALLSYMS=y line to its debug section, and remove the
> CONFIG_KALLSYMS line from the .config, and then do a 'make oldconfig', i
> get this:
> 
> Kernel debugging (CONFIG_DEBUG_KERNEL) [Y/n/?]
>   Debug memory allocations (CONFIG_DEBUG_SLAB) [N/y/?]
>   Memory mapped I/O debugging (CONFIG_DEBUG_IOVIRT) [N/y/?]
>   Magic SysRq key (CONFIG_MAGIC_SYSRQ) [Y/n/?]
>   Spinlock debugging (CONFIG_DEBUG_SPINLOCK) [N/y/?]
>   Load all symbols for debugging/kksymoops (CONFIG_KALLSYMS) [N/y/?] (NEW)
> 
> i'd expect the 'Y' to be picked up from the defconfig - no?

No. I don't think the behavior you describe ever existed. If you do 
"rm .config; make oldconfig" then it'll get picked up.

--Kai



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:23   ` Kai Germaschewski
@ 2002-09-25 19:42     ` Ingo Molnar
  2002-09-25 19:41       ` Kai Germaschewski
  2002-09-25 19:46       ` Linus Torvalds
  2002-09-25 19:45     ` Linus Torvalds
  1 sibling, 2 replies; 23+ messages in thread
From: Ingo Molnar @ 2002-09-25 19:42 UTC (permalink / raw)
  To: Kai Germaschewski
  Cc: Linus Torvalds, linux-kernel, Rusty Russell, Arjan van de Ven


one unrelated build thing that doesnt work is arch/i386/defconfig. If i
add a CONFIG_KALLSYMS=y line to its debug section, and remove the
CONFIG_KALLSYMS line from the .config, and then do a 'make oldconfig', i
get this:

Kernel debugging (CONFIG_DEBUG_KERNEL) [Y/n/?]
  Debug memory allocations (CONFIG_DEBUG_SLAB) [N/y/?]
  Memory mapped I/O debugging (CONFIG_DEBUG_IOVIRT) [N/y/?]
  Magic SysRq key (CONFIG_MAGIC_SYSRQ) [Y/n/?]
  Spinlock debugging (CONFIG_DEBUG_SPINLOCK) [N/y/?]
  Load all symbols for debugging/kksymoops (CONFIG_KALLSYMS) [N/y/?] (NEW)

i'd expect the 'Y' to be picked up from the defconfig - no?

	Ingo


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:23   ` Kai Germaschewski
  2002-09-25 19:42     ` Ingo Molnar
@ 2002-09-25 19:45     ` Linus Torvalds
  2002-09-25 19:53       ` Ingo Molnar
  2002-09-25 19:56       ` Ingo Molnar
  1 sibling, 2 replies; 23+ messages in thread
From: Linus Torvalds @ 2002-09-25 19:45 UTC (permalink / raw)
  To: Kai Germaschewski
  Cc: Ingo Molnar, linux-kernel, Rusty Russell, Arjan van de Ven


On Wed, 25 Sep 2002, Kai Germaschewski wrote:
> 
> So this patch converts the output to the more familiar
> 
> 	sys_gettimeofday+0x84/0x108 [module-name]
> 
> format, where module-name is "" for the kernel. 

I want those [] gone too, I see no reason for them except to make the 
output ugly.

		Linus


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:42     ` Ingo Molnar
  2002-09-25 19:41       ` Kai Germaschewski
@ 2002-09-25 19:46       ` Linus Torvalds
  2002-09-25 19:54         ` Ingo Molnar
  1 sibling, 1 reply; 23+ messages in thread
From: Linus Torvalds @ 2002-09-25 19:46 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Kai Germaschewski, linux-kernel, Rusty Russell, Arjan van de Ven


On Wed, 25 Sep 2002, Ingo Molnar wrote:
> 
> i'd expect the 'Y' to be picked up from the defconfig - no?

No. defconfig is either used 100% or not at all.

		Linus


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:54         ` Ingo Molnar
@ 2002-09-25 19:52           ` Linus Torvalds
  2002-09-25 20:04             ` Ingo Molnar
  2002-09-25 20:31             ` Jeff Garzik
  2002-09-25 19:55           ` Kai Germaschewski
  1 sibling, 2 replies; 23+ messages in thread
From: Linus Torvalds @ 2002-09-25 19:52 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Kai Germaschewski, linux-kernel, Rusty Russell, Arjan van de Ven


On Wed, 25 Sep 2002, Ingo Molnar wrote:
> 
> hm, then what is the standard way to make a new kernel option default-Y?  

There is none.

In fact, there _cannot_ be any these days, since all recent kernrels have 
stopped using defconfig entirely, and favour using /etc/kernel-config 
instead (making it much easier to have per-machine default 
configurations).

> At least for the development kernel, a default-enabled kksymoops sounds
> like the right way to go.

We can ask people to enable it if they can't get their oops reports 
together (and whether they get their oops reports in shape by using the 
user-space ksymoops or the kernel version really doesn't matter).

		Linus


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:45     ` Linus Torvalds
@ 2002-09-25 19:53       ` Ingo Molnar
  2002-09-25 19:04         ` Cort Dougan
  2002-09-25 19:56       ` Ingo Molnar
  1 sibling, 1 reply; 23+ messages in thread
From: Ingo Molnar @ 2002-09-25 19:53 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Kai Germaschewski, linux-kernel, Rusty Russell, Arjan van de Ven


On Wed, 25 Sep 2002, Linus Torvalds wrote:

> I want those [] gone too, I see no reason for them except to make the
> output ugly.

yep, i removed them already, patch in a minute, after i'm done with
testing.

	Ingo


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:46       ` Linus Torvalds
@ 2002-09-25 19:54         ` Ingo Molnar
  2002-09-25 19:52           ` Linus Torvalds
  2002-09-25 19:55           ` Kai Germaschewski
  0 siblings, 2 replies; 23+ messages in thread
From: Ingo Molnar @ 2002-09-25 19:54 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Kai Germaschewski, linux-kernel, Rusty Russell, Arjan van de Ven


On Wed, 25 Sep 2002, Linus Torvalds wrote:

> > i'd expect the 'Y' to be picked up from the defconfig - no?
> 
> No. defconfig is either used 100% or not at all.

hm, then what is the standard way to make a new kernel option default-Y?  
At least for the development kernel, a default-enabled kksymoops sounds
like the right way to go.

	Ingo


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:54         ` Ingo Molnar
  2002-09-25 19:52           ` Linus Torvalds
@ 2002-09-25 19:55           ` Kai Germaschewski
  1 sibling, 0 replies; 23+ messages in thread
From: Kai Germaschewski @ 2002-09-25 19:55 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: Linus Torvalds, linux-kernel, Rusty Russell, Arjan van de Ven

On Wed, 25 Sep 2002, Ingo Molnar wrote:

> hm, then what is the standard way to make a new kernel option default-Y?  
> At least for the development kernel, a default-enabled kksymoops sounds
> like the right way to go.

There isn't really any. You can do 

	define_bool CONFIG_KALLSYMS y

for two releases and hope to propagate it into people's .config before 
making it an actual choice in config.in.

Or you can hack something up like

if [ "$CONFIG_KALLSYMS" = "" ]; then
	define_bool CONFIG_KALLSYMS y
fi
bool 'kallsyms' CONFIG_KALLSYMS

which gives the desired effect in make oldconfig, but may magically break 
make xconfig or so.

So no, just hope for people to read the help text and enable it.

--Kai



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:45     ` Linus Torvalds
  2002-09-25 19:53       ` Ingo Molnar
@ 2002-09-25 19:56       ` Ingo Molnar
  2002-09-25 22:04         ` J.A. Magallon
  2002-09-26 17:16         ` Ruth Ivimey-Cook
  1 sibling, 2 replies; 23+ messages in thread
From: Ingo Molnar @ 2002-09-25 19:56 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Kai Germaschewski, linux-kernel, Rusty Russell, Arjan van de Ven


okay, here is the new oops output:

------------[ cut here ]------------
kernel BUG at time.c:99!
invalid operand: 0000
CPU:    1
EIP:    0060:[<c011bd14>]    Not tainted
EFLAGS: 00010246
EIP is at sys_gettimeofday+0x84/0x90
eax: 0000004e   ebx: cef9e000   ecx: 00000000   edx: 00000068
esi: 00000000   edi: 00000000   ebp: bffffad8   esp: cef9ffa0
ds: 0068   es: 0068   ss: 0068
Process gettimeofday (pid: 549, threadinfo=cef9e000 task=cf84d860)
Stack: 4001695c bffff414 40156154 00000004 c0112a40 cef9e000 400168e4 bffffb44
       c0107973 00000000 00000000 40156154 400168e4 bffffb44 bffffad8 0000004e
       0000002b 0000002b 0000004e 400cecc1 00000023 00000246 bffffacc 0000002b
Call Trace: [<c0112a40>] do_page_fault+0x0/0x4a2
[<c0107973>] syscall_call+0x7/0xb

and the patch, against BK-curr:

--- linux/arch/i386/kernel/head.S.orig	Fri Sep 20 17:20:16 2002
+++ linux/arch/i386/kernel/head.S	Wed Sep 25 21:46:56 2002
@@ -121,7 +121,7 @@
  */
 	xorl %eax,%eax
 	movl $__bss_start,%edi
-	movl $_end,%ecx
+	movl $__bss_stop,%ecx
 	subl %edi,%ecx
 	rep
 	stosb
--- linux/arch/i386/kernel/process.c.orig	Fri Sep 20 17:20:12 2002
+++ linux/arch/i386/kernel/process.c	Wed Sep 25 21:46:56 2002
@@ -33,6 +33,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/mc146818rtc.h>
+#include <linux/module.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -155,8 +156,6 @@
 
 __setup("idle=", idle_setup);
 
-extern void show_trace(unsigned long* esp);
-
 void show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
@@ -164,6 +163,8 @@
 	printk("\n");
 	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
 	printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
+	print_symbol("EIP is at %s\n", regs->eip);
+
 	if (regs->xcs & 3)
 		printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
 	printk(" EFLAGS: %08lx    %s\n",regs->eflags, print_tainted());
--- linux/arch/i386/kernel/traps.c.orig	Fri Sep 20 17:20:19 2002
+++ linux/arch/i386/kernel/traps.c	Wed Sep 25 21:46:56 2002
@@ -94,7 +94,6 @@
 
 #ifdef CONFIG_MODULES
 
-extern struct module *module_list;
 extern struct module kernel_module;
 
 static inline int kernel_text_address(unsigned long addr)
@@ -142,10 +141,12 @@
 	while (((long) stack & (THREAD_SIZE-1)) != 0) {
 		addr = *stack++;
 		if (kernel_text_address(addr)) {
-			if (i && ((i % 6) == 0))
-				printk("\n   ");
 			printk("[<%08lx>] ", addr);
-			i++;
+			if (print_symbol("%s\n", addr)) {
+				/* save screen space */
+				if ((i++ % 6) == 0)
+					printk("\n   ");
+			}
 		}
 	}
 	printk("\n");
@@ -206,8 +207,11 @@
 		esp = regs->esp;
 		ss = regs->xss & 0xffff;
 	}
+	print_modules();
 	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx\n",
 		smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
+
+	print_symbol("EIP is at %s\n", regs->eip);
 	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
 		regs->eax, regs->ebx, regs->ecx, regs->edx);
 	printk("esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
@@ -268,6 +272,7 @@
 		(unsigned long)file < PAGE_OFFSET || __get_user(c, file))
 		file = "<bad filename>";
 
+	printk("------------[ cut here ]------------\n");
 	printk("kernel BUG at %s:%d!\n", file, line);
 
 no_bug:
--- linux/arch/i386/Config.help.orig	Fri Sep 20 17:20:16 2002
+++ linux/arch/i386/Config.help	Wed Sep 25 21:46:56 2002
@@ -946,6 +946,11 @@
   of the BUG call as well as the EIP and oops trace.  This aids
   debugging but costs about 70-100K of memory.
 
+CONFIG_KALLSYMS
+  Say Y here to let the kernel print out symbolic crash information and
+  symbolic stack backtraces. This increases the size of the kernel
+  somewhat, as all symbols have to be loaded into the kernel image.
+
 CONFIG_DEBUG_OBSOLETE
   Say Y here if you want to reduce the chances of the tree compiling,
   and are prepared to dig into driver internals to fix compile errors.
--- linux/arch/i386/config.in.orig	Wed Sep 25 21:43:13 2002
+++ linux/arch/i386/config.in	Wed Sep 25 21:46:56 2002
@@ -435,6 +435,7 @@
    if [ "$CONFIG_HIGHMEM" = "y" ]; then
       bool '  Highmem debugging' CONFIG_DEBUG_HIGHMEM
    fi
+   bool '  Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS
 fi
 
 if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then
--- linux/arch/i386/vmlinux.lds.S.orig	Fri Sep 20 17:20:19 2002
+++ linux/arch/i386/vmlinux.lds.S	Wed Sep 25 21:46:56 2002
@@ -78,9 +78,13 @@
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
   __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
+  .bss : { *(.bss) }
+  __bss_stop = .; 
+
+  __start___kallsyms = .;     /* All kernel symbols */
+  __kallsyms : { *(__kallsyms) }
+  __stop___kallsyms = .;
+
   _end = . ;
 
   /* Sections to be discarded */
--- linux/include/linux/kallsyms.h.orig	Wed Sep 25 21:46:56 2002
+++ linux/include/linux/kallsyms.h	Wed Sep 25 21:46:56 2002
@@ -0,0 +1,163 @@
+/* kallsyms headers
+   Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+   This file is part of the Linux modutils.  It is exported to kernel
+   space so debuggers can access the kallsyms data.
+
+   The kallsyms data contains all the non-stack symbols from a kernel
+   or a module.  The kernel symbols are held between __start___kallsyms
+   and __stop___kallsyms.  The symbols for a module are accessed via
+   the struct module chain which is based at module_list.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ident "$Id: linux-2.4.9-kallsyms.patch,v 1.8 2002/02/11 18:34:53 arjanv Exp $"
+
+#ifndef MODUTILS_KALLSYMS_H
+#define MODUTILS_KALLSYMS_H 1
+
+/* Have to (re)define these ElfW entries here because external kallsyms
+ * code does not have access to modutils/include/obj.h.  This code is
+ * included from user spaces tools (modutils) and kernel, they need
+ * different includes.
+ */
+
+#ifndef ELFCLASS32
+#ifdef __KERNEL__
+#include <linux/elf.h>
+#else	/* __KERNEL__ */
+#include <elf.h>
+#endif	/* __KERNEL__ */
+#endif	/* ELFCLASS32 */
+
+#ifndef ELFCLASSM
+#define ELFCLASSM ELF_CLASS
+#endif
+
+#ifndef ElfW
+# if ELFCLASSM == ELFCLASS32
+#  define ElfW(x)  Elf32_ ## x
+#  define ELFW(x)  ELF32_ ## x
+# else
+#  define ElfW(x)  Elf64_ ## x
+#  define ELFW(x)  ELF64_ ## x
+# endif
+#endif
+
+/* Format of data in the kallsyms section.
+ * Most of the fields are small numbers but the total size and all
+ * offsets can be large so use the 32/64 bit types for these fields.
+ *
+ * Do not use sizeof() on these structures, modutils may be using extra
+ * fields.  Instead use the size fields in the header to access the
+ * other bits of data.
+ */  
+
+struct kallsyms_header {
+	int		size;		/* Size of this header */
+	ElfW(Word)	total_size;	/* Total size of kallsyms data */
+	int		sections;	/* Number of section entries */
+	ElfW(Off)	section_off;	/* Offset to first section entry */
+	int		section_size;	/* Size of one section entry */
+	int		symbols;	/* Number of symbol entries */
+	ElfW(Off)	symbol_off;	/* Offset to first symbol entry */
+	int		symbol_size;	/* Size of one symbol entry */
+	ElfW(Off)	string_off;	/* Offset to first string */
+	ElfW(Addr)	start;		/* Start address of first section */
+	ElfW(Addr)	end;		/* End address of last section */
+};
+
+struct kallsyms_section {
+	ElfW(Addr)	start;		/* Start address of section */
+	ElfW(Word)	size;		/* Size of this section */
+	ElfW(Off)	name_off;	/* Offset to section name */
+	ElfW(Word)	flags;		/* Flags from section */
+};
+
+struct kallsyms_symbol {
+	ElfW(Off)	section_off;	/* Offset to section that owns this symbol */
+	ElfW(Addr)	symbol_addr;	/* Address of symbol */
+	ElfW(Off)	name_off;	/* Offset to symbol name */
+};
+
+#define KALLSYMS_SEC_NAME "__kallsyms"
+#define KALLSYMS_IDX 2			/* obj_kallsyms creates kallsyms as section 2 */
+
+#define kallsyms_next_sec(h,s) \
+	((s) = (struct kallsyms_section *)((char *)(s) + (h)->section_size))
+#define kallsyms_next_sym(h,s) \
+	((s) = (struct kallsyms_symbol *)((char *)(s) + (h)->symbol_size))
+
+#ifdef CONFIG_KALLSYMS
+
+int kallsyms_symbol_to_address(
+	const char       *name,			/* Name to lookup */
+	unsigned long    *token,		/* Which module to start with */
+	const char      **mod_name,		/* Set to module name or "kernel" */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	);
+
+int kallsyms_address_to_symbol(
+	unsigned long     address,		/* Address to lookup */
+	const char      **mod_name,		/* Set to module name */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	);
+
+int kallsyms_sections(void *token,
+		      int (*callback)(void *,	/* token */
+		      	const char *,		/* module name */
+			const char *,		/* section name */
+			ElfW(Addr),		/* Section start */
+			ElfW(Addr),		/* Section end */
+			ElfW(Word)		/* Section flags */
+		      )
+		);
+
+#else
+
+static inline int kallsyms_address_to_symbol(
+	unsigned long     address,		/* Address to lookup */
+	const char      **mod_name,		/* Set to module name */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	)
+{
+	return -ESRCH;
+}
+
+#endif
+
+#endif /* kallsyms.h */
--- linux/include/linux/module.h.orig	Fri Sep 20 17:20:32 2002
+++ linux/include/linux/module.h	Wed Sep 25 21:46:56 2002
@@ -316,8 +316,6 @@
 #define MOD_DEC_USE_COUNT	do { } while (0)
 #define MOD_IN_USE		1
 
-extern struct module *module_list;
-
 #endif /* !__GENKSYMS__ */
 
 #endif /* MODULE */
@@ -504,6 +502,30 @@
 #define SET_MODULE_OWNER(some_struct) do { (some_struct)->owner = THIS_MODULE; } while (0)
 #else
 #define SET_MODULE_OWNER(some_struct) do { } while (0)
+#endif
+
+extern void print_modules(void);
+
+#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
+
+extern struct module *module_list;
+
+/*
+ * print_symbols takes a format string containing one %s.
+ * If support for resolving symbols is compiled in, the %s will
+ * be replaced by the closest symbol to the address and the entire
+ * string is printk()ed. Otherwise, nothing is printed.
+ */
+extern int print_symbol(const char *fmt, unsigned long address);
+
+#else
+
+static inline int
+print_symbol(const char *fmt, unsigned long address)
+{
+	return -ESRCH;
+}
+
 #endif
 
 #endif /* _LINUX_MODULE_H */
--- linux/include/linux/sched.h.orig	Wed Sep 25 21:43:13 2002
+++ linux/include/linux/sched.h	Wed Sep 25 21:46:56 2002
@@ -151,7 +151,13 @@
 
 extern void sched_init(void);
 extern void init_idle(task_t *idle, int cpu);
+
 extern void show_state(void);
+extern void show_trace(unsigned long *stack);
+extern void show_stack(unsigned long *stack);
+extern void show_regs(struct pt_regs *);
+
+
 extern void cpu_init (void);
 extern void trap_init(void);
 extern void update_process_times(int user);
--- linux/include/asm-i386/hardirq.h.orig	Fri Sep 20 17:20:32 2002
+++ linux/include/asm-i386/hardirq.h	Wed Sep 25 21:46:56 2002
@@ -97,6 +97,4 @@
   extern void synchronize_irq(unsigned int irq);
 #endif /* CONFIG_SMP */
 
-extern void show_stack(unsigned long * esp);
-
 #endif /* __ASM_HARDIRQ_H */
--- linux/include/asm-i386/ptrace.h.orig	Fri Sep 20 17:20:16 2002
+++ linux/include/asm-i386/ptrace.h	Wed Sep 25 21:46:56 2002
@@ -57,7 +57,6 @@
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
 #define instruction_pointer(regs) ((regs)->eip)
-extern void show_regs(struct pt_regs *);
 #endif
 
 #endif
--- linux/kernel/Makefile.orig	Fri Sep 20 17:20:19 2002
+++ linux/kernel/Makefile	Wed Sep 25 21:46:56 2002
@@ -3,7 +3,7 @@
 #
 
 export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
-		printk.o platform.o suspend.o dma.o
+	      printk.o platform.o suspend.o dma.o module.o
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o time.o softirq.o resource.o \
@@ -14,6 +14,7 @@
 obj-$(CONFIG_SMP) += cpu.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
+obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += pm.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
--- linux/kernel/kallsyms.c.orig	Wed Sep 25 21:46:56 2002
+++ linux/kernel/kallsyms.c	Wed Sep 25 21:51:18 2002
@@ -0,0 +1,227 @@
+/*
+ * kksymoops.c: in-kernel printing of symbolic oopses and stack traces.
+ *
+ *  Copyright 2000 Keith Owens <kaos@ocs.com.au> April 2000
+ *  Copyright 2002 Arjan van de Ven <arjanv@redhat.com>
+ *
+   This code uses the list of all kernel and module symbols to :-
+
+   * Find any non-stack symbol in a kernel or module.  Symbols do
+     not have to be exported for debugging.
+
+   * Convert an address to the module (or kernel) that owns it, the
+     section it is in and the nearest symbol.  This finds all non-stack
+     symbols, not just exported ones.
+
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+
+/* A symbol can appear in more than one module.  A token is used to
+ * restart the scan at the next module, set the token to 0 for the
+ * first scan of each symbol.
+ */
+
+int kallsyms_symbol_to_address(
+	const char	 *name,		/* Name to lookup */
+	unsigned long 	 *token,	/* Which module to start at */
+	const char	**mod_name,	/* Set to module name */
+	unsigned long 	 *mod_start,	/* Set to start address of module */
+	unsigned long 	 *mod_end,	/* Set to end address of module */
+	const char	**sec_name,	/* Set to section name */
+	unsigned long 	 *sec_start,	/* Set to start address of section */
+	unsigned long 	 *sec_end,	/* Set to end address of section */
+	const char	**sym_name,	/* Set to full symbol name */
+	unsigned long 	 *sym_start,	/* Set to start address of symbol */
+	unsigned long 	 *sym_end	/* Set to end address of symbol */
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec;
+	const struct kallsyms_symbol	*ka_sym = NULL;
+	const char			*ka_str = NULL;
+	const struct module *m;
+	int i = 0, l;
+	const char *p, *pt_R;
+	char *p2;
+
+	/* Restart? */
+	m = module_list;
+	if (token && *token) {
+		for (; m; m = m->next)
+			if ((unsigned long)m == *token)
+				break;
+		if (m)
+			m = m->next;
+	}
+
+	for (; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sym = (struct kallsyms_symbol *)
+			((char *)(ka_hdr) + ka_hdr->symbol_off);
+		ka_str = 
+			((char *)(ka_hdr) + ka_hdr->string_off);
+		for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+			p = ka_str + ka_sym->name_off;
+			if (strcmp(p, name) == 0)
+				break;
+			/* Unversioned requests match versioned names */
+			if (!(pt_R = strstr(p, "_R")))
+				continue;
+			l = strlen(pt_R);
+			if (l < 10)
+				continue;	/* Not _R.*xxxxxxxx */
+			(void)simple_strtoul(pt_R+l-8, &p2, 16);
+			if (*p2)
+				continue;	/* Not _R.*xxxxxxxx */
+			if (strncmp(p, name, pt_R-p) == 0)
+				break;	/* Match with version */
+		}
+		if (i < ka_hdr->symbols)
+			break;
+	}
+
+	if (token)
+		*token = (unsigned long)m;
+	if (!m)
+		return(0);	/* not found */
+
+	ka_sec = (const struct kallsyms_section *)
+		((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off);
+	*mod_name = m->name;
+	*mod_start = ka_hdr->start;
+	*mod_end = ka_hdr->end;
+	*sec_name = ka_sec->name_off + ka_str;
+	*sec_start = ka_sec->start;
+	*sec_end = ka_sec->start + ka_sec->size;
+	*sym_name = ka_sym->name_off + ka_str;
+	*sym_start = ka_sym->symbol_addr;
+	if (i < ka_hdr->symbols-1) {
+		const struct kallsyms_symbol *ka_symn = ka_sym;
+		kallsyms_next_sym(ka_hdr, ka_symn);
+		*sym_end = ka_symn->symbol_addr;
+	}
+	else
+		*sym_end = *sec_end;
+	return(1);
+}
+
+int kallsyms_address_to_symbol(
+	unsigned long	  address,	/* Address to lookup */
+	const char	**mod_name,	/* Set to module name */
+	unsigned long 	 *mod_start,	/* Set to start address of module */
+	unsigned long 	 *mod_end,	/* Set to end address of module */
+	const char	**sec_name,	/* Set to section name */
+	unsigned long 	 *sec_start,	/* Set to start address of section */
+	unsigned long 	 *sec_end,	/* Set to end address of section */
+	const char	**sym_name,	/* Set to full symbol name */
+	unsigned long 	 *sym_start,	/* Set to start address of symbol */
+	unsigned long 	 *sym_end	/* Set to end address of symbol */
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec = NULL;
+	const struct kallsyms_symbol	*ka_sym;
+	const char			*ka_str;
+	const struct module *m;
+	int i;
+	unsigned long end;
+
+	for (m = module_list; m; m = m->next) {
+	  
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sec = (const struct kallsyms_section *)
+			((char *)ka_hdr + ka_hdr->section_off);
+		/* Is the address in any section in this module? */
+		for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) {
+			if (ka_sec->start <= address &&
+			    (ka_sec->start + ka_sec->size) > address)
+				break;
+		}
+		if (i < ka_hdr->sections)
+			break;	/* Found a matching section */
+	}
+
+	if (!m)
+		return(0);	/* not found */
+
+	ka_sym = (struct kallsyms_symbol *)
+		((char *)(ka_hdr) + ka_hdr->symbol_off);
+	ka_str = 
+		((char *)(ka_hdr) + ka_hdr->string_off);
+	*mod_name = m->name;
+	*mod_start = ka_hdr->start;
+	*mod_end = ka_hdr->end;
+	*sec_name = ka_sec->name_off + ka_str;
+	*sec_start = ka_sec->start;
+	*sec_end = ka_sec->start + ka_sec->size;
+	*sym_name = *sec_name;		/* In case we find no matching symbol */
+	*sym_start = *sec_start;
+	*sym_end = *sec_end;
+
+	for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+		if (ka_sym->symbol_addr > address)
+			continue;
+		if (i < ka_hdr->symbols-1) {
+			const struct kallsyms_symbol *ka_symn = ka_sym;
+			kallsyms_next_sym(ka_hdr, ka_symn);
+			end = ka_symn->symbol_addr;
+		}
+		else
+			end = *sec_end;
+		if (end <= address)
+			continue;
+		if ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off
+		    != (char *)ka_sec)
+			continue;	/* wrong section */
+		*sym_name = ka_str + ka_sym->name_off;
+		*sym_start = ka_sym->symbol_addr;
+		*sym_end = end;
+		break;
+	}
+	return(1);
+}
+
+/* List all sections in all modules.  The callback routine is invoked with
+ * token, module name, section name, section start, section end, section flags.
+ */
+int kallsyms_sections(void *token,
+		      int (*callback)(void *, const char *, const char *, ElfW(Addr), ElfW(Addr), ElfW(Word)))
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec = NULL;
+	const char			*ka_str;
+	const struct module *m;
+	int i;
+
+	for (m = module_list; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sec = (const struct kallsyms_section *) ((char *)ka_hdr + ka_hdr->section_off);
+		ka_str = ((char *)(ka_hdr) + ka_hdr->string_off);
+		for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) {
+			if (callback(
+				token,
+				*(m->name) ? m->name : "kernel",
+				ka_sec->name_off + ka_str,
+				ka_sec->start,
+				ka_sec->start + ka_sec->size,
+				ka_sec->flags))
+				return(0);
+		}
+	}
+	return(1);
+}
--- linux/kernel/module.c.orig	Fri Sep 20 17:20:19 2002
+++ linux/kernel/module.c	Wed Sep 25 21:52:00 2002
@@ -3,6 +3,7 @@
 #include <linux/module.h>
 #include <asm/module.h>
 #include <asm/uaccess.h>
+#include <linux/kallsyms.h>
 #include <linux/vmalloc.h>
 #include <linux/smp_lock.h>
 #include <asm/pgalloc.h>
@@ -39,13 +40,19 @@
 extern const struct exception_table_entry __start___ex_table[];
 extern const struct exception_table_entry __stop___ex_table[];
 
-extern const char __start___kallsyms[] __attribute__ ((weak));
-extern const char __stop___kallsyms[] __attribute__ ((weak));
+extern const char __start___kallsyms[] __attribute__((weak));
+extern const char __stop___kallsyms[] __attribute__((weak));
+
+/* modutils uses these exported symbols to figure out if
+   kallsyms support is present */
+
+EXPORT_SYMBOL(__start___kallsyms);
+EXPORT_SYMBOL(__stop___kallsyms);
 
 struct module kernel_module =
 {
 	.size_of_struct		= sizeof(struct module),
-	.name 			= "",
+	.name 			= NULL,
 	.uc	 		= {ATOMIC_INIT(1)},
 	.flags			= MOD_RUNNING,
 	.syms			= __start___ksymtab,
@@ -1220,6 +1227,30 @@
 	.show	= s_show
 };
 
+#define MODLIST_SIZE 4096
+
+/*
+ * this function isn't smp safe but that's not really a problem; it's
+ * called from oops context only and any locking could actually prevent
+ * the oops from going out; the line that is generated is informational
+ * only and should NEVER prevent the real oops from going out. 
+ */
+void print_modules(void)
+{
+	static char modlist[MODLIST_SIZE];
+	struct module *this_mod;
+	int pos = 0;
+
+	this_mod = module_list;
+	while (this_mod) {
+		if (this_mod->name)
+			pos += snprintf(modlist+pos, MODLIST_SIZE-pos-1, 
+					"%s ", this_mod->name);
+		this_mod = this_mod->next;
+	}
+	printk("%s\n",modlist);
+}
+
 #else		/* CONFIG_MODULES */
 
 /* Dummy syscalls for people who don't want modules */
@@ -1265,4 +1296,79 @@
 	return 1;
 }
 
+void print_modules(void)
+{
+}
+
 #endif	/* CONFIG_MODULES */
+
+
+#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
+
+#define MAX_SYMBOL_SIZE 512
+
+static void
+address_to_exported_symbol(unsigned long address, const char **mod_name, 
+			   const char **sym_name, unsigned long *sym_start,
+			   unsigned long *sym_end)
+{
+	struct module *this_mod;
+	int i;
+
+	for (this_mod = module_list; this_mod; this_mod = this_mod->next) {
+		/* walk the symbol list of this module. Only symbols
+		   who's address is smaller than the searched for address
+		   are relevant; and only if it's better than the best so far */
+		for (i = 0; i < this_mod->nsyms; i++)
+			if ((this_mod->syms[i].value <= address) &&
+			    (*sym_start < this_mod->syms[i].value)) {
+				*sym_start = this_mod->syms[i].value;
+				*sym_name  = this_mod->syms[i].name;
+				*mod_name  = this_mod->name;
+				if (i + 1 < this_mod->nsyms)
+					*sym_end = this_mod->syms[i+1].value;
+				else
+					*sym_end = (unsigned long) this_mod + this_mod->size;
+			}
+	}
+}
+
+int
+print_symbol(const char *fmt, unsigned long address)
+{
+	/* static to not take up stackspace; if we race here too bad */
+	static char buffer[MAX_SYMBOL_SIZE];
+
+	const char *mod_name = NULL, *sec_name = NULL, *sym_name = NULL;
+	unsigned long mod_start, mod_end, sec_start, sec_end,
+		sym_start, sym_end;
+	char *tag = "";
+	
+	memset(buffer, 0, MAX_SYMBOL_SIZE);
+
+	sym_start = 0;
+	if (!kallsyms_address_to_symbol(address, &mod_name, &mod_start, &mod_end, &sec_name, &sec_start, &sec_end, &sym_name, &sym_start, &sym_end)) {
+		tag = "E ";
+		address_to_exported_symbol(address, &mod_name, &sym_name, &sym_start, &sym_end);
+	}
+
+	if (sym_start) {
+		if (mod_name)
+		    snprintf(buffer, MAX_SYMBOL_SIZE - 1, "%s%s+%#x/%#x [%s]",
+			 tag, sym_name,
+			 (unsigned int)(address - sym_start),
+			 (unsigned int)(sym_end - sym_start),
+			 mod_name);
+		else
+		    snprintf(buffer, MAX_SYMBOL_SIZE - 1, "%s%s+%#x/%#x",
+			 tag, sym_name,
+			 (unsigned int)(address - sym_start),
+			 (unsigned int)(sym_end - sym_start));
+		printk(fmt, buffer);
+	} else {
+		printk(fmt, "[unresolved]");
+	}
+	return 0;
+}
+
+#endif
--- linux/Makefile.orig	Wed Sep 25 21:43:13 2002
+++ linux/Makefile	Wed Sep 25 21:46:56 2002
@@ -138,6 +138,7 @@
 MAKEFILES	= $(TOPDIR)/.config
 GENKSYMS	= /sbin/genksyms
 DEPMOD		= /sbin/depmod
+KALLSYMS	= /sbin/kallsyms
 PERL		= perl
 MODFLAGS	= -DMODULE
 CFLAGS_MODULE   = $(MODFLAGS)
@@ -291,32 +292,64 @@
 vmlinux-objs := $(HEAD) $(INIT) $(CORE_FILES) $(LIBS) $(DRIVERS) $(NETWORKS)
 
 quiet_cmd_link_vmlinux = LD      $@
-cmd_link_vmlinux = $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $(HEAD) $(INIT) \
-		--start-group \
-		$(CORE_FILES) \
-		$(LIBS) \
-		$(DRIVERS) \
-		$(NETWORKS) \
-		--end-group \
-		-o vmlinux
+define cmd_link_vmlinux
+	$(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) $(HEAD) $(INIT) \
+	--start-group \
+	$(CORE_FILES) \
+	$(LIBS) \
+	$(DRIVERS) \
+	$(NETWORKS) \
+	--end-group \
+	$(filter $(kallsyms.o),$^) \
+	-o $@
+endef
 
 #	set -e makes the rule exit immediately on error
 
-define rule_link_vmlinux
+define rule_vmlinux
 	set -e
 	echo '  Generating build number'
-	. scripts/mkversion > .tmpversion
-	mv -f .tmpversion .version
+	. scripts/mkversion > .tmp_version
+	mv -f .tmp_version .version
 	+$(MAKE) -C init
 	$(call cmd,link_vmlinux)
 	echo 'cmd_$@ := $(cmd_link_vmlinux)' > $(@D)/.$(@F).cmd
-	$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
+	$(NM) $@ | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
 endef
 
 LDFLAGS_vmlinux += -T arch/$(ARCH)/vmlinux.lds.s
 
-vmlinux: $(vmlinux-objs) arch/$(ARCH)/vmlinux.lds.s FORCE
-	$(call if_changed_rule,link_vmlinux)
+#	Generate section listing all symbols and add it into vmlinux
+
+ifdef CONFIG_KALLSYMS
+
+kallsyms.o := .tmp_kallsyms.o
+
+quiet_cmd_kallsyms = KSYM    $@
+cmd_kallsyms = $(KALLSYMS) $< > $@
+
+.tmp_kallsyms.o: .tmp_vmlinux
+	$(call cmd,kallsyms)
+
+# 	After generating .tmp_vmlinux just like vmlinux, decrement the version
+#	number again, so the final vmlinux gets the same one.
+#	Ignore return value of 'expr'.
+
+define rule_.tmp_vmlinux
+	$(rule_vmlinux)
+	if expr 0`cat .version` - 1 > .tmp_version; then true; fi
+	mv -f .tmp_version .version
+endef
+
+.tmp_vmlinux: $(vmlinux-objs) arch/$(ARCH)/vmlinux.lds.s FORCE
+	$(call if_changed_rule,.tmp_vmlinux)
+
+endif
+
+#	Finally the vmlinux rule
+
+vmlinux: $(vmlinux-objs) $(kallsyms.o) arch/$(ARCH)/vmlinux.lds.s FORCE
+	$(call if_changed_rule,vmlinux)
 
 #	The actual objects are generated when descending, 
 #	make sure no implicit rule kicks in
@@ -820,7 +853,7 @@
 
 # FIXME Should go into a make.lib or something 
 # ===========================================================================
-echo_target = $(RELDIR)/$@
+echo_target = $@
 
 a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(NOSTDINC_FLAGS) \
 	  $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:52           ` Linus Torvalds
@ 2002-09-25 20:04             ` Ingo Molnar
  2002-09-25 20:31             ` Jeff Garzik
  1 sibling, 0 replies; 23+ messages in thread
From: Ingo Molnar @ 2002-09-25 20:04 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Kai Germaschewski, linux-kernel, Rusty Russell, Arjan van de Ven


one config variant (no-modules, no-kksymoops) did not compile due to
linux/errno.h not being included in linux/module.h, the attached patch
does this properly.

	Ingo

--- linux/arch/i386/kernel/head.S.orig	Fri Sep 20 17:20:16 2002
+++ linux/arch/i386/kernel/head.S	Wed Sep 25 21:46:56 2002
@@ -121,7 +121,7 @@
  */
 	xorl %eax,%eax
 	movl $__bss_start,%edi
-	movl $_end,%ecx
+	movl $__bss_stop,%ecx
 	subl %edi,%ecx
 	rep
 	stosb
--- linux/arch/i386/kernel/process.c.orig	Fri Sep 20 17:20:12 2002
+++ linux/arch/i386/kernel/process.c	Wed Sep 25 21:46:56 2002
@@ -33,6 +33,7 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/mc146818rtc.h>
+#include <linux/module.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -155,8 +156,6 @@
 
 __setup("idle=", idle_setup);
 
-extern void show_trace(unsigned long* esp);
-
 void show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
@@ -164,6 +163,8 @@
 	printk("\n");
 	printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
 	printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id());
+	print_symbol("EIP is at %s\n", regs->eip);
+
 	if (regs->xcs & 3)
 		printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
 	printk(" EFLAGS: %08lx    %s\n",regs->eflags, print_tainted());
--- linux/arch/i386/kernel/traps.c.orig	Fri Sep 20 17:20:19 2002
+++ linux/arch/i386/kernel/traps.c	Wed Sep 25 21:46:56 2002
@@ -94,7 +94,6 @@
 
 #ifdef CONFIG_MODULES
 
-extern struct module *module_list;
 extern struct module kernel_module;
 
 static inline int kernel_text_address(unsigned long addr)
@@ -142,10 +141,12 @@
 	while (((long) stack & (THREAD_SIZE-1)) != 0) {
 		addr = *stack++;
 		if (kernel_text_address(addr)) {
-			if (i && ((i % 6) == 0))
-				printk("\n   ");
 			printk("[<%08lx>] ", addr);
-			i++;
+			if (print_symbol("%s\n", addr)) {
+				/* save screen space */
+				if ((i++ % 6) == 0)
+					printk("\n   ");
+			}
 		}
 	}
 	printk("\n");
@@ -206,8 +207,11 @@
 		esp = regs->esp;
 		ss = regs->xss & 0xffff;
 	}
+	print_modules();
 	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]    %s\nEFLAGS: %08lx\n",
 		smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags);
+
+	print_symbol("EIP is at %s\n", regs->eip);
 	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
 		regs->eax, regs->ebx, regs->ecx, regs->edx);
 	printk("esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
@@ -268,6 +272,7 @@
 		(unsigned long)file < PAGE_OFFSET || __get_user(c, file))
 		file = "<bad filename>";
 
+	printk("------------[ cut here ]------------\n");
 	printk("kernel BUG at %s:%d!\n", file, line);
 
 no_bug:
--- linux/arch/i386/Config.help.orig	Fri Sep 20 17:20:16 2002
+++ linux/arch/i386/Config.help	Wed Sep 25 21:46:56 2002
@@ -946,6 +946,11 @@
   of the BUG call as well as the EIP and oops trace.  This aids
   debugging but costs about 70-100K of memory.
 
+CONFIG_KALLSYMS
+  Say Y here to let the kernel print out symbolic crash information and
+  symbolic stack backtraces. This increases the size of the kernel
+  somewhat, as all symbols have to be loaded into the kernel image.
+
 CONFIG_DEBUG_OBSOLETE
   Say Y here if you want to reduce the chances of the tree compiling,
   and are prepared to dig into driver internals to fix compile errors.
--- linux/arch/i386/config.in.orig	Wed Sep 25 21:43:13 2002
+++ linux/arch/i386/config.in	Wed Sep 25 21:46:56 2002
@@ -435,6 +435,7 @@
    if [ "$CONFIG_HIGHMEM" = "y" ]; then
       bool '  Highmem debugging' CONFIG_DEBUG_HIGHMEM
    fi
+   bool '  Load all symbols for debugging/kksymoops' CONFIG_KALLSYMS
 fi
 
 if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then
--- linux/arch/i386/vmlinux.lds.S.orig	Fri Sep 20 17:20:19 2002
+++ linux/arch/i386/vmlinux.lds.S	Wed Sep 25 21:46:56 2002
@@ -78,9 +78,13 @@
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
   __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
+  .bss : { *(.bss) }
+  __bss_stop = .; 
+
+  __start___kallsyms = .;     /* All kernel symbols */
+  __kallsyms : { *(__kallsyms) }
+  __stop___kallsyms = .;
+
   _end = . ;
 
   /* Sections to be discarded */
--- linux/include/linux/kallsyms.h.orig	Wed Sep 25 21:46:56 2002
+++ linux/include/linux/kallsyms.h	Wed Sep 25 21:46:56 2002
@@ -0,0 +1,163 @@
+/* kallsyms headers
+   Copyright 2000 Keith Owens <kaos@ocs.com.au>
+
+   This file is part of the Linux modutils.  It is exported to kernel
+   space so debuggers can access the kallsyms data.
+
+   The kallsyms data contains all the non-stack symbols from a kernel
+   or a module.  The kernel symbols are held between __start___kallsyms
+   and __stop___kallsyms.  The symbols for a module are accessed via
+   the struct module chain which is based at module_list.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ident "$Id: linux-2.4.9-kallsyms.patch,v 1.8 2002/02/11 18:34:53 arjanv Exp $"
+
+#ifndef MODUTILS_KALLSYMS_H
+#define MODUTILS_KALLSYMS_H 1
+
+/* Have to (re)define these ElfW entries here because external kallsyms
+ * code does not have access to modutils/include/obj.h.  This code is
+ * included from user spaces tools (modutils) and kernel, they need
+ * different includes.
+ */
+
+#ifndef ELFCLASS32
+#ifdef __KERNEL__
+#include <linux/elf.h>
+#else	/* __KERNEL__ */
+#include <elf.h>
+#endif	/* __KERNEL__ */
+#endif	/* ELFCLASS32 */
+
+#ifndef ELFCLASSM
+#define ELFCLASSM ELF_CLASS
+#endif
+
+#ifndef ElfW
+# if ELFCLASSM == ELFCLASS32
+#  define ElfW(x)  Elf32_ ## x
+#  define ELFW(x)  ELF32_ ## x
+# else
+#  define ElfW(x)  Elf64_ ## x
+#  define ELFW(x)  ELF64_ ## x
+# endif
+#endif
+
+/* Format of data in the kallsyms section.
+ * Most of the fields are small numbers but the total size and all
+ * offsets can be large so use the 32/64 bit types for these fields.
+ *
+ * Do not use sizeof() on these structures, modutils may be using extra
+ * fields.  Instead use the size fields in the header to access the
+ * other bits of data.
+ */  
+
+struct kallsyms_header {
+	int		size;		/* Size of this header */
+	ElfW(Word)	total_size;	/* Total size of kallsyms data */
+	int		sections;	/* Number of section entries */
+	ElfW(Off)	section_off;	/* Offset to first section entry */
+	int		section_size;	/* Size of one section entry */
+	int		symbols;	/* Number of symbol entries */
+	ElfW(Off)	symbol_off;	/* Offset to first symbol entry */
+	int		symbol_size;	/* Size of one symbol entry */
+	ElfW(Off)	string_off;	/* Offset to first string */
+	ElfW(Addr)	start;		/* Start address of first section */
+	ElfW(Addr)	end;		/* End address of last section */
+};
+
+struct kallsyms_section {
+	ElfW(Addr)	start;		/* Start address of section */
+	ElfW(Word)	size;		/* Size of this section */
+	ElfW(Off)	name_off;	/* Offset to section name */
+	ElfW(Word)	flags;		/* Flags from section */
+};
+
+struct kallsyms_symbol {
+	ElfW(Off)	section_off;	/* Offset to section that owns this symbol */
+	ElfW(Addr)	symbol_addr;	/* Address of symbol */
+	ElfW(Off)	name_off;	/* Offset to symbol name */
+};
+
+#define KALLSYMS_SEC_NAME "__kallsyms"
+#define KALLSYMS_IDX 2			/* obj_kallsyms creates kallsyms as section 2 */
+
+#define kallsyms_next_sec(h,s) \
+	((s) = (struct kallsyms_section *)((char *)(s) + (h)->section_size))
+#define kallsyms_next_sym(h,s) \
+	((s) = (struct kallsyms_symbol *)((char *)(s) + (h)->symbol_size))
+
+#ifdef CONFIG_KALLSYMS
+
+int kallsyms_symbol_to_address(
+	const char       *name,			/* Name to lookup */
+	unsigned long    *token,		/* Which module to start with */
+	const char      **mod_name,		/* Set to module name or "kernel" */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	);
+
+int kallsyms_address_to_symbol(
+	unsigned long     address,		/* Address to lookup */
+	const char      **mod_name,		/* Set to module name */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	);
+
+int kallsyms_sections(void *token,
+		      int (*callback)(void *,	/* token */
+		      	const char *,		/* module name */
+			const char *,		/* section name */
+			ElfW(Addr),		/* Section start */
+			ElfW(Addr),		/* Section end */
+			ElfW(Word)		/* Section flags */
+		      )
+		);
+
+#else
+
+static inline int kallsyms_address_to_symbol(
+	unsigned long     address,		/* Address to lookup */
+	const char      **mod_name,		/* Set to module name */
+	unsigned long    *mod_start,		/* Set to start address of module */
+	unsigned long    *mod_end,		/* Set to end address of module */
+	const char      **sec_name,		/* Set to section name */
+	unsigned long    *sec_start,		/* Set to start address of section */
+	unsigned long    *sec_end,		/* Set to end address of section */
+	const char      **sym_name,		/* Set to full symbol name */
+	unsigned long    *sym_start,		/* Set to start address of symbol */
+	unsigned long    *sym_end		/* Set to end address of symbol */
+	)
+{
+	return -ESRCH;
+}
+
+#endif
+
+#endif /* kallsyms.h */
--- linux/include/linux/module.h.orig	Fri Sep 20 17:20:32 2002
+++ linux/include/linux/module.h	Wed Sep 25 22:01:19 2002
@@ -10,6 +10,7 @@
 #include <linux/config.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
+#include <linux/errno.h>
 
 #include <asm/atomic.h>
 
@@ -316,8 +317,6 @@
 #define MOD_DEC_USE_COUNT	do { } while (0)
 #define MOD_IN_USE		1
 
-extern struct module *module_list;
-
 #endif /* !__GENKSYMS__ */
 
 #endif /* MODULE */
@@ -504,6 +503,30 @@
 #define SET_MODULE_OWNER(some_struct) do { (some_struct)->owner = THIS_MODULE; } while (0)
 #else
 #define SET_MODULE_OWNER(some_struct) do { } while (0)
+#endif
+
+extern void print_modules(void);
+
+#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
+
+extern struct module *module_list;
+
+/*
+ * print_symbols takes a format string containing one %s.
+ * If support for resolving symbols is compiled in, the %s will
+ * be replaced by the closest symbol to the address and the entire
+ * string is printk()ed. Otherwise, nothing is printed.
+ */
+extern int print_symbol(const char *fmt, unsigned long address);
+
+#else
+
+static inline int
+print_symbol(const char *fmt, unsigned long address)
+{
+	return -ESRCH;
+}
+
 #endif
 
 #endif /* _LINUX_MODULE_H */
--- linux/include/linux/sched.h.orig	Wed Sep 25 21:43:13 2002
+++ linux/include/linux/sched.h	Wed Sep 25 21:46:56 2002
@@ -151,7 +151,13 @@
 
 extern void sched_init(void);
 extern void init_idle(task_t *idle, int cpu);
+
 extern void show_state(void);
+extern void show_trace(unsigned long *stack);
+extern void show_stack(unsigned long *stack);
+extern void show_regs(struct pt_regs *);
+
+
 extern void cpu_init (void);
 extern void trap_init(void);
 extern void update_process_times(int user);
--- linux/include/asm-i386/hardirq.h.orig	Fri Sep 20 17:20:32 2002
+++ linux/include/asm-i386/hardirq.h	Wed Sep 25 21:46:56 2002
@@ -97,6 +97,4 @@
   extern void synchronize_irq(unsigned int irq);
 #endif /* CONFIG_SMP */
 
-extern void show_stack(unsigned long * esp);
-
 #endif /* __ASM_HARDIRQ_H */
--- linux/include/asm-i386/ptrace.h.orig	Fri Sep 20 17:20:16 2002
+++ linux/include/asm-i386/ptrace.h	Wed Sep 25 21:46:56 2002
@@ -57,7 +57,6 @@
 #ifdef __KERNEL__
 #define user_mode(regs) ((VM_MASK & (regs)->eflags) || (3 & (regs)->xcs))
 #define instruction_pointer(regs) ((regs)->eip)
-extern void show_regs(struct pt_regs *);
 #endif
 
 #endif
--- linux/kernel/Makefile.orig	Fri Sep 20 17:20:19 2002
+++ linux/kernel/Makefile	Wed Sep 25 21:46:56 2002
@@ -3,7 +3,7 @@
 #
 
 export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
-		printk.o platform.o suspend.o dma.o
+	      printk.o platform.o suspend.o dma.o module.o
 
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o time.o softirq.o resource.o \
@@ -14,6 +14,7 @@
 obj-$(CONFIG_SMP) += cpu.o
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
+obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += pm.o
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o
--- linux/kernel/kallsyms.c.orig	Wed Sep 25 21:46:56 2002
+++ linux/kernel/kallsyms.c	Wed Sep 25 21:51:18 2002
@@ -0,0 +1,227 @@
+/*
+ * kksymoops.c: in-kernel printing of symbolic oopses and stack traces.
+ *
+ *  Copyright 2000 Keith Owens <kaos@ocs.com.au> April 2000
+ *  Copyright 2002 Arjan van de Ven <arjanv@redhat.com>
+ *
+   This code uses the list of all kernel and module symbols to :-
+
+   * Find any non-stack symbol in a kernel or module.  Symbols do
+     not have to be exported for debugging.
+
+   * Convert an address to the module (or kernel) that owns it, the
+     section it is in and the nearest symbol.  This finds all non-stack
+     symbols, not just exported ones.
+
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+
+/* A symbol can appear in more than one module.  A token is used to
+ * restart the scan at the next module, set the token to 0 for the
+ * first scan of each symbol.
+ */
+
+int kallsyms_symbol_to_address(
+	const char	 *name,		/* Name to lookup */
+	unsigned long 	 *token,	/* Which module to start at */
+	const char	**mod_name,	/* Set to module name */
+	unsigned long 	 *mod_start,	/* Set to start address of module */
+	unsigned long 	 *mod_end,	/* Set to end address of module */
+	const char	**sec_name,	/* Set to section name */
+	unsigned long 	 *sec_start,	/* Set to start address of section */
+	unsigned long 	 *sec_end,	/* Set to end address of section */
+	const char	**sym_name,	/* Set to full symbol name */
+	unsigned long 	 *sym_start,	/* Set to start address of symbol */
+	unsigned long 	 *sym_end	/* Set to end address of symbol */
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec;
+	const struct kallsyms_symbol	*ka_sym = NULL;
+	const char			*ka_str = NULL;
+	const struct module *m;
+	int i = 0, l;
+	const char *p, *pt_R;
+	char *p2;
+
+	/* Restart? */
+	m = module_list;
+	if (token && *token) {
+		for (; m; m = m->next)
+			if ((unsigned long)m == *token)
+				break;
+		if (m)
+			m = m->next;
+	}
+
+	for (; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sym = (struct kallsyms_symbol *)
+			((char *)(ka_hdr) + ka_hdr->symbol_off);
+		ka_str = 
+			((char *)(ka_hdr) + ka_hdr->string_off);
+		for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+			p = ka_str + ka_sym->name_off;
+			if (strcmp(p, name) == 0)
+				break;
+			/* Unversioned requests match versioned names */
+			if (!(pt_R = strstr(p, "_R")))
+				continue;
+			l = strlen(pt_R);
+			if (l < 10)
+				continue;	/* Not _R.*xxxxxxxx */
+			(void)simple_strtoul(pt_R+l-8, &p2, 16);
+			if (*p2)
+				continue;	/* Not _R.*xxxxxxxx */
+			if (strncmp(p, name, pt_R-p) == 0)
+				break;	/* Match with version */
+		}
+		if (i < ka_hdr->symbols)
+			break;
+	}
+
+	if (token)
+		*token = (unsigned long)m;
+	if (!m)
+		return(0);	/* not found */
+
+	ka_sec = (const struct kallsyms_section *)
+		((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off);
+	*mod_name = m->name;
+	*mod_start = ka_hdr->start;
+	*mod_end = ka_hdr->end;
+	*sec_name = ka_sec->name_off + ka_str;
+	*sec_start = ka_sec->start;
+	*sec_end = ka_sec->start + ka_sec->size;
+	*sym_name = ka_sym->name_off + ka_str;
+	*sym_start = ka_sym->symbol_addr;
+	if (i < ka_hdr->symbols-1) {
+		const struct kallsyms_symbol *ka_symn = ka_sym;
+		kallsyms_next_sym(ka_hdr, ka_symn);
+		*sym_end = ka_symn->symbol_addr;
+	}
+	else
+		*sym_end = *sec_end;
+	return(1);
+}
+
+int kallsyms_address_to_symbol(
+	unsigned long	  address,	/* Address to lookup */
+	const char	**mod_name,	/* Set to module name */
+	unsigned long 	 *mod_start,	/* Set to start address of module */
+	unsigned long 	 *mod_end,	/* Set to end address of module */
+	const char	**sec_name,	/* Set to section name */
+	unsigned long 	 *sec_start,	/* Set to start address of section */
+	unsigned long 	 *sec_end,	/* Set to end address of section */
+	const char	**sym_name,	/* Set to full symbol name */
+	unsigned long 	 *sym_start,	/* Set to start address of symbol */
+	unsigned long 	 *sym_end	/* Set to end address of symbol */
+	)
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec = NULL;
+	const struct kallsyms_symbol	*ka_sym;
+	const char			*ka_str;
+	const struct module *m;
+	int i;
+	unsigned long end;
+
+	for (m = module_list; m; m = m->next) {
+	  
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sec = (const struct kallsyms_section *)
+			((char *)ka_hdr + ka_hdr->section_off);
+		/* Is the address in any section in this module? */
+		for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) {
+			if (ka_sec->start <= address &&
+			    (ka_sec->start + ka_sec->size) > address)
+				break;
+		}
+		if (i < ka_hdr->sections)
+			break;	/* Found a matching section */
+	}
+
+	if (!m)
+		return(0);	/* not found */
+
+	ka_sym = (struct kallsyms_symbol *)
+		((char *)(ka_hdr) + ka_hdr->symbol_off);
+	ka_str = 
+		((char *)(ka_hdr) + ka_hdr->string_off);
+	*mod_name = m->name;
+	*mod_start = ka_hdr->start;
+	*mod_end = ka_hdr->end;
+	*sec_name = ka_sec->name_off + ka_str;
+	*sec_start = ka_sec->start;
+	*sec_end = ka_sec->start + ka_sec->size;
+	*sym_name = *sec_name;		/* In case we find no matching symbol */
+	*sym_start = *sec_start;
+	*sym_end = *sec_end;
+
+	for (i = 0; i < ka_hdr->symbols; ++i, kallsyms_next_sym(ka_hdr, ka_sym)) {
+		if (ka_sym->symbol_addr > address)
+			continue;
+		if (i < ka_hdr->symbols-1) {
+			const struct kallsyms_symbol *ka_symn = ka_sym;
+			kallsyms_next_sym(ka_hdr, ka_symn);
+			end = ka_symn->symbol_addr;
+		}
+		else
+			end = *sec_end;
+		if (end <= address)
+			continue;
+		if ((char *)ka_hdr + ka_hdr->section_off + ka_sym->section_off
+		    != (char *)ka_sec)
+			continue;	/* wrong section */
+		*sym_name = ka_str + ka_sym->name_off;
+		*sym_start = ka_sym->symbol_addr;
+		*sym_end = end;
+		break;
+	}
+	return(1);
+}
+
+/* List all sections in all modules.  The callback routine is invoked with
+ * token, module name, section name, section start, section end, section flags.
+ */
+int kallsyms_sections(void *token,
+		      int (*callback)(void *, const char *, const char *, ElfW(Addr), ElfW(Addr), ElfW(Word)))
+{
+	const struct kallsyms_header	*ka_hdr = NULL;	/* stupid gcc */
+	const struct kallsyms_section	*ka_sec = NULL;
+	const char			*ka_str;
+	const struct module *m;
+	int i;
+
+	for (m = module_list; m; m = m->next) {
+		if (!mod_member_present(m, kallsyms_start) || 
+		    !mod_member_present(m, kallsyms_end) ||
+		    m->kallsyms_start >= m->kallsyms_end)
+			continue;
+		ka_hdr = (struct kallsyms_header *)m->kallsyms_start;
+		ka_sec = (const struct kallsyms_section *) ((char *)ka_hdr + ka_hdr->section_off);
+		ka_str = ((char *)(ka_hdr) + ka_hdr->string_off);
+		for (i = 0; i < ka_hdr->sections; ++i, kallsyms_next_sec(ka_hdr, ka_sec)) {
+			if (callback(
+				token,
+				*(m->name) ? m->name : "kernel",
+				ka_sec->name_off + ka_str,
+				ka_sec->start,
+				ka_sec->start + ka_sec->size,
+				ka_sec->flags))
+				return(0);
+		}
+	}
+	return(1);
+}
--- linux/kernel/module.c.orig	Fri Sep 20 17:20:19 2002
+++ linux/kernel/module.c	Wed Sep 25 21:52:00 2002
@@ -3,6 +3,7 @@
 #include <linux/module.h>
 #include <asm/module.h>
 #include <asm/uaccess.h>
+#include <linux/kallsyms.h>
 #include <linux/vmalloc.h>
 #include <linux/smp_lock.h>
 #include <asm/pgalloc.h>
@@ -39,13 +40,19 @@
 extern const struct exception_table_entry __start___ex_table[];
 extern const struct exception_table_entry __stop___ex_table[];
 
-extern const char __start___kallsyms[] __attribute__ ((weak));
-extern const char __stop___kallsyms[] __attribute__ ((weak));
+extern const char __start___kallsyms[] __attribute__((weak));
+extern const char __stop___kallsyms[] __attribute__((weak));
+
+/* modutils uses these exported symbols to figure out if
+   kallsyms support is present */
+
+EXPORT_SYMBOL(__start___kallsyms);
+EXPORT_SYMBOL(__stop___kallsyms);
 
 struct module kernel_module =
 {
 	.size_of_struct		= sizeof(struct module),
-	.name 			= "",
+	.name 			= NULL,
 	.uc	 		= {ATOMIC_INIT(1)},
 	.flags			= MOD_RUNNING,
 	.syms			= __start___ksymtab,
@@ -1220,6 +1227,30 @@
 	.show	= s_show
 };
 
+#define MODLIST_SIZE 4096
+
+/*
+ * this function isn't smp safe but that's not really a problem; it's
+ * called from oops context only and any locking could actually prevent
+ * the oops from going out; the line that is generated is informational
+ * only and should NEVER prevent the real oops from going out. 
+ */
+void print_modules(void)
+{
+	static char modlist[MODLIST_SIZE];
+	struct module *this_mod;
+	int pos = 0;
+
+	this_mod = module_list;
+	while (this_mod) {
+		if (this_mod->name)
+			pos += snprintf(modlist+pos, MODLIST_SIZE-pos-1, 
+					"%s ", this_mod->name);
+		this_mod = this_mod->next;
+	}
+	printk("%s\n",modlist);
+}
+
 #else		/* CONFIG_MODULES */
 
 /* Dummy syscalls for people who don't want modules */
@@ -1265,4 +1296,79 @@
 	return 1;
 }
 
+void print_modules(void)
+{
+}
+
 #endif	/* CONFIG_MODULES */
+
+
+#if defined(CONFIG_MODULES) || defined(CONFIG_KALLSYMS)
+
+#define MAX_SYMBOL_SIZE 512
+
+static void
+address_to_exported_symbol(unsigned long address, const char **mod_name, 
+			   const char **sym_name, unsigned long *sym_start,
+			   unsigned long *sym_end)
+{
+	struct module *this_mod;
+	int i;
+
+	for (this_mod = module_list; this_mod; this_mod = this_mod->next) {
+		/* walk the symbol list of this module. Only symbols
+		   who's address is smaller than the searched for address
+		   are relevant; and only if it's better than the best so far */
+		for (i = 0; i < this_mod->nsyms; i++)
+			if ((this_mod->syms[i].value <= address) &&
+			    (*sym_start < this_mod->syms[i].value)) {
+				*sym_start = this_mod->syms[i].value;
+				*sym_name  = this_mod->syms[i].name;
+				*mod_name  = this_mod->name;
+				if (i + 1 < this_mod->nsyms)
+					*sym_end = this_mod->syms[i+1].value;
+				else
+					*sym_end = (unsigned long) this_mod + this_mod->size;
+			}
+	}
+}
+
+int
+print_symbol(const char *fmt, unsigned long address)
+{
+	/* static to not take up stackspace; if we race here too bad */
+	static char buffer[MAX_SYMBOL_SIZE];
+
+	const char *mod_name = NULL, *sec_name = NULL, *sym_name = NULL;
+	unsigned long mod_start, mod_end, sec_start, sec_end,
+		sym_start, sym_end;
+	char *tag = "";
+	
+	memset(buffer, 0, MAX_SYMBOL_SIZE);
+
+	sym_start = 0;
+	if (!kallsyms_address_to_symbol(address, &mod_name, &mod_start, &mod_end, &sec_name, &sec_start, &sec_end, &sym_name, &sym_start, &sym_end)) {
+		tag = "E ";
+		address_to_exported_symbol(address, &mod_name, &sym_name, &sym_start, &sym_end);
+	}
+
+	if (sym_start) {
+		if (mod_name)
+		    snprintf(buffer, MAX_SYMBOL_SIZE - 1, "%s%s+%#x/%#x [%s]",
+			 tag, sym_name,
+			 (unsigned int)(address - sym_start),
+			 (unsigned int)(sym_end - sym_start),
+			 mod_name);
+		else
+		    snprintf(buffer, MAX_SYMBOL_SIZE - 1, "%s%s+%#x/%#x",
+			 tag, sym_name,
+			 (unsigned int)(address - sym_start),
+			 (unsigned int)(sym_end - sym_start));
+		printk(fmt, buffer);
+	} else {
+		printk(fmt, "[unresolved]");
+	}
+	return 0;
+}
+
+#endif
--- linux/Makefile.orig	Wed Sep 25 21:43:13 2002
+++ linux/Makefile	Wed Sep 25 21:46:56 2002
@@ -138,6 +138,7 @@
 MAKEFILES	= $(TOPDIR)/.config
 GENKSYMS	= /sbin/genksyms
 DEPMOD		= /sbin/depmod
+KALLSYMS	= /sbin/kallsyms
 PERL		= perl
 MODFLAGS	= -DMODULE
 CFLAGS_MODULE   = $(MODFLAGS)
@@ -291,32 +292,64 @@
 vmlinux-objs := $(HEAD) $(INIT) $(CORE_FILES) $(LIBS) $(DRIVERS) $(NETWORKS)
 
 quiet_cmd_link_vmlinux = LD      $@
-cmd_link_vmlinux = $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $(HEAD) $(INIT) \
-		--start-group \
-		$(CORE_FILES) \
-		$(LIBS) \
-		$(DRIVERS) \
-		$(NETWORKS) \
-		--end-group \
-		-o vmlinux
+define cmd_link_vmlinux
+	$(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) $(HEAD) $(INIT) \
+	--start-group \
+	$(CORE_FILES) \
+	$(LIBS) \
+	$(DRIVERS) \
+	$(NETWORKS) \
+	--end-group \
+	$(filter $(kallsyms.o),$^) \
+	-o $@
+endef
 
 #	set -e makes the rule exit immediately on error
 
-define rule_link_vmlinux
+define rule_vmlinux
 	set -e
 	echo '  Generating build number'
-	. scripts/mkversion > .tmpversion
-	mv -f .tmpversion .version
+	. scripts/mkversion > .tmp_version
+	mv -f .tmp_version .version
 	+$(MAKE) -C init
 	$(call cmd,link_vmlinux)
 	echo 'cmd_$@ := $(cmd_link_vmlinux)' > $(@D)/.$(@F).cmd
-	$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
+	$(NM) $@ | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
 endef
 
 LDFLAGS_vmlinux += -T arch/$(ARCH)/vmlinux.lds.s
 
-vmlinux: $(vmlinux-objs) arch/$(ARCH)/vmlinux.lds.s FORCE
-	$(call if_changed_rule,link_vmlinux)
+#	Generate section listing all symbols and add it into vmlinux
+
+ifdef CONFIG_KALLSYMS
+
+kallsyms.o := .tmp_kallsyms.o
+
+quiet_cmd_kallsyms = KSYM    $@
+cmd_kallsyms = $(KALLSYMS) $< > $@
+
+.tmp_kallsyms.o: .tmp_vmlinux
+	$(call cmd,kallsyms)
+
+# 	After generating .tmp_vmlinux just like vmlinux, decrement the version
+#	number again, so the final vmlinux gets the same one.
+#	Ignore return value of 'expr'.
+
+define rule_.tmp_vmlinux
+	$(rule_vmlinux)
+	if expr 0`cat .version` - 1 > .tmp_version; then true; fi
+	mv -f .tmp_version .version
+endef
+
+.tmp_vmlinux: $(vmlinux-objs) arch/$(ARCH)/vmlinux.lds.s FORCE
+	$(call if_changed_rule,.tmp_vmlinux)
+
+endif
+
+#	Finally the vmlinux rule
+
+vmlinux: $(vmlinux-objs) $(kallsyms.o) arch/$(ARCH)/vmlinux.lds.s FORCE
+	$(call if_changed_rule,vmlinux)
 
 #	The actual objects are generated when descending, 
 #	make sure no implicit rule kicks in
@@ -820,7 +853,7 @@
 
 # FIXME Should go into a make.lib or something 
 # ===========================================================================
-echo_target = $(RELDIR)/$@
+echo_target = $@
 
 a_flags = -Wp,-MD,$(depfile) $(AFLAGS) $(NOSTDINC_FLAGS) \
 	  $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:04         ` Cort Dougan
@ 2002-09-25 20:14           ` Ingo Molnar
  0 siblings, 0 replies; 23+ messages in thread
From: Ingo Molnar @ 2002-09-25 20:14 UTC (permalink / raw)
  To: Cort Dougan
  Cc: Linus Torvalds, Kai Germaschewski, linux-kernel, Rusty Russell,
	Arjan van de Ven


On Wed, 25 Sep 2002, Cort Dougan wrote:

> How does this change differ from the one I sent a month ago?

kallsyms/kksymoops existed for quite some time already, and there are a
couple of additional things it does:

 - it includes and uses the full symbol table, not just the module 
   symbols. (hence the 'all' in KALLSYMS)

 - as far as i can see your patch did not extend to show_stack()?

 - kksymoops prints a module list as well.

	Ingo


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:52           ` Linus Torvalds
  2002-09-25 20:04             ` Ingo Molnar
@ 2002-09-25 20:31             ` Jeff Garzik
  1 sibling, 0 replies; 23+ messages in thread
From: Jeff Garzik @ 2002-09-25 20:31 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Ingo Molnar, Kai Germaschewski, linux-kernel, Rusty Russell,
	Arjan van de Ven

Linus Torvalds wrote:
> In fact, there _cannot_ be any these days, since all recent kernrels have 
> stopped using defconfig entirely, and favour using /etc/kernel-config 
> instead (making it much easier to have per-machine default 
> configurations).


wow, cool... I missed that.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:56       ` Ingo Molnar
@ 2002-09-25 22:04         ` J.A. Magallon
  2002-09-27 20:48           ` Bill Davidsen
  2002-09-26 17:16         ` Ruth Ivimey-Cook
  1 sibling, 1 reply; 23+ messages in thread
From: J.A. Magallon @ 2002-09-25 22:04 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Linus Torvalds, Kai Germaschewski, linux-kernel, Rusty Russell,
	Arjan van de Ven


On 2002.09.25 Ingo Molnar wrote:
>
>okay, here is the new oops output:
>

Sorry to be picky, but...

>------------[ cut here ]------------
>kernel BUG at time.c:99!
>invalid operand: 0000
>CPU:    1
>EIP:    0060:[<c011bd14>]    Not tainted
>EFLAGS: 00010246
>EIP is at sys_gettimeofday+0x84/0x90
>eax: 0000004e   ebx: cef9e000   ecx: 00000000   edx: 00000068
>esi: 00000000   edi: 00000000   ebp: bffffad8   esp: cef9ffa0
>ds: 0068   es: 0068   ss: 0068
>Process gettimeofday (pid: 549, threadinfo=cef9e000 task=cf84d860)
>Stack: 4001695c bffff414 40156154 00000004 c0112a40 cef9e000 400168e4 bffffb44
>       c0107973 00000000 00000000 40156154 400168e4 bffffb44 bffffad8 0000004e
>       0000002b 0000002b 0000004e 400cecc1 00000023 00000246 bffffacc 0000002b
>Call Trace: [<c0112a40>] do_page_fault+0x0/0x4a2
>[<c0107973>] syscall_call+0x7/0xb
>

...wouldn't this look much nicer with some '\n' and a couple space for indent ?

Stack:
  4001695c bffff414 40156154 00000004 c0112a40 cef9e000 400168e4 bffffb44
  c0107973 00000000 00000000 40156154 400168e4 bffffb44 bffffad8 0000004e
  0000002b 0000002b 0000004e 400cecc1 00000023 00000246 bffffacc 0000002b
Call Trace:
  [<c0112a40>] do_page_fault+0x0/0x4a2
  [<c0107973>] syscall_call+0x7/0xb


-- 
J.A. Magallon <jamagallon@able.es>      \                 Software is like sex:
werewolf.able.es                         \           It's better when it's free
Mandrake Linux release 9.0 (Cooker) for i586
Linux 2.4.20-pre7-jam0 (gcc 3.2 (Mandrake Linux 9.0 3.2-1mdk))

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 19:56       ` Ingo Molnar
  2002-09-25 22:04         ` J.A. Magallon
@ 2002-09-26 17:16         ` Ruth Ivimey-Cook
  1 sibling, 0 replies; 23+ messages in thread
From: Ruth Ivimey-Cook @ 2002-09-26 17:16 UTC (permalink / raw)
  To: Ingo Molnar, Linus Torvalds
  Cc: Kai Germaschewski, linux-kernel, Rusty Russell, Arjan van de Ven

On Wednesday 25 September 2002 20:56, Ingo Molnar wrote:
> ------------[ cut here ]------------
> kernel BUG at time.c:99!
> invalid operand: 0000
> CPU:    1
> EIP:    0060:[<c011bd14>]    Not tainted
> EFLAGS: 00010246
> EIP is at sys_gettimeofday+0x84/0x90
> eax: 0000004e   ebx: cef9e000   ecx: 00000000   edx: 00000068
> esi: 00000000   edi: 00000000   ebp: bffffad8   esp: cef9ffa0
> ds: 0068   es: 0068   ss: 0068
> Process gettimeofday (pid: 549, threadinfo=cef9e000 task=cf84d860)
> Stack: 4001695c bffff414 40156154 00000004 c0112a40 cef9e000 400168e4

Something that's been bugging me of late: the Oops output is quite expensive 
in lines on the terminal, which means if you get a couple of oops before the 
kernel stops, you're unlikely to see the one that fired first.

To help with this, would it be good to use the following form for the initial 
part:

 kernel BUG at time.c:99, invalid operand: 0000
 CPU 1: EIP:    0060:[<c011bd14>]    Not tainted
 EIP is at sys_gettimeofday+0x84/0x90
 eax: 0000004e   ebx: cef9e000   ecx: 00000000   edx: 00000068
 esi: 00000000   edi: 00000000   ebp: bffffad8   esp: cef9ffa0
 ds: 0068   es: 0068   ss: 0068   eflags: 00010246 [textflags]

Where [textflags] is some arch-specific representation of the flags word.

Also, in the same vein I would like to be able to say (as a kernel option):

if kernel-oops {
 copy console output to [printer|serial] port
}

[printer output == ascii only, of course]

Regards,

Ruth

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-25 22:04         ` J.A. Magallon
@ 2002-09-27 20:48           ` Bill Davidsen
  2002-09-27 21:13             ` Ingo Molnar
  0 siblings, 1 reply; 23+ messages in thread
From: Bill Davidsen @ 2002-09-27 20:48 UTC (permalink / raw)
  To: J.A. Magallon
  Cc: Ingo Molnar, Linus Torvalds, Kai Germaschewski, linux-kernel,
	Rusty Russell, Arjan van de Ven

On Thu, 26 Sep 2002, J.A. Magallon wrote:

> Sorry to be picky, but...

> ...wouldn't this look much nicer with some '\n' and a couple space for indent ?
> 
> Stack:
>   4001695c bffff414 40156154 00000004 c0112a40 cef9e000 400168e4 bffffb44
>   c0107973 00000000 00000000 40156154 400168e4 bffffb44 bffffad8 0000004e
>   0000002b 0000002b 0000004e 400cecc1 00000023 00000246 bffffacc 0000002b
> Call Trace:
>   [<c0112a40>] do_page_fault+0x0/0x4a2
>   [<c0107973>] syscall_call+0x7/0xb

You mean like making it human readable? ;-)

I think that's a great idea.

-- 
bill davidsen <davidsen@tmr.com>
  CTO, TMR Associates, Inc
Doing interesting things with little computers since 1979.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-27 20:48           ` Bill Davidsen
@ 2002-09-27 21:13             ` Ingo Molnar
  2002-09-27 23:58               ` J.A. Magallon
  0 siblings, 1 reply; 23+ messages in thread
From: Ingo Molnar @ 2002-09-27 21:13 UTC (permalink / raw)
  To: Bill Davidsen
  Cc: J.A. Magallon, Linus Torvalds, Kai Germaschewski, linux-kernel,
	Rusty Russell, Arjan van de Ven


> > Call Trace:
> >   [<c0112a40>] do_page_fault+0x0/0x4a2
> >   [<c0107973>] syscall_call+0x7/0xb

> I think that's a great idea.

it's already in the kksymoops patch that Linus applied two days ago.

	Ingo


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0
  2002-09-27 21:13             ` Ingo Molnar
@ 2002-09-27 23:58               ` J.A. Magallon
  0 siblings, 0 replies; 23+ messages in thread
From: J.A. Magallon @ 2002-09-27 23:58 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Bill Davidsen, J.A. Magallon, Linus Torvalds, Kai Germaschewski,
	linux-kernel, Rusty Russell, Arjan van de Ven


On 2002.09.27 Ingo Molnar wrote:
>
>> > Call Trace:
>> >   [<c0112a40>] do_page_fault+0x0/0x4a2
>> >   [<c0107973>] syscall_call+0x7/0xb
>
>> I think that's a great idea.
>
>it's already in the kksymoops patch that Linus applied two days ago.
>

Any version of this for 2.4 ? I think this is going to be very, very usefull,
so it is interesting to have it on 2.4...

-- 
J.A. Magallon <jamagallon@able.es>      \                 Software is like sex:
werewolf.able.es                         \           It's better when it's free
Mandrake Linux release 9.0 (Cooker) for i586
Linux 2.4.20-pre8-jam0 (gcc 3.2 (Mandrake Linux 9.0 3.2-1mdk))

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2002-09-27 23:56 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-25  9:02 [ANNOUNCE] [patch] kksymoops, in-kernel symbolic oopser, 2.5.38-B0 Ingo Molnar
2002-09-25  9:32 ` [re-ANNOUNCE] " Ingo Molnar
2002-09-25  9:51   ` Arnaldo Carvalho de Melo
2002-09-25 18:16 ` [ANNOUNCE] " Linus Torvalds
2002-09-25 19:23   ` Kai Germaschewski
2002-09-25 19:42     ` Ingo Molnar
2002-09-25 19:41       ` Kai Germaschewski
2002-09-25 19:46       ` Linus Torvalds
2002-09-25 19:54         ` Ingo Molnar
2002-09-25 19:52           ` Linus Torvalds
2002-09-25 20:04             ` Ingo Molnar
2002-09-25 20:31             ` Jeff Garzik
2002-09-25 19:55           ` Kai Germaschewski
2002-09-25 19:45     ` Linus Torvalds
2002-09-25 19:53       ` Ingo Molnar
2002-09-25 19:04         ` Cort Dougan
2002-09-25 20:14           ` Ingo Molnar
2002-09-25 19:56       ` Ingo Molnar
2002-09-25 22:04         ` J.A. Magallon
2002-09-27 20:48           ` Bill Davidsen
2002-09-27 21:13             ` Ingo Molnar
2002-09-27 23:58               ` J.A. Magallon
2002-09-26 17:16         ` Ruth Ivimey-Cook

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).