Re: [PATCH] Module loader against 2.5.46: 9/9

Rusty Russell (rusty@rustcorp.com.au)
Tue, 05 Nov 2002 11:47:27 +1100


Since I believe kallsyms is important, this reimplements it sanely,
using the current module infrastructure, and not using an external
kallsyms script.

FYI, the previous interface was:

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 */
);

The new one is:
/* Lookup an address. modname is set to NULL if it's in the kernel. */
const char *kallsyms_lookup(unsigned long addr,
unsigned long *symbolsize,
unsigned long *offset,
char **modname);

Rusty.

Name: kallsyms support
Author: Rusty Russell
Status: Documentation
Depends: Module/param-oldstyle.patch.gz

D: Reintroduces kallsyms support.

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/Makefile .7287-linux-2.5.46.updated/Makefile
--- .7287-linux-2.5.46/Makefile 2002-11-05 11:12:39.000000000 +1100
+++ .7287-linux-2.5.46.updated/Makefile 2002-11-05 11:13:10.000000000 +1100
@@ -157,7 +157,7 @@ OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
AWK = awk
GENKSYMS = /sbin/genksyms
-KALLSYMS = /sbin/kallsyms
+KALLSYMS = scripts/kallsyms
PERL = perl
MODFLAGS = -DMODULE
CFLAGS_MODULE = $(MODFLAGS)
@@ -335,7 +335,7 @@ ifdef CONFIG_KALLSYMS
kallsyms.o := .tmp_kallsyms2.o

quiet_cmd_kallsyms = KSYM $@
-cmd_kallsyms = $(KALLSYMS) $< > $@
+cmd_kallsyms = sh $(KALLSYMS) $< $@

.tmp_kallsyms1.o: .tmp_vmlinux1
$(call cmd,kallsyms)
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/arch/i386/Kconfig .7287-linux-2.5.46.updated/arch/i386/Kconfig
--- .7287-linux-2.5.46/arch/i386/Kconfig 2002-11-05 11:12:39.000000000 +1100
+++ .7287-linux-2.5.46.updated/arch/i386/Kconfig 2002-11-05 11:13:10.000000000 +1100
@@ -1605,14 +1605,13 @@ config DEBUG_HIGHMEM
This options enables addition error checking for high memory systems.
Disable for production systems.

-# Reimplemented RSN.
-#config KALLSYMS
-# bool "Load all symbols for debugging/kksymoops"
-# depends on DEBUG_KERNEL
-# help
-# 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 KALLSYMS
+ bool "Load all symbols for debugging/kksymoops"
+ depends on DEBUG_KERNEL
+ help
+ 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 X86_EXTRA_IRQS
bool
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/arch/ia64/Kconfig .7287-linux-2.5.46.updated/arch/ia64/Kconfig
--- .7287-linux-2.5.46/arch/ia64/Kconfig 2002-11-05 11:12:39.000000000 +1100
+++ .7287-linux-2.5.46.updated/arch/ia64/Kconfig 2002-11-05 11:13:10.000000000 +1100
@@ -813,13 +813,13 @@ config DEBUG_KERNEL
Say Y here if you are developing drivers or trying to debug and
identify kernel problems.

-# config KALLSYMS
-# bool "Load all symbols for debugging/kksymoops"
-# depends on DEBUG_KERNEL
-# help
-# 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 KALLSYMS
+ bool "Load all symbols for debugging/kksymoops"
+ depends on DEBUG_KERNEL
+ help
+ 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 IA64_PRINT_HAZARDS
bool "Print possible IA-64 dependency violations to console"
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/arch/ppc/Kconfig .7287-linux-2.5.46.updated/arch/ppc/Kconfig
--- .7287-linux-2.5.46/arch/ppc/Kconfig 2002-11-05 11:12:39.000000000 +1100
+++ .7287-linux-2.5.46.updated/arch/ppc/Kconfig 2002-11-05 11:13:10.000000000 +1100
@@ -1784,9 +1784,9 @@ config DEBUG_HIGHMEM
bool "Highmem debugging"
depends on DEBUG_KERNEL && HIGHMEM

-# config KALLSYMS
-# bool "Load all symbols for debugging/kksymoops"
-# depends on DEBUG_KERNEL
+config KALLSYMS
+ bool "Load all symbols for debugging/kksymoops"
+ depends on DEBUG_KERNEL

