linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch] kksymoops-2.5.38-C9
@ 2002-09-26 14:01 Ingo Molnar
  2002-09-26 14:36 ` Kai Germaschewski
  2002-10-02 11:16 ` Gianni Tedesco
  0 siblings, 2 replies; 3+ messages in thread
From: Ingo Molnar @ 2002-09-26 14:01 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Kai Germaschewski, linux-kernel


in the attached kksymoops patch (against BK-curr) has the following fixes
over yesterday's version:

- i've tidied up the backtrace part of the oops output a bit, properly
  whitespaced backtrace, no superfluous newlines, etc.

- i've also removed the 'int' return type of print_symbol(), it's always 0
  and nothing uses it anymore.

- made the no-kksymoops output compatible with userspace ksymoops again.

- no-kksymoops but modules-enabled oopses do not contain the superfluous 
  [unresolved] name after every address.

the kksymoops-enabled modules-disabled oops output is:

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

Code: 0f 0b 64 00 6d d7 26 c0 eb b6 89 f6 83 ec 0c 89 5c 24 04 8b
<-------

the kksymoops-disabled, modules-disabled raw output:

------->
kernel BUG at time.c:100!
invalid operand: 0000
CPU:    0
EIP:    0060:[<c011be44>]    Not tainted
EFLAGS: 00010246
eax: 0000004e   ebx: cee22000   ecx: 00000000   edx: 00000068
esi: 00000000   edi: 00000000   ebp: bffffad8   esp: cee23fa0
ds: 0068   es: 0068   ss: 0068
Process gettimeofday (pid: 569, threadinfo=cee22000 task=cf7911a0)
Stack: 4001695c bffff414 40156154 00000004 c0112ae0 cee22000 400168e4 bffffb44
       c0107963 00000000 00000000 40156154 400168e4 bffffb44 bffffad8 0000004e
       0000002b 0000002b 0000004e 400cecc1 00000023 00000246 bffffacc 0000002b
Call Trace: [<c0112ae0>] [<c0107963>]

Code: 0f 0b 64 00 6d d7 26 c0 eb b6 89 f6 83 ec 0c 89 5c 24 04 8b
<-------

userspace ksymoops can interpret and decode the raw oops just fine:

------->
Call Trace: [<c0112ae0>] [<c0107963>]

>>EIP; c011be44 <sys_gettimeofday+84/90>   <=====
Trace; c0112ae0 <do_page_fault+0/49e>
Trace; c0107963 <syscall_call+7/b>
Code;  c011be44 <sys_gettimeofday+84/90>
<-------

kksymoops-disabled, modules-enabled output:

--------->
kernel BUG at time.c:100!
invalid operand: 0000

CPU:    1
EIP:    0060:[<c011ddd4>]    Not tainted
EFLAGS: 00010246
eax: 0000004e   ebx: cf0fe000   ecx: 00000000   edx: 00000068
esi: 00000000   edi: 00000000   ebp: bffffad8   esp: cf0fffa0
ds: 0068   es: 0068   ss: 0068
Process gettimeofday (pid: 569, threadinfo=cf0fe000 task=cf418060)
Stack: 4001695c bffff414 40156154 00000004 c0112b50 cf0fe000 400168e4 bffffb44
       c0107973 00000000 00000000 40156154 400168e4 bffffb44 bffffad8 0000004e
       0000002b 0000002b 0000004e 400cecc1 00000023 00000246 bffffacc 0000002b
Call Trace: [<c0112b50>] [<c0107973>]
Code: 0f 0b 64 00 8d 06 27 c0 eb b6 89 f6 83 ec 0c 89 5c 24 04 8b
<---------

this too is userspace-ksymoops compatible. All the oops variants work fine
and look reasonable.

	Ingo

--- linux/arch/i386/kernel/head.S.orig	Fri Sep 20 17:20:16 2002
+++ linux/arch/i386/kernel/head.S	Thu Sep 26 15:27:12 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	Thu Sep 26 15:27:12 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	Thu Sep 26 15:48:42 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)
@@ -137,15 +136,16 @@
 	if (!stack)
 		stack = (unsigned long*)&stack;
 
-	printk("Call Trace: ");
+	printk("Call Trace:");
+#if CONFIG_KALLSYMS
+	printk("\n");
+#endif
 	i = 1;
 	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++;
+			printk(" [<%08lx>]", addr);
+			print_symbol("%s\n", addr);
 		}
 	}
 	printk("\n");
@@ -206,8 +206,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",
@@ -225,7 +228,7 @@
 		printk("\nStack: ");
 		show_stack((unsigned long*)esp);
 
-		printk("\nCode: ");
+		printk("Code: ");
 		if(regs->eip < PAGE_OFFSET)
 			goto bad;
 
@@ -268,6 +271,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	Thu Sep 26 15:27:16 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	Thu Sep 26 15:26:53 2002
+++ linux/arch/i386/config.in	Thu Sep 26 15:27:16 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	Thu Sep 26 15:27:16 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	Thu Sep 26 15:27:16 2002
+++ linux/include/linux/kallsyms.h	Thu Sep 26 15:27:16 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	Thu Sep 26 15:31:15 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 void 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	Thu Sep 26 15:26:53 2002
+++ linux/include/linux/sched.h	Thu Sep 26 15:27:16 2002
@@ -152,7 +152,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	Thu Sep 26 15:27:16 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	Thu Sep 26 15:27:16 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	Thu Sep 26 15:27:16 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	Thu Sep 26 15:27:16 2002
+++ linux/kernel/kallsyms.c	Thu Sep 26 15:27:16 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	Thu Sep 26 15:55:34 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,81 @@
 	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;
