diff -urN modutils-2.2.2-pre6.orig/include/util.h modutils-2.2.2-pre6/include/util.h --- modutils-2.2.2-pre6.orig/include/util.h Thu Mar 11 06:48:07 1999 +++ modutils-2.2.2-pre6/include/util.h Sun May 23 11:56:44 1999 @@ -59,4 +59,6 @@ } GLOB_LIST; int meta_expand(char *pt, GLOB_LIST *g, char *base_dir, char *version); +extern void snap_shot(void); + #endif /* util.h */ diff -urN modutils-2.2.2-pre6.orig/insmod/insmod.c modutils-2.2.2-pre6/insmod/insmod.c --- modutils-2.2.2-pre6.orig/insmod/insmod.c Fri Mar 19 06:45:13 1999 +++ modutils-2.2.2-pre6/insmod/insmod.c Sun May 23 11:52:23 1999 @@ -69,6 +69,7 @@ int flag_verbose = 0; int flag_export = 1; int flag_load_map = 0; +int flag_ksymoops = 1; static int n_ext_modules_used; static int m_has_modinfo; @@ -243,7 +244,8 @@ unsigned long aa = obj_symbol_final_value(f, *as); unsigned long ba = obj_symbol_final_value(f, *bs); return aa < ba ? -1 : aa > ba ? 1 : 0; - } int i, nsyms, *loaded; + } + int i, nsyms, *loaded; /* Report on the section layout. */ @@ -407,6 +409,34 @@ } #endif +/* add an entry to the __ksymtab section, creating it if necessary */ +static void add_ksymtab(struct obj_file *f, struct obj_symbol *sym) +{ + struct obj_section *sec; + ElfW(Addr) ofs; + + /* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section. + * If __ksymtab is defined but not marked alloc, x out the first character + * (no obj_delete routine) and create a new __ksymtab with the correct + * characteristics. + */ + sec = obj_find_section(f, "__ksymtab"); + if (sec && !(sec->header.sh_flags & SHF_ALLOC)) { + *((char *)(sec->name)) = 'x'; /* override const */ + sec = NULL; + } + if (!sec) + sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0); + if (!sec) + return; + sec->header.sh_flags |= SHF_ALLOC; + + ofs = sec->header.sh_size; + obj_symbol_patch(f, sec->idx, ofs, sym); + obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name); + obj_extend_section(sec, 2 * tgt_sizeof_char_p); +} + static int create_module_ksymtab(struct obj_file *f) { struct obj_section *sec; @@ -435,11 +465,8 @@ } } if (flag_export && !obj_find_section(f, "__ksymtab")) { - size_t nsyms; int *loaded; - sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0); - /* We don't want to export symbols residing in sections that aren't loaded. There are a number of these created so that we make sure certain module options don't appear twice. */ @@ -448,23 +475,17 @@ while (--i >= 0) loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; - for (nsyms = i = 0; i < HASH_BUCKETS; ++i) { + for (i = 0; i < HASH_BUCKETS; ++i) { struct obj_symbol *sym; - for (sym = f->symtab[i]; sym; sym = sym->next) + for (sym = f->symtab[i]; sym; sym = sym->next) { if (ELFW(ST_BIND) (sym->info) != STB_LOCAL && sym->secidx <= SHN_HIRESERVE && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx])) { - ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p; - - obj_symbol_patch(f, sec->idx, ofs, sym); - obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name); - - nsyms++; + add_ksymtab(f, sym); } + } } - - obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p); } return 1; } @@ -531,6 +552,90 @@ return obj_find_symbol(f, "Using_Versions") != NULL; } +/* add module source, timestamp, kernel version and a symbol for the start of some sections. + * this info is used by ksymoops to do better debugging. + */ +static void add_ksymoops_symbols(struct obj_file *f, const char *filename, const char *m_name) +{ + struct obj_section *sec; + struct obj_symbol *sym; + char *name; + char str[STRVERSIONLEN]; + const char symprefix[] = "__insmod_"; + int i, l, lm_name, lfilename, use_ksymtab, version; + struct stat statbuf; + + static const char *section_names[] = { + ".text", + ".rodata", + ".data", + ".bss" + }; + + lm_name = strlen(m_name); + lfilename = strlen(filename); + + /* add to ksymtab if it already exists or there is no ksymtab and other symbols + * are not to be exported. otherwise leave ksymtab alone for now, the + * "export all symbols" compatibility code will export these symbols later. + */ + + use_ksymtab = obj_find_section(f, "__ksymtab") || !flag_export; + + if ((sec = obj_find_section(f, ".this"))) { + /* tag the module header with the object name, last modified + * timestamp and module version. worst case for module version + * is 0xffffff, decimal 16777215. putting all three fields in + * one symbol is less readable but saves kernel space. + */ + l = sizeof(symprefix)+ /* "__insmod_" */ + lm_name+ /* module name */ + 2+ /* "_O" */ + lfilename+ /* object filename */ + 2+ /* "_M" */ + 2*sizeof(statbuf.st_mtime)+ /* mtime in hex */ + 2+ /* "_V" */ + 8+ /* version in dec */ + 1; /* nul */ + name = xmalloc(l); + if (stat(filename, &statbuf) != 0) + statbuf.st_mtime = 0; + version = get_module_version(f, str); /* -1 if not found */ + snprintf(name, l, "%s%s_O%s_M%0*lX_V%d", + symprefix, m_name, filename, + 2*sizeof(statbuf.st_mtime), statbuf.st_mtime, + version); + sym = obj_add_symbol(f, name, -1, + ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), + sec->idx, sec->header.sh_addr, 0); + if (use_ksymtab) + add_ksymtab(f, sym); + } + + /* tag the desired sections if size is non-zero */ + + for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); ++i) { + if ((sec = obj_find_section(f, section_names[i])) && + sec->header.sh_size) { + l = sizeof(symprefix)+ /* "__insmod_" */ + lm_name+ /* module name */ + 2+ /* "_S" */ + strlen(sec->name)+ /* section name */ + 2+ /* "_L" */ + 8+ /* length in dec */ + 1; /* nul */ + name = xmalloc(l); + snprintf(name, l, "%s%s_S%s_L%d", + symprefix, m_name, sec->name, + sec->header.sh_size); + sym = obj_add_symbol(f, name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE), + sec->idx, sec->header.sh_addr, 0); + if (use_ksymtab) + add_ksymtab(f, sym); + } + } +} + static int process_module_arguments(struct obj_file *f, int argc, char **argv) { for (; argc > 0; ++argv, --argc) { @@ -941,7 +1046,7 @@ static void usage(void) { fputs("Usage:\n" - "insmod [-fkmopsvVxX] [-o name] [-P prefix] module [[sym=value]...]\n" + "insmod [-fkmopsvVxXyY] [-o name] [-P prefix] module [[sym=value]...]\n" "\n" " module Filename of a loadable kernel module (*.o)\n" @@ -957,6 +1062,8 @@ " -V, --version Show version\n" " -x Do not export externs\n" " -X Do export externs (default)\n" + " -y Do not add ksymoops symbols\n" + " -Y Do add ksymoops symbols (default)\n" " -P PREFIX\n" " --prefix=PREFIX Prefix for kernel or module symbols\n" ,stderr); @@ -983,6 +1090,8 @@ {"noexport", 0, 0, 'x'}, {"export", 0, 0, 'X'}, {"quiet", 0, 0, 'q'}, + {"noksymoops", 0, 0, 'y'}, + {"ksymoops", 0, 0, 'Y'}, {0, 0, 0, 0} }; char *m_name = NULL; @@ -1007,7 +1116,7 @@ errors = optind = 0; /* Process the command line. */ - while ((o = getopt_long(argc, argv, "fkmno:pqsvVxXLP:", + while ((o = getopt_long(argc, argv, "fkmno:pqsvVxXLP:yY", &long_opts[0], NULL)) != EOF) switch (o) { case 'f': /* force loading */ @@ -1049,6 +1158,12 @@ case 'X': /* do export externs */ flag_export = 1; break; + case 'y': /* do not define ksymoops symbols */ + flag_ksymoops = 0; + break; + case 'Y': /* do define ksymoops symbols */ + flag_ksymoops = 1; + break; case 'P': /* use prefix on crc */ set_ncv_prefix(optarg); break; @@ -1180,6 +1295,8 @@ } arch_create_got(f); hide_special_symbols(f); + if (flag_ksymoops) + add_ksymoops_symbols(f, filename, m_name); if (k_new_syscalls) create_module_ksymtab(f); @@ -1254,6 +1371,8 @@ if (dolock) flock(fileno(fp), LOCK_UN); fclose(fp); + if (!noload) + snap_shot(); return exit_status; } diff -urN modutils-2.2.2-pre6.orig/insmod/rmmod.c modutils-2.2.2-pre6/insmod/rmmod.c --- modutils-2.2.2-pre6.orig/insmod/rmmod.c Sun Mar 14 01:10:43 1999 +++ modutils-2.2.2-pre6/insmod/rmmod.c Sun May 23 12:02:36 1999 @@ -56,8 +56,10 @@ /* Remove all unused modules and stacks. */ if (delete_module(NULL)) { perror("rmmod"); + snap_shot(); return 1; } + snap_shot(); return 0; case 'r': @@ -90,6 +92,7 @@ perror(argv[1]); } } + snap_shot(); return ret ? 1 : 0; } @@ -153,5 +156,6 @@ } } + snap_shot(); return ret; } diff -urN modutils-2.2.2-pre6.orig/man/insmod.8 modutils-2.2.2-pre6/man/insmod.8 --- modutils-2.2.2-pre6.orig/man/insmod.8 Fri Mar 19 06:45:20 1999 +++ modutils-2.2.2-pre6/man/insmod.8 Sun May 23 12:17:56 1999 @@ -3,12 +3,12 @@ .\" See the file COPYING in the kernel source directory. .\" $Id: insmod.8,v 1.2 1999/03/18 19:45:20 bj0rn Exp $ .\" -.TH INSMOD 1 "26 Dec 1996" Linux "Linux Module Support" +.TH INSMOD 1 "04 Apr 1999" Linux "Linux Module Support" .SH NAME insmod \- install loadable kernel module .SH SYNOPSIS .B insmod -[\-fkmpqsxXv] [\-P prefix] [\-o module_name] object_file [ symbol=value ... ] +[\-fkmpqsxXvyY] [\-P prefix] [\-o module_name] object_file [ symbol=value ... ] .SH DESCRIPTION .B Insmod installs a loadable module in the running kernel. @@ -68,6 +68,18 @@ effective if the module does not explicitly export its own controled symbol table, and thus is depreciated. .TP +.I "\-Y, -y" +Do and do not add ksymoops symbols to ksyms. These symbols are used by +ksymoops to provide better debugging if there is an Oops in this +module. The default is for the ksymoops symbols to be defined. This +option is independent of the -X/-x options. +.TP +.I "" +ksymoops symbols add approximately 260 bytes per loaded module. Unless +you are really short on kernel space and are trying to reduce ksyms to +its minimum size, take the default and get more accurate Oops +debugging. +.TP .I "\-P prefix" This option can be used with versioned modules for a SMP kernel, since such modules have an extra prefix added in their symbol names. @@ -95,9 +107,57 @@ begins with double-quotes (\fI"\fP), the string is interpreted as in C, escape sequences and all. Do note that from the shell prompt, the quotes themselves may need to be protected from shell interpretation. +.SS "KSYMOOPS ASSISTANCE" +To assist with debugging of kernel Oops when using modules, insmod +defaults to adding some symbols to ksyms, see the \fB-Y\fP option. +These symbols start with \fB__insmod_\fP\fImodulename\fP\fB_\fP. The +\fImodulename\fP is required to make the symbols unique, it is legal to +load the same object more than once under different module names. +Currently defined symbols are +.PP +__insmod_\fImodulename\fP_O\fIobjectfile\fP_M\fImtime\fP_V\fIversion\fP +.PP +\fIobjectfile\fP is the name of the file that the object was loaded +from. This ensures that ksymoops can match the code to the correct +object. \fImtime\fP is the last modified timestamp on that file in +hex, zero if stat failed. \fIversion\fP is the kernel version that +the module was compiled for, -1 if no version is available. The +_O symbol has the same start address as the module header. +.PP +__insmod_\fImodulename\fP_S\fIsectionname\fP_L\fIlength\fP +.PP +This symbol appears at the start of selected ELF sections, +currently .text, .rodata, .data and .bss. It only appears if the +section has a non-zero size. \fIsectionname\fP is the name of the ELF +section, \fIlength\fP is the length of the section in decimal. These +symbols help ksymoops map addresses to sections when no symbols are +available. +.PP +The other problem with debugging kernel Oops in modules is that the +contents of /proc/ksyms and /proc/modules can change between the Oops +and when you process the log file. To help overcome this problem, if +directory /var/log/ksymoops exists then insmod and rmmod will +automatically copy /proc/ksyms and /proc/modules to /var/log/ksymoops +with a prefix of `date\ +%Y%m%d%T%M%S\ |\ sed\ -e\ 's/://g'`. +The system administrator can tell ksymoops which snapshot files to use +when debugging an Oops. There is no switch to disable this automatic +copy, if you do not want it to occur, do not create /var/log/ksymoops. +If that directory exists, it should be owned by root and be mode 644 or +600 and you should run this script every day or so. +.PP +.ne 8 + #!/bin/sh + # Delete saved ksyms and modules not accessed in 7 days + set -e + # Make sure there is always at least one version + d=`date +%Y%m%d%T%M%S | sed -e 's/://g'` + cp -a /proc/ksyms /var/log/ksymoops/${d}.ksyms + cp -a /proc/modules /var/log/ksymoops/${d}.modules + find /var/log/ksymoops -type f -atime +7 -exec rm {} \; .SH SEE ALSO \fBrmmod\fP(8), \fBmodprobe\fP(8), \fBdepmod\fP(8), \fBlsmod\fP(8), -\fBksyms\fP(8), \fBmodules\fP(2), \fBgenksyms\fP(8), \fBkerneld\fP(8). +\fBksyms\fP(8), \fBmodules\fP(2), \fBgenksyms\fP(8), \fBkerneld\fP(8), +\fBksymoops\fP(kernel). .SH HISTORY Module support was first concieved by Anonymous .br @@ -112,3 +172,5 @@ Rewritten for 2.1.17 by Richard Henderson .br Extended by Bjorn Ekwall for modutils-2.2.*, March 1999 +.br +Assistance for ksymoops by Keith Owens , May 1999 diff -urN modutils-2.2.2-pre6.orig/util/Makefile.in modutils-2.2.2-pre6/util/Makefile.in --- modutils-2.2.2-pre6.orig/util/Makefile.in Sat Mar 20 00:45:50 1999 +++ modutils-2.2.2-pre6/util/Makefile.in Sun May 23 11:53:06 1999 @@ -26,7 +26,7 @@ OBJS = sys_cm.o sys_dm.o sys_gks.o sys_nim.o sys_oim.o sys_qm.o \ xmalloc.o xrealloc.o xstrdup.o logger.o \ - modstat.o meta_expand.o config.o + modstat.o meta_expand.o config.o snap_shot.o meta_expand.o: meta_expand.c $(CC) $(CFLAGS) $(DEFS) @HAVE_WORDEXP@ @HAVE_GLOB@ -c $< diff -urN modutils-2.2.2-pre6.orig/util/snap_shot.c modutils-2.2.2-pre6/util/snap_shot.c --- modutils-2.2.2-pre6.orig/util/snap_shot.c Thu Jan 1 10:00:00 1970 +++ modutils-2.2.2-pre6/util/snap_shot.c Sun May 23 11:57:47 1999 @@ -0,0 +1,85 @@ +/* Take a snap shot of ksyms and modules for Oops debugging + Copyright 1999 Linux International. + + Contributed by Keith Owens + + This file is part of the Linux modutils. + + 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: snap_shot.c,v 1.0 1999/05/23 11:55:19 keith Exp $" + +#include +#include +#include + +#include "util.h" + +/* If snap_dir exists, take a snap shot of ksyms and modules to snap_dir. + * Prefix the files with the equivalent of + * date +%Y%m%d%T%M%S | sed -e 's/://g' + */ +void snap_shot(void) +{ + static char snap_dir[] = "/var/log/ksymoops"; + char wd[sizeof(snap_dir)+2], file[] = "ccyymmddhhmmss.modules", buffer[4096]; + static char *infile[] = { "/proc/ksyms", "/proc/modules" }; + static char *suffix[] = { "ksyms", "modules" }; + struct tm *local; + time_t t; + int i, l; + FILE *in, *out; + if (chdir(snap_dir)) + return; + if (!getcwd(wd, sizeof(wd)) || strcmp(snap_dir, wd)) { + error("%s must be a real directory", snap_dir); + return; + } + t = time(NULL); + local = localtime(&t); + for (i = 0; i < sizeof(infile)/sizeof(infile[0]); ++i) { + snprintf(file, sizeof(file), "%04d%02d%02d%02d%02d%02d.%s", + local->tm_year+1900, + local->tm_mon, + local->tm_mday, + local->tm_hour, + local->tm_min, + local->tm_sec, + suffix[i]); + out = fopen(file, "w"); + if (!out) { + error("cannot create %s/%s %m", snap_dir, file); + return; + } + in = fopen(infile[i], "r"); + if (!in) { + error("cannot open %s %m", infile[i]); + return; + } + while ((l = fread(buffer, 1, sizeof(buffer), in)) > 0) { + if (fwrite(buffer, l, 1, out) != 1) { + error("unable to write to %s %m", file); + fclose(in); + fclose(out); + return; + } + } + if (ferror(in)) + error("unable to read from %s %m", infile[i]); + fclose(in); + fclose(out); + } +}