config KGDB
bool "Include kgdb kernel debugger"
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/arch/ppc/kernel/process.c .7287-linux-2.5.46.updated/arch/ppc/kernel/process.c
--- .7287-linux-2.5.46/arch/ppc/kernel/process.c 2002-10-15 15:30:52.000000000 +1000
+++ .7287-linux-2.5.46.updated/arch/ppc/kernel/process.c 2002-11-05 11:13:10.000000000 +1100
@@ -34,6 +34,7 @@
#include <linux/prctl.h>
#include <linux/init_task.h>
#include <linux/module.h>
+#include <linux/kallsyms.h>

#include <asm/pgtable.h>
#include <asm/uaccess.h>
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/arch/x86_64/Kconfig .7287-linux-2.5.46.updated/arch/x86_64/Kconfig
--- .7287-linux-2.5.46/arch/x86_64/Kconfig 2002-11-05 11:12:39.000000000 +1100
+++ .7287-linux-2.5.46.updated/arch/x86_64/Kconfig 2002-11-05 11:13:10.000000000 +1100
@@ -739,13 +739,13 @@ config INIT_DEBUG
help
Fill __init and __initdata at the end of boot. This is only for debugging.

-# config KALLSYMS
-# bool "Load all symbols for debugging/kksymoops"
-# depends on DEBUG_KERNEL
-# help
-# 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 KALLSYMS
+ bool "Load all symbols for debugging/kksymoops"
+ depends on DEBUG_KERNEL
+ help
+ 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.

endmenu

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/fs/proc/base.c .7287-linux-2.5.46.updated/fs/proc/base.c
--- .7287-linux-2.5.46/fs/proc/base.c 2002-11-05 10:54:27.000000000 +1100
+++ .7287-linux-2.5.46.updated/fs/proc/base.c 2002-11-05 11:13:10.000000000 +1100
@@ -257,20 +257,18 @@ out:
*/
static int proc_pid_wchan(struct task_struct *task, char *buffer)
{
- const char *sym_name, *ignore;
- unsigned long wchan, dummy;
+ char *modname;
+ const char *sym_name;
+ unsigned long wchan, size, offset;

wchan = get_wchan(task);

- if (!kallsyms_address_to_symbol(wchan, &ignore, &dummy, &dummy,
- &ignore, &dummy, &dummy, &sym_name,
- &dummy, &dummy)) {
- return sprintf(buffer, "%lu", wchan);
- }
-
- return sprintf(buffer, "%s", sym_name);
+ sym_name = kallsyms_lookup(wchan, &size, &offset, &modname);
+ if (sym_name)
+ return sprintf(buffer, "%s", sym_name);
+ return sprintf(buffer, "%lu", wchan);
}
-#endif
+#endif /* CONFIG_KALLSYMS */

/************************************************************************/
/* Here the fs part begins */
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/include/linux/kallsyms.h .7287-linux-2.5.46.updated/include/linux/kallsyms.h
--- .7287-linux-2.5.46/include/linux/kallsyms.h 2002-10-15 15:19:44.000000000 +1000
+++ .7287-linux-2.5.46.updated/include/linux/kallsyms.h 2002-11-05 11:13:11.000000000 +1100
@@ -1,163 +1,47 @@
-/* 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.
+/* Rewritten and vastly simplified by Rusty Russell for in-kernel
+ * module loader:
+ * Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
*/
+#ifndef _LINUX_KALLSYMS_H
+#define _LINUX_KALLSYMS_H

-#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))
+#include <linux/config.h>

#ifdef CONFIG_KALLSYMS
+/* Lookup an address. modname is set to NULL if it's in the kernel. */
+const char *kallsyms_lookup(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset,
+ char **modname);

-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 */
- );
+/* Replace "%s" in format with address, if found */
+extern void __print_symbol(const char *fmt, unsigned long address);

-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 */
- );
+#else /* !CONFIG_KALLSYMS */

-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 */
- )
- );
+static inline const char *kallsyms_lookup(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset,
+ char **modname)
+{
+ return NULL;
+}

-#else
+/* Stupid that this does nothing, but I didn't create this mess. */
+#define __print_symbol(fmt, addr)
+#endif /*CONFIG_KALLSYMS*/

-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 */
- )
+/* This macro allows us to keep printk typechecking */
+static void __check_printsym_format(const char *fmt, ...)
+__attribute__((format(printf,1,2)));
+static inline void __check_printsym_format(const char *fmt, ...)
{
- return -ESRCH;
}

-#endif
+#define print_symbol(fmt, addr) \
+do { \
+ __check_printsym_format(fmt, ""); \
+ __print_symbol(fmt, addr); \
+} while(0)