+			}
+	}
+}
+
+void
+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);
+	}
+#if 0
+ else {
+		printk(fmt, "[unresolved]");
+	}
+#endif
+}
+
+#endif
--- linux/Makefile.orig	Thu Sep 26 15:26:53 2002
+++ linux/Makefile	Thu Sep 26 15:27:16 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] 3+ messages in thread

* Re: [patch] kksymoops-2.5.38-C9
  2002-09-26 14:01 [patch] kksymoops-2.5.38-C9 Ingo Molnar
@ 2002-09-26 14:36 ` Kai Germaschewski
  2002-10-02 11:16 ` Gianni Tedesco
  1 sibling, 0 replies; 3+ messages in thread
From: Kai Germaschewski @ 2002-09-26 14:36 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: Linus Torvalds, linux-kernel

On Thu, 26 Sep 2002, Ingo Molnar wrote:

> in the attached kksymoops patch (against BK-curr) has the following fixes
> over yesterday's version:

I know this seems to be a never ending story to get exactly right, but 
anyway, more comments.

> kksymoops-disabled, modules-enabled output:
> 
> --------->
> kernel BUG at time.c:100!
> invalid operand: 0000
> 
> CPU:    1
> EIP:    0060:[<c011ddd4>]    Not tainted
> EFLAGS: 00010246
> eax: 0000004e   ebx: cf0fe000   ecx: 00000000   edx: 00000068
> esi: 00000000   edi: 00000000   ebp: bffffad8   esp: cf0fffa0
> ds: 0068   es: 0068   ss: 0068
> Process gettimeofday (pid: 569, threadinfo=cf0fe000 task=cf418060)
> Stack: 4001695c bffff414 40156154 00000004 c0112b50 cf0fe000 400168e4 bffffb44
>        c0107973 00000000 00000000 40156154 400168e4 bffffb44 bffffad8 0000004e
>        0000002b 0000002b 0000004e 400cecc1 00000023 00000246 bffffacc 0000002b
> Call Trace: [<c0112b50>] [<c0107973>]

Actually, in this case I would have expected to get the symbols resolved
using the exported symbols the kernel knows anyway. I can see two possible
explanations for that not happening: The addresses are lower than the
first exported symbol (look in /proc/ksyms to check), or (more likely)
there is still a bug in the address_to_exported_symbol() function.

I wondered initially, if it even makes any sense to use exported symbols 
only for resolving an address, but it actually is useful in the case of 
modules. For one reason, it actually names the module which the crash 
occured in, and given the module it also allows to actually find out where 
exactly the problem happened, which you normally cannot do, since you do 
not know which address the module was loaded at.

> @@ -137,15 +136,16 @@
>  	if (!stack)
>  		stack = (unsigned long*)&stack;
>  
> -	printk("Call Trace: ");
> +	printk("Call Trace:");
> +#if CONFIG_KALLSYMS

I think this should be || CONFIG_MODULES (see above)

> +	printk("\n");
> +#endif
>  	i = 1;
>  	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++;
> +			printk(" [<%08lx>]", addr);
> +			print_symbol("%s\n", addr);
>  		}
>  	}
>  	printk("\n");

This will produce rather ugly output when the call trace is longer than
what fits in one line, since no one is adding "\n" then at all.

(This can be done with an ifdef, to avoid it I used the return value of
print_symbol() before, which is not really all that nice, either).
Maybe it's better to bite the bullet, use one #ifdef and get both cases 
separate, even if that's a slight duplication of code. (Oh, and I think 
most code uses #ifdef not #if, though of course both works the same)


> --- linux/include/linux/module.h.orig	Fri Sep 20 17:20:32 2002
> +++ linux/include/linux/module.h	Thu Sep 26 15:31:15 2002

> +extern void 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 */

You missed converting the return value of the inline variant.


--Kai





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

* Re: [patch] kksymoops-2.5.38-C9
  2002-09-26 14:01 [patch] kksymoops-2.5.38-C9 Ingo Molnar
  2002-09-26 14:36 ` Kai Germaschewski
@ 2002-10-02 11:16 ` Gianni Tedesco
  1 sibling, 0 replies; 3+ messages in thread
From: Gianni Tedesco @ 2002-10-02 11:16 UTC (permalink / raw)
  To: Ingo Molnar; +Cc: Linus Torvalds, Kai Germaschewski, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1109 bytes --]

On Thu, 2002-09-26 at 15:01, Ingo Molnar wrote:
> --- linux/Makefile.orig	Thu Sep 26 15:26:53 2002
> +++ linux/Makefile	Thu Sep 26 15:27:16 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)

Ingo, this breaks cross compiles because kallsyms expects a host
executable:

$ /sbin/kallsyms .tmp_vmlinux > .tmp_kallsyms.o
.tmp_vmlinux: ELF file .tmp_vmlinux not for this architecture

You can't even do $(CROSS_COMPILE)kallsyms because that isn't part of
most peoples toolchains. (and /sbin might not be in the $PATH).

I'm not sure what kallsyms does *exactly* but it sounds like the same
functionality can be had from objcopy...

-- 
// Gianni Tedesco (gianni at ecsc dot co dot uk)
lynx --source www.scaramanga.co.uk/gianni-at-ecsc.asc | gpg --import
8646BE7D: 6D9F 2287 870E A2C9 8F60 3A3C 91B5 7669 8646 BE7D

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 232 bytes --]

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

end of thread, other threads:[~2002-10-02 11:10 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-26 14:01 [patch] kksymoops-2.5.38-C9 Ingo Molnar
2002-09-26 14:36 ` Kai Germaschewski
2002-10-02 11:16 ` Gianni Tedesco

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).