-#endif /* kallsyms.h */
+#endif /*_LINUX_KALLSYMS_H*/
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/include/linux/module.h .7287-linux-2.5.46.updated/include/linux/module.h
--- .7287-linux-2.5.46/include/linux/module.h 2002-11-05 11:12:43.000000000 +1100
+++ .7287-linux-2.5.46.updated/include/linux/module.h 2002-11-05 11:13:11.000000000 +1100
@@ -27,8 +27,6 @@
#define MODULE_GENERIC_TABLE(gtype,name)
#define MODULE_DEVICE_TABLE(type,name)
#define MODULE_PARM_DESC(var,desc)
-#define print_symbol(format, addr)
-#define print_modules()

#define MODULE_NAME_LEN (64 - sizeof(unsigned long))
struct kernel_symbol
@@ -136,6 +134,13 @@ struct module
void (*exit)(void);
#endif

+#ifdef CONFIG_KALLSYMS
+ /* We keep the symbol and string tables for kallsyms. */
+ Elf_Sym *symtab;
+ unsigned long num_syms;
+ char *strtab;
+#endif
+
/* The command line arguments (may be mangled). People like
keeping pointers to this stuff */
char args[0];
@@ -248,6 +253,12 @@ do { \
} \
} while(0)

+/* For kallsyms to ask for address resolution. NULL means not found. */
+const char *module_address_lookup(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset,
+ char **modname);
+
#else /* !CONFIG_MODULES... */
#define EXPORT_SYMBOL(sym)
#define EXPORT_SYMBOL_GPL(sym)
@@ -261,6 +272,15 @@ do { \
#define module_put(module) do { } while(0)

#define __unsafe(mod)
+
+/* For kallsyms to ask for address resolution. NULL means not found. */
+static inline const char *module_address_lookup(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset,
+ char **modname)
+{
+ return NULL;
+}
#endif /* CONFIG_MODULES */

/* For archs to search exception tables */
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/kernel/Makefile .7287-linux-2.5.46.updated/kernel/Makefile
--- .7287-linux-2.5.46/kernel/Makefile 2002-11-05 11:12:41.000000000 +1100
+++ .7287-linux-2.5.46.updated/kernel/Makefile 2002-11-05 11:14:07.000000000 +1100
@@ -4,7 +4,7 @@

export-objs = signal.o sys.o kmod.o workqueue.o ksyms.o pm.o exec_domain.o \
printk.o platform.o suspend.o dma.o module.o cpufreq.o \
- profile.o rcupdate.o intermodule.o params.o
+ profile.o rcupdate.o intermodule.o params.o kallsyms.o

obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
exit.o itimer.o time.o softirq.o resource.o \
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/kernel/kallsyms.c .7287-linux-2.5.46.updated/kernel/kallsyms.c
--- .7287-linux-2.5.46/kernel/kallsyms.c 2002-10-15 15:30:05.000000000 +1000
+++ .7287-linux-2.5.46.updated/kernel/kallsyms.c 2002-11-05 11:13:11.000000000 +1100
@@ -1,233 +1,105 @@
/*
- * 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>
+ * kallsyms.c: in-kernel printing of symbolic oopses and stack traces.
*
- This code uses the list of all kernel and module symbols to :-
+ * Rewritten and vastly simplified by Rusty Russell for in-kernel
+ * module loader:
+ * Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ */
+#include <linux/kallsyms.h>
+#include <linux/module.h>

- * Find any non-stack symbol in a kernel or module. Symbols do
- not have to be exported for debugging.
+static char kallsyms_dummy;

- * 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.
+/* These get overridden when the real kallsyms.o is linked in. */
+extern unsigned long kallsyms_addresses[1]
+ __attribute__((alias("kallsyms_dummy"), weak));
+extern unsigned long kallsyms_num_syms
+ __attribute__((alias("kallsyms_dummy"), weak));
+extern char kallsyms_names[1]
+ __attribute__((alias("kallsyms_dummy"), weak));

- */
+/* Defined by the linker script. */
+extern char _stext[], _etext[];

-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
+/* Lookup an address. modname is set to NULL if it's in the kernel. */
+const char *kallsyms_lookup(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset,
+ char **modname)
+{
+ unsigned long i, best = 0;

-/* 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.
- */
+ /* This kernel should never had been booted. */
+ if ((void *)kallsyms_addresses == &kallsyms_dummy)
+ BUG();

-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;
+ if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) {
+ unsigned long symbol_end;
+ char *name = kallsyms_names;

- /* Restart? */
- m = module_list;
- if (token && *token) {
- for (; m; m = m->next)
- if ((unsigned long)m == *token)
- break;
- if (m)
- m = m->next;
- }
+ /* They're sorted, we could be clever here, but who cares? */
+ for (i = 0; i < kallsyms_num_syms; i++) {
+ if (kallsyms_addresses[i] > kallsyms_addresses[best] &&
+ kallsyms_addresses[i] <= addr)
+ best = i;
+ }

- 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)
+ /* Grab name */
+ for (i = 0; i < best; i++)
+ name += strlen(name)+1;
+
+ /* Base symbol size on next symbol, but beware aliases. */
+ symbol_end = (unsigned long)_etext;
+ for (i = best+1; i < kallsyms_num_syms; i++) {
+ if (kallsyms_addresses[i] != kallsyms_addresses[best]){
+ symbol_end = kallsyms_addresses[i];
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;
+ *symbolsize = symbol_end - kallsyms_addresses[best];
+ *modname = NULL;
+ *offset = addr - kallsyms_addresses[best];
+ return name;
}
- else
- *sym_end = *sec_end;
- return(1);
+
+ return module_address_lookup(addr, symbolsize, offset, modname);
}

-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 */
- )
+/* Replace "%s" in format with address, or returns -errno. */
+void __print_symbol(const char *fmt, unsigned long address)
{
- 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 */
- }
+ char *modname;
+ const char *name;
+ unsigned long offset, size;

- if (!m)
- return(0); /* not found */
+ name = kallsyms_lookup(address, &size, &offset, &modname);

- 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;
+ if (!name) {
+ char addrstr[sizeof("0x%lx") + (BITS_PER_LONG*3/10)];

- 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;
+ sprintf(addrstr, "0x%lx", address);
+ printk(fmt, addrstr);
+ return;
}
- 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;
+ if (modname) {
+ /* This is pretty small. */
+ char buffer[sizeof("%s+%#lx/%#lx [%s]")
+ + strlen(name) + 2*(BITS_PER_LONG*3/10)
+ + strlen(modname)];

- 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);
- }
+ sprintf(buffer, "%s+%#lx/%#lx [%s]",
+ name, offset, size, modname);
+ printk(fmt, buffer);
+ } else {
+ char buffer[sizeof("%s+%#lx/%#lx")
+ + strlen(name) + 2*(BITS_PER_LONG*3/10)];
+
+ sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
+ printk(fmt, buffer);
}
- return(1);
}

-/* Allocate the __kallsyms section, so it's already present in
- * the temporary vmlinux that kallsyms is run on, so the first
- * run will pick up the section info already. */
-
-__asm__(".section __kallsyms,\"a\"\n.previous");
+EXPORT_SYMBOL(kallsyms_lookup);
+EXPORT_SYMBOL(__print_symbol);
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/kernel/module.c .7287-linux-2.5.46.updated/kernel/module.c
--- .7287-linux-2.5.46/kernel/module.c 2002-11-05 11:12:43.000000000 +1100
+++ .7287-linux-2.5.46.updated/kernel/module.c 2002-11-05 11:13:11.000000000 +1100
@@ -1026,6 +1026,11 @@ static struct module *load_module(void *
DEBUGP("Obsolete param found in section %u\n", i);
obsparmindex = i;
}
+#ifdef CONFIG_KALLSYMS
+ /* symbol and string tables for decoding later. */
+ if (sechdrs[i].sh_type == SHT_SYMTAB || i == hdr->e_shstrndx)
+ sechdrs[i].sh_flags |= SHF_ALLOC;
+#endif
#ifndef CONFIG_MODULE_UNLOAD
/* Don't load .exit sections */
if (strstr(secstrings+sechdrs[i].sh_name, ".exit"))
@@ -1138,6 +1143,11 @@ static struct module *load_module(void *
goto cleanup;
}

+#ifdef CONFIG_KALLSYMS
+ mod->symtab = (void *)sechdrs[symindex].sh_offset;
+ mod->num_syms = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
+ mod->strtab = (void *)sechdrs[strindex].sh_offset;
+#endif
err = module_finalize(hdr, sechdrs, mod);
if (err < 0)
goto cleanup;
@@ -1252,9 +1262,82 @@ sys_init_module(void *umod,
return 0;
}

-/* Called by the /proc file system to return a current list of
- modules. Al Viro came up with this interface as an "improvement".
- God save us from any more such interface improvements. */
+#ifdef CONFIG_KALLSYMS
+static inline int inside_init(struct module *mod, unsigned long addr)
+{
+ if (mod->module_init
+ && (unsigned long)mod->module_init <= addr
+ && (unsigned long)mod->module_init + mod->init_size > addr)
+ return 1;
+ return 0;
+}
+
+static inline int inside_core(struct module *mod, unsigned long addr)
+{
+ if ((unsigned long)mod->module_core <= addr
+ && (unsigned long)mod->module_core + mod->core_size > addr)
+ return 1;
+ return 0;
+}
+
+static const char *get_ksymbol(struct module *mod,
+ unsigned long addr,
+ unsigned long *size,
+ unsigned long *offset)
+{
+ unsigned int i, next = 0, best = 0;
+
+ /* Scan for closest preceeding symbol, and next symbol. (ELF
+ starts real symbols at 1). */
+ for (i = 1; i < mod->num_syms; i++) {
+ if (mod->symtab[i].st_shndx == SHN_UNDEF)
+ continue;
+
+ if (mod->symtab[i].st_value <= addr
+ && mod->symtab[i].st_value > mod->symtab[best].st_value)
+ best = i;
+ if (mod->symtab[i].st_value > addr
+ && mod->symtab[i].st_value < mod->symtab[next].st_value)
+ next = i;
+ }
+
+ if (!best)
+ return NULL;
+
+ if (!next) {
+ /* Last symbol? It ends at the end of the module then. */
+ if (inside_core(mod, addr))
+ *size = mod->module_core+mod->core_size - (void*)addr;
+ else
+ *size = mod->module_init+mod->init_size - (void*)addr;
+ } else
+ *size = mod->symtab[next].st_value - addr;
+
+ *offset = addr - mod->symtab[best].st_value;
+ return mod->strtab + mod->symtab[best].st_name;
+}
+
+/* For kallsyms to ask for address resolution. NULL means not found.
+ We don't lock, as this is used for oops resolution and races are a
+ lesser concern. */
+const char *module_address_lookup(unsigned long addr,
+ unsigned long *size,
+ unsigned long *offset,
+ char **modname)
+{
+ struct module *mod;
+
+ list_for_each_entry(mod, &modules, list) {
+ if (inside_core(mod, addr) || inside_init(mod, addr)) {
+ *modname = mod->name;
+ return get_ksymbol(mod, addr, size, offset);
+ }
+ }
+ return NULL;
+}
+#endif /* CONFIG_KALLSYMS */
+
+/* Called by the /proc file system to return a list of modules. */
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct list_head *i;
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .7287-linux-2.5.46/scripts/kallsyms .7287-linux-2.5.46.updated/scripts/kallsyms
--- .7287-linux-2.5.46/scripts/kallsyms 1970-01-01 10:00:00.000000000 +1000
+++ .7287-linux-2.5.46.updated/scripts/kallsyms 2002-11-05 11:13:11.000000000 +1100
@@ -0,0 +1,40 @@
+#! /bin/sh
+# Written by Rusty Russell <rusty@rustcorp.com.au> 2002.
+
+if [ $# -ne 2 ]; then
+ echo Usage: kallsyms vmlinux objfile >&2
+
+ echo Adds a .kallsyms section containing symbol info.
+ exit 1
+fi
+
+set -e
+
+# Clean up on exit.
+trap "rm -f kallsyms.map kallsyms.c $2" 0
+
+# Takes nm output from $1, produces a .c file on standard output.
+encode_symbols()
+{
+ # First take addresses.
+ echo "unsigned long kallsyms_addresses[] = {"
+ sed 's/^[ ]*\([A-Fa-f0-9]*\).*/0x\1UL,/' < $1
+ echo "};"
+
+ # Now output size.
+ echo "unsigned long kallsyms_num_syms = `wc -l < $1`;"
+
+ # Now output names.
+ echo "char kallsyms_names[] = ";
+ sed 's/^[ ]*[A-Fa-f0-9]*[ ]*.[ ]\(.*\)/"\1\\0"/' < $1
+ echo ";"
+}
+
+# FIXME: Use System.map as input, and regenerate each time in Makefile.
+$NM $1 | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > kallsyms.map
+
+encode_symbols kallsyms.map > kallsyms.c
+$CC $CFLAGS -c -o $2 kallsyms.c
+
+trap "rm -f kallsyms.map kallsyms.c" 0
+exit 0

--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/