summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
commit0ae8dceaebe3659ee0c3352c08125f403e77ebca (patch)
tree5085c389f09da78182b899d19fe1068b619a69dd /scripts
parent273767781288c35c9d679e908672b9996cda4c34 (diff)
Merge with 2.3.10.
Diffstat (limited to 'scripts')
-rw-r--r--scripts/ksymoops/Makefile79
-rw-r--r--scripts/ksymoops/README404
-rw-r--r--scripts/ksymoops/io.c139
-rw-r--r--scripts/ksymoops/ksymoops.c678
-rw-r--r--scripts/ksymoops/ksymoops.h146
-rw-r--r--scripts/ksymoops/ksyms.c294
-rw-r--r--scripts/ksymoops/map.c251
-rw-r--r--scripts/ksymoops/misc.c108
-rw-r--r--scripts/ksymoops/object.c230
-rw-r--r--scripts/ksymoops/oops.c1377
-rw-r--r--scripts/ksymoops/re.c145
-rw-r--r--scripts/ksymoops/symbol.c444
-rw-r--r--scripts/ver_linux8
13 files changed, 11 insertions, 4292 deletions
diff --git a/scripts/ksymoops/Makefile b/scripts/ksymoops/Makefile
deleted file mode 100644
index 81e80c1e0..000000000
--- a/scripts/ksymoops/Makefile
+++ /dev/null
@@ -1,79 +0,0 @@
-# Description file for ksymoops
-
-# Thu Nov 26 16:37:46 EST 1998
-# Version 0.6c
-# Add -c option.
-
-# Tue Nov 3 02:31:01 EST 1998
-# Version 0.6
-# Read lsmod (/proc/modules).
-# Add Makefile defaults for vmlinux, ksyms, objects, System.map, lsmod.
-# Upper case variables.
-# Convert from a.out to bfd, using same format as ksymoops.
-
-DEFS = Makefile ksymoops.h
-
-# Defaults for vmlinux, ksyms, objects, lsmod, System.map. Externalised so
-# distributions can tweak to suit their own file system layout.
-
-# To default to not reading a source, set to any empty string.
-# To default to reading a source, supply a quoted and escaped string.
-
-# If the string contains *r (*m, *n, *s) then it is replaced at run time by
-# the current value of `uname -r` (-m, -n, -s). '*' was chosen as something
-# that rarely appears in filenames and does not cause problems like '%' or '$'.
-
-DEF_VMLINUX = # default no vmlinux
-DEF_OBJECTS = \"/lib/modules/*r/\" # default current modules
-DEF_KSYMS = \"/proc/ksyms\" # default current ksyms
-DEF_LSMOD = \"/proc/modules\" # default current lsmod
-DEF_MAP = \"/usr/src/linux/System.map\" # default current map
-DEF_CODE_BYTES = 1 # default bytes per code unit
-
-# RedHat users might want defaults like these
-# DEF_MAP = \"/boot/System.map-*r\"
-# DEF_OBJECTS = \"/boot/module-info-*r\"
-
-PROGS = ksymoops
-
-CC=gcc
-CFLAGS = -Dlinux \
- -Wall \
- -Wno-conversion \
- -Waggregate-return \
- -Wstrict-prototypes \
- -Wmissing-prototypes \
- $(DEBUG)
-
-ifneq ($(strip $(DEF_VMLINUX)),)
- CFLAGS += -DDEF_VMLINUX=$(strip $(DEF_VMLINUX))
-endif
-ifneq ($(strip $(DEF_OBJECTS)),)
- CFLAGS += -DDEF_OBJECTS=$(strip $(DEF_OBJECTS))
-endif
-ifneq ($(strip $(DEF_KSYMS)),)
- CFLAGS += -DDEF_KSYMS=$(strip $(DEF_KSYMS))
-endif
-ifneq ($(strip $(DEF_LSMOD)),)
- CFLAGS += -DDEF_LSMOD=$(strip $(DEF_LSMOD))
-endif
-ifneq ($(strip $(DEF_MAP)),)
- CFLAGS += -DDEF_MAP=$(strip $(DEF_MAP))
-endif
-
-CFLAGS += -DDEF_CODE_BYTES=$(strip $(DEF_CODE_BYTES))
-
-OBJECTS = io.o ksyms.o ksymoops.o map.o misc.o object.o oops.o re.o symbol.o
-
-all: $(PROGS)
-
-: $(OBJECTS)
-
-$(OBJECTS): $(DEFS)
-
-$(PROGS): %: %.o $(DEFS) $(OBJECTS)
- $(CC) $(OBJECTS) $(CFLAGS) -lbfd -liberty -o $@
- -@size $@
-
-clean:
- rm -f core *.o $(PROGS)
diff --git a/scripts/ksymoops/README b/scripts/ksymoops/README
index e38ee2c10..c463b4c71 100644
--- a/scripts/ksymoops/README
+++ b/scripts/ksymoops/README
@@ -1,399 +1,7 @@
- ksymoops.
+ksymoops has been removed from the kernel. It was always meant to be a
+free standing utility, not linked to any particular kernel version.
+The latest version can be found in ftp://ftp.ocs.com.au/pub/ksymoops,
+together with patches to other utilities in order to give more accurate
+Oops debugging.
- Read a kernel Oops file and make the best stab at converting the code to
- instructions and mapping stack values to kernel symbols.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- To compile, simply type "make" in the ksymoops directory.
-
- TESTERS WANTED.
-
- ksymoops handles ix86. It appears to handle Alpha, Sparc, M68K, PPC,
- MIPS but I have no machine to test on. I would appreciate feedback
- from users of non ix86 machines. In particular, it would be nice if
- you could run
-
- ksymoops -VMO -k /proc/ksyms -dd <oops.file >/tmp/ksymoops.log 2>&1
-
- and mail /tmp/ksymoops.log to kaos@ocs.com.au
-
- TODO:
- Clean up these docs.
- Tweak System.map to include arch information.
- Tweak modutils to log at least one symbol for each module loaded,
- otherwise they are invisible to ksymoops. Also arch and version data.
- Include sparc/sparc64 patches from Jakub Jelinek <jj@sunsite.mff.cuni.cz>.
- Add object format override for sparc/soparc64 or any cross platform
- oops debugging.
-
- Mon Jan 4 09:48:13 EST 1999
- Version 0.6e
- Added to kernel.
- Add ARM support.
- Typo in oops_code.
- Add -c option.
- Add -1 option.
- Report if options were specified or defaulted.
- Remove false warnings when comparing ksyms and lsmod.
- Performance inprovements.
-
- Wed Oct 28 23:14:55 EST 1998
- Version 0.5
- No longer read vmlinux by default, it only duplicates System.map.
-
- Wed Oct 28 13:46:39 EST 1998
- Version 0.4
- Split into separate sources.
-
- Mon Oct 26 00:01:47 EST 1998
- Version 0.3c
- Add alpha (arm) processing.
-
- Mon Oct 26 00:01:47 EST 1998
- Version 0.3b
- Add sparc processing.
- Handle kernel symbol versions.
-
- Fri Oct 23 13:11:20 EST 1998
- Version 0.3
- Add -follow to find command for people who use symlinks to modules.
- Add Version_ checking.
-
- Thu Oct 22 22:28:30 EST 1998
- Version 0.2.
- Generalise text prefix handling.
- Handle messages on Code: line.
- Format addresses with leading zeroes.
- Minor bug fixes.
-
- Wed Oct 21 23:28:48 EST 1998
- Version 0.1. Rewrite from scratch in C.
-
- CREDITS.
- Oops disassembly based on ksymoops.cc,
- Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
- m68k code based on ksymoops.cc changes by
- Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-
- This code subsumes the Perl script make_System.map.pl which is no longer
- supported.
-
- Why another ksymoops I hear you ask? Various complaints about
- ksymoops.cc -
-
- * It requires C++.
- * It has hard wired limitations on the number of symbols.
- * It does not handle modules at all.
- * Very rigid requirements on the format of input, especially the Oops
- log.
- * No cross checking between ksyms, modules, System.map etc.
- * Very little error checking, diagnostics are not suitable for
- beginners.
- * It only prints the trace and decoded code, users have to manually
- extract the other lines from the Oops.
- * Gives up on the slightest problem.
- * Only handles i386 and possibly m68k. The code is difficult to extend
- to other architectures.
- * Stops after the first Oops, you have to manually extract each one and
- run through ksymoops one at a time.
-
- This version is -
- * C.
- * No hard wired limitations (malloc as far as the eye can see).
- * Handles modules by default.
- * Uses regular pattern matching so it is a lot more forgiving about
- input formats.
- * By default, cross checks ksyms, modules, System.map and vmlinux.
- * Lots of diagnostics and error checking.
- * Prints all relevant lines for a complete Oops report.
- * Tries to provide output no matter how bad the input is. The level of
- progress and error reporting is aimed at beginners.
- * Handles i386, alpha, sparc, sparc64, m68k. It is a lot easier to extend
- to other architectures (patches and/or sample data gratefully accepted).
- * Handles all Oops in the input file(s).
-
-
- Usage: ksymoops
- [-v vmlinux] Where to read vmlinux
- [-V] No vmlinux is available
- [-o object_dir] Directory containing modules
- [-O] No modules is available
- [-k ksyms] Where to read ksyms
- [-K] No ksyms is available
- [-l lsmod] Where to read lsmod
- [-L] No lsmod is available
- [-m system.map] Where to read System.map
- [-M] No System.map is available
- [-s save.map] Save consolidated map
- [-c code_bytes] How many bytes in each unit of code
- [-1] One shot toggle (exit after first Oops)
- [-d] Increase debug level by 1
- [-h] Print help text
- Oops.file Oops to decode
-
- All flags can occur more than once. With the exception of -o
- and -d which are cumulative, the last occurrence of each flag is
- used. Note that "-v my.vmlinux -V" will be taken as "No vmlinux
- available" but "-V -v my.vmlinux" will read my.vmlinux. You
- will be warned about such combinations.
-
- Each occurrence of -d increases the debug level.
-
- Each -o flag can refer to a directory or to a single object
- file. If a directory is specified then all *.o files in that
- directory and its subdirectories are assumed to be modules.
-
- If any of the vmlinux, object_dir, ksyms or system.map options
- contain the string *r (*m, *n, *s) then it is replaced at run time
- by the current value of `uname -r` (-m, -n, -s).
-
- The defaults can be changed in the Makefile, typical options are
-
- Defaults: -V
- -o /lib/modules/%r
- -k /proc/ksyms
- -l /proc/modules
- -m /usr/src/linux/System.map
- -c 1
- Oops report is read from stdin
-
- Note: Unless you tell ksymoops *NOT* to read a particular file, it
- will try to read and reconcile almost all possible sources of kernel
- symbol information. This is intended for beginners, they just
- type
-
- ksymoops < /var/log/syslog
-
- no thinking required. Experts can point at different files or
- suppress the input from selected files. For example, if you
- save /proc/ksyms before doing a test that creates an Oops, you
- can point ksymoops at the saved ksyms instead of using
- /proc/ksyms.
-
- vmlinux is not read by default, it only duplicates the
- information in System.map. If you want to read vmlinux as well
- as or instead of System.map, use -v.
-
- To get the equivalent of the old ksymoops.cc (no vmlinux, no
- modules objects, no ksyms, no System.map) just do ksymoops
- -VOKLM. Or to just read System.map, ksymoops -VOKL -m mapfile.
-
-
- Return codes: 0 - normal.
- 1 - error(s) or warning(s) issued, results may not be
- reliable.
- 2 - fatal error, no useful results.
- 3 - One shot mode, end of input reached.
-
- Supported architectures
-
- i386 tested.
- m68k code derived from ksymoops.cc and reading traps.c, untested.
- MIPS tested.
- Sparc tested.
- Sparc64 tested.
- Alpha tested.
- ARM tested.
-
- The term "eip" is generic, for example it includes the i386 EIP
- and the m68k PC. Remember that objdump output always says EIP,
- no matter what the architecture, see objfile_head.
-
- To support another arch, check the Oops_ procedures between
- 'Start architecture sensitive code' and 'End architecture
- sensitive code'.
-
- The pattern matching should take care of different lengths for
- the address, i.e. addresses should not be arch sensitive. I
- assume that all addresses are at least 4 characters.
-
- If nm output has a different format on your arch, check for uses
- of re_nm.
-
-
-
- Because ksymoops reads kernel information from multiple sources, there
- could be mismatches. ksymoops does the following cross checks, but only
- if the specified files exist -
-
- * Compare Version_nnn numbers from all sources against each other. Pity
- that only vmlinux and System.map have these symbols (as at 2.1.125),
- however I check ksyms, modules and Oops as well. If somebody adds
- symbol Version_nnn to ksyms or modules or adds a Version_nnn line to
- the Oops log, this code is ready.
-
- * Compare kernel ksyms against vmlinux. vmlinux takes precedence.
-
- * Compare System.map against vmlinux. vmlinux takes precedence.
-
- * Compare vmlinux against System.map. vmlinux takes precedence.
-
- * Compare kernel ksyms against System.map. System.map takes precedence.
-
- * Compare modules against module ksyms. modules take precedence. Only
- if at least one module appears in ksyms.
-
- * Compare module names in ksyms against lsmod. Warn if a module
- appears in lsmod but not in ksyms. Error if a modules appears in
- ksyms but is not in lsmod. Only if both ksyms and lsmod have being
- read.
-
- The precedence order is somewhat arbitrary, however it only applies if
- there is any difference between the various sources.
-
- Handling modules is awkward. They can be loaded under different names
- (insmod -o dummy1 dummy.o) and the text, data and read only data are
- loaded at different offsets. Although you can give the -m option to
- insmod which will output the module map when it is loaded, this has a
- few problems -
-
- * No equivalent for removing a module. If you load and remove a lot of
- modules, you end up with multiple sets of symbols around the same
- offsets, which set is correct?
-
- * "insmod -o dummy1 dummy.o" still reports as dummy. That is, there is
- no way of telling which particular version of a multiply loaded
- module the insmod output refers to. Therefore there is no way of
- telling which instantiation failed.
-
- * Even if the above problems are fixed, how do you tell what the module
- environment looked like when the Oops occurred? What if a module is
- loaded or removed just after Oops, how is the user expected to edit
- the insmod log? Rule 1 - make ksymoops easy for beginners.
-
- Although those problems could be fixed, they require changes to
- modutils. Working from ksyms and the module objects can be done without
- changing modutils and without confusing beginners.
-
- Alas the ksyms plus object approach has another problem - matching ksyms
- to module objects. Nowhere does the kernel say that module dummy1 came
- from module /lib/modules/2.1.215/net/dummy.o, ksyms just says dummy1. I
- have to match ksyms to the relevant object by finding a globally unique
- external symbol in each module that can be used to map to the external
- symbols in ksyms. This assumes that each module exports at least one
- text symbol that is unique amongst all modules.
-
- It may not be possible to correctly map other sections such as data and
- readonly data for modules because they may not have exported symbols.
- Since the main aim of ksymoops is to map a code Oops, this should not be
- a problem.
-
- Unfortunately some modules export no symbols. They are marked as
- EXPORT_NO_SYMBOLS are simply do not export anything. It is
- impossible to detect these in ksyms because, by definition, ksyms
- only contains exported symbols for modules. Since all modules appear
- in lsmod (/proc/modules), a cross check of lsmod against the module
- names will find loaded modules with no symbols, at least I can warn
- about these.
-
- After merging the various sources, ksymoops has a (hopefully) accurate
- map including modules. The -s option lets you save the merged
- System.map, but remember that module data and readonly data sections may
- not be correctly relocated, see above.
-
- Environment Variables.
- KSYMOOPS_NM path for nm, defaults to /usr/bin/nm.
- KSYMOOPS_FIND path for find, defaults to /usr/bin/find.
- KSYMOOPS_OBJDUMP path for objdump, defaults to /usr/bin/objdump.
-
-
- Input Oops data.
-
- The ideal input is to feed the syslog straight into this program. If
- you cannot do that, you need to know what the program looks for.
- Especially if you are typing in the Oops by hand :(. All input is case
- insensitive.
-
- * White space in this context means space or tab. It does not include
- newline.
-
- * Oops in syslog has a syslog prefix. Leading text up to and including
- ' kernel: ' is always ignored, there is no need to edit syslog first.
- This leading text need not exist but if it does, it must end in
- ' kernel: '.
-
- * An alternative prefix is <n> where n is the kernel print level. Also
- ignored if present.
-
- * Leading white space is treated as a prefix and ignored, the input is
- not indentation sensitive.
-
- * In the following paragraphs, assume that any prefixes have been
- skipped. If there is more than one prefix, all are skipped, no matter
- which order they appear in.
-
- * A bracketed address is optional '[', required '<', at least 4 hex
- digits, required '>', optional ']'. For example [<01234567>] or
- <1234>.
-
- * The ix86 EIP line is identified by optional white space followed by
- 'EIP:', followed by a least one white space, followed by a bracketed
- address.
-
- * The m68k PC line is identified by optional white space followed by
- 'PC', optionally followed by white space, followed by '=', optionally
- followed by white space, followed by a bracketed address.
-
- * The sparc PC line starts with PSR and PC is the second hex value, not
- bracketed.
-
- * The sparc64 TPC line starts with TSTATE and TPC is the second hex value,
- not bracketed.
-
- * A call trace line is identified by 'Call Trace:' followed by at least
- one white space. Or it is a line starting with a bracketed address,
- but only if the previous line was a call trace line (I hate multi line
- output that relies on identation for recognition, especially when
- lines can have a variable prefix).
-
- * The Code line is identified by 'Code:' followed by a least one white
- space character followed by at least one hex value. The line can
- contain multiple hex values, each separated by at least one white
- space. Each hex value must be 2 to 8 digits and must be a multiple of
- 2 digits.
-
- On some architectures the Code: data is a stream of single bytes,
- in machine order. On other architectures, it is a stream of shorts
- or ints in human readable order which does not always match the
- machine order, endianess raises its ugly head. We are consistently
- inconsistent.
-
- To cater for these architecture inconsistencies, use the -c option.
- If the Code: line is already in machine order, use -c 1. If the
- Code: data is a stream of shorts or ints which do not match the
- machine order, use -c 2 or -c 4. Each set of 'c' bytes are swapped
- to (hopefully) reflect the machine order.
-
- Special cases where Code: can be followed by text.
- 'Code: general protection'
- 'Code: <n>'
- Dump the data anyway, the code was unavailable.
-
- * Formatted data is only output when the Code: line is seen. If any
- data has been stored and more than 5 lines other than Oops text (see
- Oops_print) or end of file are encountered then ksymoops assumes that
- the Code: line is missing or garbled and dumps the formatted data
- anyway. Fail safe, I hope.
-
- * By default, ksymoops reads its entire input file. If the -1 toggle
- is set, it will run in one shot mode and exit after the first Oops.
- This is useful for automatically mailing reports as they happen,
- like this :-
-
- #!/bin/sh
- # ksymoops1
- while (true)
- do
- ksymoops -1 > $HOME/oops1
- if [ $? -eq 3 ]
- then
- exit 0
- fi
- mail -s Oops admin < $HOME/oops1
- done
-
- tail -f /var/log/messages | ksymoops1
-
- Restarting after log rotation is left as an exercise for the reader.
+Keith Owens <kaos@ocs.com.au> Sat Jun 19 10:30:34 EST 1999
diff --git a/scripts/ksymoops/io.c b/scripts/ksymoops/io.c
deleted file mode 100644
index b54e8ad90..000000000
--- a/scripts/ksymoops/io.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- io.c.
-
- Local I/O routines for ksymoops.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- fwrite_local is redundant, replaced by bfd.
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into separate sources.
-
- */
-
-#include "ksymoops.h"
-#include <errno.h>
-#include <malloc.h>
-#include <string.h>
-#include <sys/stat.h>
-
-int regular_file(const char *file, const char *msg)
-{
- struct stat statbuf;
- if (stat(file, &statbuf)) {
- fprintf(stderr, "%s: %s stat %s failed",
- prefix, msg, file);
- perror(" ");
- ++errors;
- return 0;
- }
-
- if (!S_ISREG(statbuf.st_mode)) {
- fprintf(stderr,
- "%s: %s %s is not a regular file, ignored\n",
- prefix, msg, file);
- ++errors;
- return 0;
- }
- return 1;
-}
-
-FILE *fopen_local(const char *file, const char *mode, const char *msg)
-{
- FILE *f;
- if (!(f = fopen(file, mode))) {
- fprintf(stderr, "%s: %s fopen '%s' failed",
- prefix, msg, file);
- perror(" ");
- ++errors;
- }
- return f;
-}
-
-void fclose_local(FILE *f, const char *msg)
-{
- int i;
- if ((i = fclose(f))) {
- fprintf(stderr, "%s: %s fclose failed %d", prefix, msg, i);
- perror(" ");
- ++errors;
- }
-}
-
-/* Read a line, increasing the size of the line as necessary until \n is read */
-#define INCREMENT 10 /* arbitrary */
-char *fgets_local(char **line, int *size, FILE *f, const char *msg)
-{
- char *l, *p, *r;
- int longline = 1;
-
- if (!*line) {
- *size = INCREMENT;
- *line = malloc(*size);
- if (!*line)
- malloc_error("fgets_local alloc line");
- }
-
- l = *line;
- while (longline) {
- r = fgets(l, *size-(l-*line), f);
- if (!r) {
- if (ferror(f)) {
- fprintf(stderr,
- "%s: %s fgets failed", prefix, msg);
- perror(" ");
- ++errors;
- }
- if (l != *line)
- return(*line);
- else
- return(r);
- }
- if (!(p = strchr(*line, '\n'))) {
- *size += INCREMENT;
- *line = realloc(*line, *size);
- if (!*line)
- malloc_error("fgets_local realloc line");
- l = *line+*size-INCREMENT-1;
- }
- else {
- *p = '\0';
- longline = 0;
- }
- }
-
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s line '%s'\n", msg, *line);
- return(*line);
-}
-
-FILE *popen_local(const char *cmd, const char *msg)
-{
- FILE *f;
- if (!(f = popen(cmd, "r"))) {
- fprintf(stderr, "%s: %s popen '%s' failed",
- prefix, msg, cmd);
- perror(" ");
- ++errors;
- }
- return f;
-}
-
-void pclose_local(FILE *f, const char *msg)
-{
- int i;
- errno = 0;
- if ((i = pclose(f))) {
- fprintf(stderr, "%s: %s pclose failed 0x%x", prefix, msg, i);
- if (errno)
- perror(" ");
- else
- fprintf(stderr, "\n");
- ++errors;
- }
-}
diff --git a/scripts/ksymoops/ksymoops.c b/scripts/ksymoops/ksymoops.c
deleted file mode 100644
index 0cd65795b..000000000
--- a/scripts/ksymoops/ksymoops.c
+++ /dev/null
@@ -1,678 +0,0 @@
-/*
- ksymoops.c.
-
- Read a kernel Oops file and make the best stab at converting the code to
- instructions and mapping stack values to kernel symbols.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-*/
-
-#define VERSION "0.6e"
-
-/*
-
- Tue Jan 5 19:26:02 EST 1999
- Version 0.6e
- Added to kernel.
-
- Mon Jan 4 09:48:13 EST 1999
- Version 0.6d
- Add ARM support.
-
- Thu Nov 26 16:37:46 EST 1998
- Version 0.6c
- Typo in oops_code.
- Add -c option.
- Add -1 option.
- Report if options were specified or defaulted.
-
- Fri Nov 6 10:38:42 EST 1998
- Version 0.6b
- Remove false warnings when comparing ksyms and lsmod.
-
- Tue Nov 3 23:33:04 EST 1998
- Version 0.6a
- Performance inprovements.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- Read lsmod (/proc/modules).
- Ignore addresses 0-4095 when mapping address to symbol.
- Discard default objects if -o specified.
- Oops file must be regular.
- Add "invalid operand" to Oops_print.
- Move "Using_Version" copy to map.c.
- Add Makefile defaults for vmlinux, ksyms, objects, System.map, lsmod.
- Minor adjustment to re for ppc.
- Minor adjustment to re for objdump lines with <_EIP+xxx>.
- Convert from a.out to bfd, using same format as ksymoops.
- Added MIPS.
- PPC handling based on patches by "Ryan Nielsen" <ran@krazynet.com>
-
- Wed Oct 28 23:14:55 EST 1998
- Version 0.5
- No longer read vmlinux by default, it only duplicates System.map.
-
- Wed Oct 28 13:47:38 EST 1998
- Version 0.4
- Split into separate sources.
-
- Mon Oct 26 00:01:47 EST 1998
- Version 0.3c
- Add alpha (arm) processing.
-
- Mon Oct 26 00:01:47 EST 1998
- Version 0.3b
- Add sparc processing.
- Handle kernel symbol versions.
-
- Fri Oct 23 13:11:20 EST 1998
- Version 0.3
- Add -follow to find command for people who use symlinks to modules.
- Add Version_ checking.
-
- Thu Oct 22 22:28:30 EST 1998
- Version 0.2.
- Generalise text prefix handling.
- Handle messages on Code: line.
- Format addresses with leading zeroes.
- Minor bug fixes.
-
- Wed Oct 21 23:28:48 EST 1998
- Version 0.1. Rewrite from scratch in C.
-
- CREDITS.
- Oops disassembly based on ksymoops.cc,
- Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com>
- m68k code based on ksymoops.cc changes by
- Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- */
-
-#include "ksymoops.h"
-#include <ctype.h>
-#include <errno.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/utsname.h>
-
-char *prefix;
-char *path_nm = "/usr/bin/nm"; /* env KSYMOOPS_NM */
-char *path_find = "/usr/bin/find"; /* env KSYMOOPS_FIND */
-char *path_objdump = "/usr/bin/objdump"; /* env KSYMOOPS_OBJDUMP */
-int debug = 0;
-int errors = 0;
-int warnings = 0;
-
-SYMBOL_SET ss_vmlinux;
-SYMBOL_SET ss_ksyms_base;
-SYMBOL_SET *ss_ksyms_module;
-int ss_ksyms_modules;
-SYMBOL_SET ss_lsmod;
-SYMBOL_SET *ss_object;
-int ss_objects;
-SYMBOL_SET ss_system_map;
-
-SYMBOL_SET ss_merged; /* merged map with info from all sources */
-SYMBOL_SET ss_Version; /* Version_ numbers where available */
-
-/* Regular expression stuff */
-
-regex_t re_nm;
-regmatch_t *re_nm_pmatch;
-regex_t re_bracketed_address;
-regmatch_t *re_bracketed_address_pmatch;
-regex_t re_unbracketed_address;
-regmatch_t *re_unbracketed_address_pmatch;
-
-static void usage(void)
-{
- fprintf(stderr, "Version " VERSION "\n");
- fprintf(stderr, "usage: %s\n", prefix);
- fprintf(stderr,
- "\t\t[-v vmlinux]\tWhere to read vmlinux\n"
- "\t\t[-V]\t\tNo vmlinux is available\n"
- "\t\t[-o object_dir]\tDirectory containing modules\n"
- "\t\t[-O]\t\tNo modules is available\n"
- "\t\t[-k ksyms]\tWhere to read ksyms\n"
- "\t\t[-K]\t\tNo ksyms is available\n"
- "\t\t[-l lsmod]\tWhere to read lsmod\n"
- "\t\t[-L]\t\tNo lsmod is available\n"
- "\t\t[-m system.map]\tWhere to read System.map\n"
- "\t\t[-M]\t\tNo System.map is available\n"
- "\t\t[-s save.map]\tSave consolidated map\n"
- "\t\t[-d]\t\tIncrease debug level by 1\n"
- "\t\t[-h]\t\tPrint help text\n"
- "\t\t[-c code_bytes]\tHow many bytes in each unit of code\n"
- "\t\t[-1]\t\tOne shot toggle (exit after first Oops)\n"
- "\t\t<Oops.file\tOops report to decode\n"
- "\n"
- "\t\tAll flags can occur more than once. With the exception "
- "of -o\n"
- "\t\tand -d which are cumulative, the last occurrence of each "
- "flag is\n"
- "\t\tused. Note that \"-v my.vmlinux -V\" will be taken as "
- "\"No vmlinux\n"
- "\t\tavailable\" but \"-V -v my.vmlinux\" will read "
- "my.vmlinux. You\n"
- "\t\twill be warned about such combinations.\n"
- "\n"
- "\t\tEach occurrence of -d increases the debug level.\n"
- "\n"
- "\t\tEach -o flag can refer to a directory or to a single "
- "object\n"
- "\t\tfile. If a directory is specified then all *.o files in "
- "that\n"
- "\t\tdirectory and its subdirectories are assumed to be "
- "modules.\n"
- "\n"
- "\t\tIf any of the vmlinux, object_dir, ksyms or system.map "
- "options\n"
- "\t\tcontain the string *r (*m, *n, *s) then it is replaced "
- "at run\n"
- "\t\ttime by the current value of `uname -r` (-m, -n, -s).\n"
- "\n"
- "\t\tThe defaults can be changed in the Makefile, current "
- "defaults\n"
- "\t\tare\n\n"
- "\t\t\t"
-#ifdef DEF_VMLINUX
- "-v " DEF_LINUX
-#else
- "-V"
-#endif
- "\n"
- "\t\t\t"
-#ifdef DEF_OBJECTS
- "-o " DEF_OBJECTS
-#else
- "-O"
-#endif
- "\n"
- "\t\t\t"
-#ifdef DEF_KSYMS
- "-k " DEF_KSYMS
-#else
- "-K"
-#endif
- "\n"
- "\t\t\t"
-#ifdef DEF_LSMOD
- "-l " DEF_LSMOD
-#else
- "-L"
-#endif
- "\n"
- "\t\t\t"
-#ifdef DEF_MAP
- "-m " DEF_MAP
-#else
- "-M"
-#endif
- "\n"
- "\t\t\t-c %d\n" /* DEF_CODE_BYTES */
- "\t\t\tOops report is read from stdin\n"
- "\n",
- DEF_CODE_BYTES
- );
-}
-
-/* Check if possibly conflicting options were specified */
-static void multi_opt(int specl, int specu, char type, const char *using)
-{
- if (specl && specu) {
- fprintf(stderr,
- "Warning - you specified both -%c and -%c. Using '",
- type, toupper(type));
- ++warnings;
- if (using) {
- fprintf(stderr, "-%c %s", type, using);
- if (type == 'o')
- fprintf(stderr, " ...");
- fprintf(stderr, "'\n");
- }
- else
- fprintf(stderr, "-%c'\n", toupper(type));
- }
- else if (specl > 1 && type != 'o') {
- fprintf(stderr,
- "Warning - you specified -%c more than once. "
- "Using '-%c %s'\n",
- type, type, using);
- ++warnings;
- }
- else if (specu > 1) {
- fprintf(stderr,
- "Warning - you specified -%c more than once. "
- "Second and subsequent '-%c' ignored\n",
- toupper(type), toupper(type));
- ++warnings;
- }
-}
-
-/* If a name contains *r (*m, *n, *s), replace with the current value of
- * `uname -r` (-m, -n, -s). Actually uses uname system call rather than the
- * uname command but the result is the same.
- */
-static void convert_uname(char **name)
-{
- char *p, *newname, *oldname, *replacement;
- unsigned len;
- int free_oldname = 0;
- static char procname[] = "convert_uname";
-
- if (!*name)
- return;
-
- while ((p = strchr(*name, '*'))) {
- struct utsname buf;
- int i = uname(&buf);
- if (debug)
- fprintf(stderr, "DEBUG: %s %s in\n", procname, *name);
- if (i) {
- fprintf(stderr,
- "%s: uname failed, %s will not be processed\n",
- prefix, *name);
- perror(prefix);
- ++errors;
- return;
- }
- switch (*(p+1)) {
- case 'r':
- replacement = buf.release;
- break;
- case 'm':
- replacement = buf.machine;
- break;
- case 'n':
- replacement = buf.nodename;
- break;
- case 's':
- replacement = buf.sysname;
- break;
- default:
- fprintf(stderr,
- "%s: invalid replacement character '*%c' "
- "in %s\n",
- prefix, *(p+1), *name);
- ++errors;
- return;
- }
- len = strlen(*name)-2+strlen(replacement)+1;
- if (!(newname = malloc(len)))
- malloc_error(procname);
- strncpy(newname, *name, (p-*name));
- strcpy(newname+(p-*name), replacement);
- strcpy(newname+(p-*name)+strlen(replacement), p+2);
- p = newname+(p-*name)+strlen(replacement); /* no rescan */
- oldname = *name;
- *name = newname;
- if (free_oldname)
- free(oldname);
- free_oldname = 1;
- if (debug)
- fprintf(stderr, "DEBUG: %s %s out\n", procname, *name);
- }
- return;
-}
-
-/* Report if the option was specified or defaulted */
-static void spec_or_default(int spec, int *some_spec) {
- if (spec) {
- printf(" (specified)\n");
- if (some_spec)
- *some_spec = 1;
- }
- else
- printf(" (default)\n");
-}
-
-/* Parse the options. Verbose but what's new with getopt? */
-static void parse(int argc,
- char **argv,
- char **vmlinux,
- char ***object,
- int *objects,
- char **ksyms,
- char **lsmod,
- char **system_map,
- char **save_system_map,
- char ***filename,
- int *filecount,
- int *spec_h,
- int *code_bytes,
- int *one_shot
- )
-{
- int spec_v = 0, spec_V = 0;
- int spec_o = 0, spec_O = 0;
- int spec_k = 0, spec_K = 0;
- int spec_l = 0, spec_L = 0;
- int spec_m = 0, spec_M = 0;
- int spec_s = 0;
- int spec_c = 0;
-
- int c, i, some_spec = 0;
- char *p;
-
- while ((c = getopt(argc, argv, "v:Vo:Ok:Kl:Lm:Ms:dhc:1")) != EOF) {
- if (debug && c != 'd')
- fprintf(stderr, "DEBUG: getopt '%c' '%s'\n", c, optarg);
- switch(c) {
- case 'v':
- *vmlinux = optarg;
- ++spec_v;
- break;
- case 'V':
- *vmlinux = NULL;
- ++spec_V;
- break;
- case 'o':
- if (!spec_o) {
- /* First -o, discard default value(s) */
- for (i = 0; i < *objects; ++i)
- free((*object)[i]);
- free(*object);
- *object = NULL;
- *objects = 0;
- }
- *object = realloc(*object,
- ((*objects)+1)*sizeof(**object));
- if (!*object)
- malloc_error("object");
- if (!(p = strdup(optarg)))
- malloc_error("strdup -o");
- else {
- (*object)[(*objects)++] = p;
- ++spec_o;
- }
- break;
- case 'O':
- ++spec_O;
- for (i = 0; i < *objects; ++i)
- free((*object)[i]);
- free(*object);
- *object = NULL;
- *objects = 0;
- break;
- case 'k':
- *ksyms = optarg;
- ++spec_k;
- break;
- case 'K':
- *ksyms = NULL;
- ++spec_K;
- break;
- case 'l':
- *lsmod = optarg;
- ++spec_l;
- break;
- case 'L':
- *lsmod = NULL;
- ++spec_L;
- break;
- case 'm':
- *system_map = optarg;
- ++spec_m;
- break;
- case 'M':
- *system_map = NULL;
- ++spec_M;
- break;
- case 's':
- *save_system_map = optarg;
- ++spec_s;
- break;
- case 'd':
- ++debug;
- break;
- case 'h':
- usage();
- ++*spec_h;
- break;
- case 'c':
- ++spec_c;
- errno = 0;
- *code_bytes = strtoul(optarg, &p, 10);
- /* Oops_code_values assumes that code_bytes is a
- * multiple of 2.
- */
- if (!*optarg || *p || errno ||
- (*code_bytes != 1 &&
- *code_bytes != 2 &&
- *code_bytes != 4 &&
- *code_bytes != 8)) {
- fprintf(stderr,
- "%s Invalid value for -c '%s'\n",
- prefix, optarg);
- ++errors;
- if (errno)
- perror(" ");
- *code_bytes = DEF_CODE_BYTES;
- }
- break;
- case '1':
- *one_shot = !*one_shot;
- break;
- case '?':
- usage();
- exit(2);
- }
- }
-
- *filecount = argc - optind;
- *filename = argv + optind;
-
- /* Expand any requests for the current uname values */
- convert_uname(vmlinux);
- if (*objects) {
- for (i = 0; i < *objects; ++i)
- convert_uname(*object+i);
- }
- convert_uname(ksyms);
- convert_uname(lsmod);
- convert_uname(system_map);
-
- /* Check for multiple options specified */
- multi_opt(spec_v, spec_V, 'v', *vmlinux);
- multi_opt(spec_o, spec_O, 'o', *object ? **object : NULL);
- multi_opt(spec_k, spec_K, 'k', *ksyms);
- multi_opt(spec_l, spec_L, 'l', *lsmod);
- multi_opt(spec_m, spec_M, 'm', *system_map);
-
- printf("Options used:");
- if (*vmlinux)
- printf(" -v %s", *vmlinux);
- else
- printf(" -V");
- spec_or_default(spec_v || spec_V, &some_spec);
-
- printf(" ");
- if (*objects) {
- for (i = 0; i < *objects; ++i)
- printf(" -o %s", (*object)[i]);
- }
- else
- printf(" -O");
- spec_or_default(spec_o || spec_O, &some_spec);
-
- printf(" ");
- if (*ksyms)
- printf(" -k %s", *ksyms);
- else
- printf(" -K");
- spec_or_default(spec_k || spec_K, &some_spec);
-
- printf(" ");
- if (*lsmod)
- printf(" -l %s", *lsmod);
- else
- printf(" -L");
- spec_or_default(spec_l || spec_L, &some_spec);
-
- printf(" ");
- if (*system_map)
- printf(" -m %s", *system_map);
- else
- printf(" -M");
- spec_or_default(spec_m || spec_M, &some_spec);
-
- printf(" ");
- printf(" -c %d", *code_bytes);
- spec_or_default(spec_c, NULL);
-
- if (*one_shot) {
- printf(" ");
- printf(" -1");
- }
-
- printf("\n");
-
- if (!some_spec) {
- printf(
-"You did not tell me where to find symbol information. I will assume\n"
-"that the log matches the kernel and modules that are running right now\n"
-"and I'll use the default options above for symbol resolution.\n"
-"If the current kernel and/or modules do not match the log, you can get\n"
-"more accurate output by telling me the kernel version and where to find\n"
-"map, modules, ksyms etc. ksymoops -h explains the options.\n"
- "\n");
- ++warnings;
- }
-}
-
-/* Read environment variables */
-static void read_env(const char *external, char **internal)
-{
- char *p;
- if ((p = getenv(external))) {
- *internal = p;
- if (debug)
- fprintf(stderr,
- "DEBUG: env override %s=%s\n",
- external, *internal);
- }
- else {
- if (debug)
- fprintf(stderr,
- "DEBUG: env default %s=%s\n",
- external, *internal);
- }
-}
-
-
-int main(int argc, char **argv)
-{
- char *vmlinux = NULL;
- char **object = NULL;
- int objects = 0;
- char *ksyms = NULL;
- char *lsmod = NULL;
- char *system_map = NULL;
- char *save_system_map = NULL;
- char **filename;
- int filecount = 0;
- int spec_h = 0; /* -h was specified */
- int code_bytes = DEF_CODE_BYTES;
- int one_shot = 0;
- int i, ret;
-
- prefix = *argv;
- setvbuf(stdout, NULL, _IONBF, 0);
-
-#ifdef DEF_VMLINUX
- vmlinux = DEF_LINUX;
-#endif
-#ifdef DEF_OBJECTS
- {
- char *p;
- object = realloc(object, (objects+1)*sizeof(*object));
- if (!object)
- malloc_error("DEF_OBJECTS");
- if (!(p = strdup(DEF_OBJECTS)))
- malloc_error("DEF_OBJECTS");
- else
- object[objects++] = p;
- }
-#endif
-#ifdef DEF_KSYMS
- ksyms = DEF_KSYMS;
-#endif
-#ifdef DEF_LSMOD
- lsmod = DEF_LSMOD;
-#endif
-#ifdef DEF_MAP
- system_map = DEF_MAP;
-#endif
-
- parse(argc,
- argv,
- &vmlinux,
- &object,
- &objects,
- &ksyms,
- &lsmod,
- &system_map,
- &save_system_map,
- &filename,
- &filecount,
- &spec_h,
- &code_bytes,
- &one_shot
- );
-
- if (spec_h && filecount == 0)
- return(0); /* just the help text */
-
- if (errors)
- return(1);
-
- if (debug)
- fprintf(stderr, "DEBUG: level %d\n", debug);
-
- read_env("KSYMOOPS_NM", &path_nm);
- read_env("KSYMOOPS_FIND", &path_find);
- read_env("KSYMOOPS_OBJDUMP", &path_objdump);
-
- re_compile_common();
- ss_init_common();
-
- read_vmlinux(vmlinux);
- read_ksyms(ksyms);
- /* No point in reading modules unless ksyms shows modules loaded */
- if (ss_ksyms_modules) {
- expand_objects(object, objects);
- for (i = 0; i < ss_objects; ++i)
- read_object(ss_object[i].source, i);
- }
- else if (objects)
- printf("No modules in ksyms, skipping objects\n");
- /* No point in reading lsmod without ksyms */
- if (ss_ksyms_modules || ss_ksyms_base.used)
- read_lsmod(lsmod);
- else if (lsmod)
- printf("No ksyms, skipping lsmod\n");
- read_system_map(system_map);
- merge_maps(save_system_map);
-
- /* After all that work, it is finally time to read the Oops report */
- ret = Oops_read(filecount, filename, code_bytes, one_shot);
-
- if (warnings || errors) {
- printf("\n");
- if (warnings)
- printf("%d warning%s ",
- warnings, warnings == 1 ? "" : "s");
- if (warnings && errors)
- printf("and ");
- if (errors)
- printf("%d error%s ", errors, errors == 1 ? "" : "s");
- printf("issued. Results may not be reliable.\n");
- if (!ret)
- return(1);
- }
-
- return(ret);
-}
diff --git a/scripts/ksymoops/ksymoops.h b/scripts/ksymoops/ksymoops.h
deleted file mode 100644
index fb3e99d8f..000000000
--- a/scripts/ksymoops/ksymoops.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- ksymoops.h.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- Read lsmod (/proc/modules).
- Convert from a.out to bfd, using same format as ksymoops.
- PPC trace addresses are not bracketed, add new re.
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into separate sources.
-*/
-
-#include <sys/types.h>
-#include <regex.h>
-#include <stdio.h>
-
-
-/* Pity this is not externalised, see binfmt_elf.c */
-#define elf_addr_t unsigned long
-
-extern char *prefix;
-extern char *path_nm; /* env KSYMOOPS_NM */
-extern char *path_find; /* env KSYMOOPS_FIND */
-extern char *path_objdump; /* env KSYMOOPS_OBJDUMP */
-extern int debug;
-extern int errors;
-extern int warnings;
-
-typedef struct symbol SYMBOL;
-
-struct symbol {
- char *name; /* name of symbol */
- char type; /* type of symbol from nm/System.map */
- char keep; /* keep this symbol in merged map? */
- elf_addr_t address; /* address in kernel */
-};
-
-/* Header for symbols from one particular source */
-
-typedef struct symbol_set SYMBOL_SET;
-
-struct symbol_set {
- char *source; /* where the symbols came from */
- int used; /* number of symbols used */
- int alloc; /* number of symbols allocated */
- SYMBOL *symbol; /* dynamic array of symbols */
- SYMBOL_SET *related; /* any related symbol set */
-};
-
-extern SYMBOL_SET ss_vmlinux;
-extern SYMBOL_SET ss_ksyms_base;
-extern SYMBOL_SET *ss_ksyms_module;
-extern int ss_ksyms_modules;
-extern SYMBOL_SET ss_lsmod;
-extern SYMBOL_SET *ss_object;
-extern int ss_objects;
-extern SYMBOL_SET ss_system_map;
-
-extern SYMBOL_SET ss_merged; /* merged map with info from all sources */
-extern SYMBOL_SET ss_Version; /* Version_ numbers where available */
-
-/* Regular expression stuff */
-
-extern regex_t re_nm;
-extern regmatch_t *re_nm_pmatch;
-extern regex_t re_bracketed_address;
-extern regmatch_t *re_bracketed_address_pmatch;
-extern regex_t re_unbracketed_address;
-extern regmatch_t *re_unbracketed_address_pmatch;
-
-/* Bracketed address: optional '[', required '<', at least 4 hex characters,
- * required '>', optional ']', optional white space.
- */
-#define BRACKETED_ADDRESS "\\[*<([0-9a-fA-F]{4,})>\\]*[ \t]*"
-
-#define UNBRACKETED_ADDRESS "([0-9a-fA-F]{4,})[ \t]*"
-
-/* io.c */
-extern int regular_file(const char *file, const char *msg);
-extern FILE *fopen_local(const char *file, const char *mode, const char *msg);
-extern void fclose_local(FILE *f, const char *msg);
-extern char *fgets_local(char **line, int *size, FILE *f, const char *msg);
-extern int fwrite_local(void const *ptr, size_t size, size_t nmemb,
- FILE *stream, const char *msg);
-extern FILE *popen_local(const char *cmd, const char *msg);
-extern void pclose_local(FILE *f, const char *msg);
-
-/* ksyms.c */
-extern void read_ksyms(const char *ksyms);
-extern void map_ksyms_to_modules(void);
-extern void read_lsmod(const char *lsmod);
-extern void compare_ksyms_lsmod(void);
-
-/* misc.c */
-extern void malloc_error(const char *msg);
-extern const char *format_address(elf_addr_t address);
-extern char *find_fullpath(const char *program);
-
-/* map.c */
-extern void read_system_map(const char *system_map);
-extern void merge_maps(const char *save_system_map);
-extern void compare_maps(const SYMBOL_SET *ss1, const SYMBOL_SET *ss2,
- int precedence);
-
-
-/* object.c */
-extern SYMBOL_SET *adjust_object_offsets(SYMBOL_SET *ss);
-extern void read_vmlinux(const char *vmlinux);
-extern void expand_objects(char * const *object, int objects);
-extern void read_object(const char *object, int i);
-
-/* oops.c */
-extern int Oops_read(int filecount, char * const *filename, int code_bytes,
- int one_shot);
-
-/* re.c */
-extern void re_compile(regex_t *preg, const char *regex, int cflags,
- regmatch_t **pmatch);
-extern void re_compile_common(void);
-extern void re_strings(regex_t *preg, const char *text, regmatch_t *pmatch,
- char ***string);
-extern void re_strings_free(const regex_t *preg, char ***string);
-extern void re_string_check(int need, int available, const char *msg);
-
-/* symbol.c */
-extern void ss_init(SYMBOL_SET *ss, const char *msg);
-extern void ss_free(SYMBOL_SET *ss);
-extern void ss_init_common(void);
-extern SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol,
- int *start);
-extern void add_symbol_n(SYMBOL_SET *ss, const elf_addr_t address,
- const char type, const char keep, const char *symbol);
-extern void add_symbol(SYMBOL_SET *ss, const char *address, const char type,
- const char keep, const char *symbol);
-extern char *map_address(const SYMBOL_SET *ss, const elf_addr_t address);
-extern void ss_sort_atn(SYMBOL_SET *ss);
-extern void ss_sort_na(SYMBOL_SET *ss);
-extern SYMBOL_SET *ss_copy(const SYMBOL_SET *ss);
-extern void add_Version(const char *version, const char *source);
-extern void extract_Version(SYMBOL_SET *ss);
-extern void compare_Version(void);
diff --git a/scripts/ksymoops/ksyms.c b/scripts/ksymoops/ksyms.c
deleted file mode 100644
index 608254ad3..000000000
--- a/scripts/ksymoops/ksyms.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- ksyms.c.
-
- Process ksyms for ksymoops.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Fri Nov 6 10:38:42 EST 1998
- Version 0.6b
- Remove false warnings when comparing ksyms and lsmod.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- Read lsmod (/proc/modules).
- Move "Using_Version" copy to map.c.
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-#include <string.h>
-
-/* Scan one line from ksyms. Split lines into the base symbols and the module
- * symbols. Separate ss for base and each module.
- */
-static void scan_ksyms_line(const char *line)
-{
- int i;
- char **string = NULL;
- SYMBOL_SET *ssp;
- static char *prev_module = NULL;
- static regex_t re_ksyms;
- static regmatch_t *re_ksyms_pmatch;
- static char const procname[] = "scan_ksyms_line";
-
- /* ksyms: address, symbol, optional module */
- re_compile(&re_ksyms,
- "^([0-9a-fA-F]{4,}) +([^ \t]+)([ \t]+\\[([^ ]+)\\])?$",
- REG_NEWLINE|REG_EXTENDED,
- &re_ksyms_pmatch);
-
- i = regexec(&re_ksyms, line,
- re_ksyms.re_nsub+1, re_ksyms_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i)
- return;
-
- /* string [1] - address, [2] - symbol, [3] - white space+module,
- * [4] - module.
- */
- re_strings(&re_ksyms, line, re_ksyms_pmatch, &string);
- if (string[4]) {
- if (!prev_module || strcmp(prev_module, string[4])) {
- /* start of a new module in ksyms */
- ++ss_ksyms_modules;
- ss_ksyms_module = realloc(ss_ksyms_module,
- ss_ksyms_modules*sizeof(*ss_ksyms_module));
- if (!ss_ksyms_module)
- malloc_error("realloc ss_ksyms_module");
- ssp = ss_ksyms_module+ss_ksyms_modules-1;
- ss_init(ssp, string[4]);
- prev_module = strdup(string[4]);
- if (!prev_module)
- malloc_error("strdup prev_module");
- }
- ssp = ss_ksyms_module+ss_ksyms_modules-1;
- }
- else
- ssp = &ss_ksyms_base;
- add_symbol(ssp, string[1], ' ', 1, string[2]);
- re_strings_free(&re_ksyms, &string);
-}
-
-/* Read the symbols from ksyms. */
-void read_ksyms(const char *ksyms)
-{
- FILE *f;
- char *line = NULL;
- int i, size;
- static char const procname[] = "read_ksyms";
-
- if (!ksyms)
- return;
- ss_init(&ss_ksyms_base, "ksyms_base");
- if (debug)
- fprintf(stderr, "DEBUG: %s %s\n", procname, ksyms);
-
- if (!regular_file(ksyms, procname))
- return;
-
- if (!(f = fopen_local(ksyms, "r", procname)))
- return;
-
- while (fgets_local(&line, &size, f, procname))
- scan_ksyms_line(line);
-
- fclose_local(f, procname);
- free(line);
-
- for (i = 0; i < ss_ksyms_modules; ++i) {
- ss_sort_na(ss_ksyms_module+i);
- extract_Version(ss_ksyms_module+i);
- }
- if (ss_ksyms_base.used) {
- ss_sort_na(&ss_ksyms_base);
- extract_Version(&ss_ksyms_base);
- }
- else {
- fprintf(stderr,
- "Warning, no kernel symbols in ksyms, is %s a valid "
- "ksyms file?\n",
- ksyms);
- ++warnings;
- }
-
- if (debug > 1) {
- for (i = 0; i < ss_ksyms_modules; ++i) {
- fprintf(stderr,
- "DEBUG: %s %s used %d out of %d entries\n",
- procname,
- ss_ksyms_module[i].source,
- ss_ksyms_module[i].used,
- ss_ksyms_module[i].alloc);
- }
- fprintf(stderr,
- "DEBUG: %s %s used %d out of %d entries\n",
- procname, ss_ksyms_base.source, ss_ksyms_base.used,
- ss_ksyms_base.alloc);
- }
-}
-
-/* Map each ksyms module entry to the corresponding object entry. Tricky,
- * see the comments in the docs about needing a unique symbol in each
- * module.
- */
-static void map_ksym_to_module(SYMBOL_SET *ss)
-{
- int i, j, matches;
- char *name = NULL;
-
- for (i = 0; i < ss->used; ++i) {
- matches = 0;
- for (j = 0; j < ss_objects; ++j) {
- name = (ss->symbol)[i].name;
- if (find_symbol_name(ss_object+j, name, NULL)) {
- ++matches;
- ss->related = ss_object+j;
- }
- }
- if (matches == 1)
- break; /* unique symbol over all objects */
- ss->related = NULL; /* keep looking */
- }
- if (!(ss->related)) {
- fprintf(stderr,
- "Warning: cannot match loaded module %s to any "
- "module object. Trace may not be reliable.\n",
- ss->source);
- ++warnings;
- }
- else if (debug)
- fprintf(stderr,
- "DEBUG: ksyms %s matches to %s based on unique "
- "symbol %s\n",
- ss->source, ss->related->source, name);
-}
-
-/* Map all ksyms module entries to their corresponding objects */
-void map_ksyms_to_modules(void)
-{
- int i;
- SYMBOL_SET *ss, *ssc;
-
- for (i = 0; i < ss_ksyms_modules; ++i) {
- ss = ss_ksyms_module+i;
- map_ksym_to_module(ss);
- if (ss->related) {
- ssc = adjust_object_offsets(ss);
- compare_maps(ss, ssc, 1);
- }
- }
-}
-
-/* Read the modules from lsmod. */
-void read_lsmod(const char *lsmod)
-{
- FILE *f;
- char *line = NULL;
- int i, size;
- char **string = NULL;
- static regex_t re_lsmod;
- static regmatch_t *re_lsmod_pmatch;
- static char const procname[] = "read_lsmod";
-
- if (!lsmod)
- return;
- ss_init(&ss_lsmod, "lsmod");
- if (debug)
- fprintf(stderr, "DEBUG: %s %s\n", procname, lsmod);
-
- if (!regular_file(lsmod, procname))
- return;
-
- if (!(f = fopen_local(lsmod, "r", procname)))
- return;
-
- /* lsmod: module, size, use count, optional used by */
- re_compile(&re_lsmod,
- "^"
- "[ \t]*([^ \t]+)" /* 1 module */
- "[ \t]*([^ \t]+)" /* 2 size */
- "[ \t]*([^ \t]+)" /* 3 count */
- "[ \t]*(.*)" /* 4 used by */
- "$",
- REG_NEWLINE|REG_EXTENDED,
- &re_lsmod_pmatch);
-
- while (fgets_local(&line, &size, f, procname)) {
- i = regexec(&re_lsmod, line,
- re_lsmod.re_nsub+1, re_lsmod_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i)
- continue;
- re_strings(&re_lsmod, line, re_lsmod_pmatch, &string);
- add_symbol(&ss_lsmod, string[2], ' ', 1, string[1]);
- }
-
- fclose_local(f, procname);
- free(line);
- re_strings_free(&re_lsmod, &string);
- if (ss_lsmod.used)
- ss_sort_na(&ss_lsmod);
- else {
- fprintf(stderr,
- "Warning, no symbols in lsmod, is %s a valid "
- "lsmod file?\n",
- lsmod);
- ++warnings;
- }
-
- if (debug > 1)
- fprintf(stderr,
- "DEBUG: %s %s used %d out of %d entries\n",
- procname, ss_lsmod.source, ss_lsmod.used,
- ss_lsmod.alloc);
-}
-
-/* Compare modules from ksyms against module list in lsmod and vice versa.
- * There is one ss_ for each ksyms module and a single ss_lsmod to cross
- * check.
- */
-void compare_ksyms_lsmod(void)
-{
- int i, j;
- SYMBOL_SET *ss;
- SYMBOL *s;
- static char const procname[] = "compare_ksyms_lsmod";
-
- if (!(ss_lsmod.used && ss_ksyms_modules))
- return;
-
- s = ss_lsmod.symbol;
- for (i = 0; i < ss_lsmod.used; ++i, ++s) {
- for (j = 0; j < ss_ksyms_modules; ++j) {
- ss = ss_ksyms_module+j;
- if (strcmp(s->name, ss->source) == 0)
- break;
- }
- if (j >= ss_ksyms_modules) {
- fprintf(stderr,
- "Warning in %s, module %s is in lsmod but not "
- "in ksyms, probably no symbols exported\n",
- procname, s->name);
- ++warnings;
- }
- }
-
- for (i = 0; i < ss_ksyms_modules; ++i) {
- ss = ss_ksyms_module+i;
- if (!find_symbol_name(&ss_lsmod, ss->source, NULL)) {
- fprintf(stderr,
- "Error in %s, module %s is in ksyms but not "
- "in lsmod\n",
- procname, ss->source);
- ++errors;
- }
- }
-}
diff --git a/scripts/ksymoops/map.c b/scripts/ksymoops/map.c
deleted file mode 100644
index 6f91e9daf..000000000
--- a/scripts/ksymoops/map.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- map.c.
-
- Read System.map for ksymoops, create merged System.map.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- Remove addresses 0-4095 from merged map after writing new map.
- Move "Using_Version" copy to map.c.
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-
-/* Read the symbols from System.map */
-void read_system_map(const char *system_map)
-{
- FILE *f;
- char *line = NULL, **string = NULL;
- int i, size = 0;
- static char const procname[] = "read_system_map";
-
- if (!system_map)
- return;
- ss_init(&ss_system_map, "System.map");
- if (debug)
- fprintf(stderr, "DEBUG: %s %s\n", procname, system_map);
-
- if (!regular_file(system_map, procname))
- return;
-
- if (!(f = fopen_local(system_map, "r", procname)))
- return;
-
- while (fgets_local(&line, &size, f, procname)) {
- i = regexec(&re_nm, line, re_nm.re_nsub+1, re_nm_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i == 0) {
- re_strings(&re_nm, line, re_nm_pmatch, &string);
- add_symbol(&ss_system_map, string[1], *string[2],
- 1, string[3]);
- }
- }
-
- fclose_local(f, procname);
- re_strings_free(&re_nm, &string);
- free(line);
- if (ss_system_map.used) {
- ss_sort_na(&ss_system_map);
- extract_Version(&ss_system_map);
- }
- else {
- fprintf(stderr,
- "Warning, no kernel symbols in System.map, is %s a "
- "valid System.map file?\n",
- system_map);
- ++warnings;
- }
-
- if (debug > 1)
- fprintf(stderr,
- "DEBUG: %s %s used %d out of %d entries\n",
- procname,
- ss_system_map.source,
- ss_system_map.used,
- ss_system_map.alloc);
-}
-
-/* Compare two maps, all symbols in the first should appear in the second. */
-void compare_maps(const SYMBOL_SET *ss1, const SYMBOL_SET *ss2,
- int precedence)
-{
- int i, start = 0;
- SYMBOL *s1, *s2, **sdrop = precedence == 1 ? &s2 : &s1;
- const SYMBOL_SET **ssdrop = precedence == 1 ? &ss2 : &ss1;
-
- if (!(ss1->used && ss2->used))
- return;
-
- if (debug > 1)
- fprintf(stderr,
- "DEBUG: compare_maps %s vs %s, %s takes precedence\n",
- ss1->source, ss2->source,
- precedence == 1 ? ss1->source : ss2->source);
-
- for (i = 0; i < ss1->used; ++i) {
- s1 = ss1->symbol+i;
- if (!(s1->keep))
- continue;
- s2 = find_symbol_name(ss2, s1->name, &start);
- if (!s2) {
- /* Some types only appear in nm output, not in things
- * like System.map. Silently ignore them.
- */
- if (s1->type == 'a' || s1->type == 't')
- continue;
- fprintf(stderr,
- "Warning: %s symbol %s not found in %s. "
- "Ignoring %s entry\n",
- ss1->source, s1->name,
- ss2->source, (*ssdrop)->source);
- ++warnings;
- if (*sdrop)
- (*sdrop)->keep = 0;
- }
- else if (s1->address != s2->address) {
- /* Type C symbols cannot be resolved from nm to ksyms,
- * silently ignore them.
- */
- if (s1->type == 'C' || s2->type == 'C')
- continue;
- fprintf(stderr,
- "Warning: mismatch on symbol %s %c, "
- "%s says %lx, %s says %lx. "
- "Ignoring %s entry\n",
- s1->name, s1->type, ss1->source, s1->address,
- ss2->source, s2->address, (*ssdrop)->source);
- ++warnings;
- if (*sdrop)
- (*sdrop)->keep = 0;
- }
- else
- ++start; /* step to next entry in ss2 */
- }
-}
-
-/* Append the second symbol set onto the first */
-static void append_map(SYMBOL_SET *ss1, const SYMBOL_SET *ss2)
-{
- int i;
- SYMBOL *s;
-
- if (!ss2 || !ss2->used)
- return;
- if (debug > 1)
- fprintf(stderr, "DEBUG: append_map %s to %s\n",
- ss2->source, ss1->source);
-
- for (i = 0; i < ss2->used; ++i) {
- s = ss2->symbol+i;
- if (s->keep)
- add_symbol_n(ss1, s->address, s->type, 1,
- s->name);
- }
-}
-
-/* Compare the various sources and build a merged system map */
-void merge_maps(const char *save_system_map)
-{
- int i;
- SYMBOL *s;
- FILE *f;
- static char const procname[] = "merge_maps";
-
- if (debug)
- fprintf(stderr, "DEBUG: %s\n", procname);
-
- /* Using_Versions only appears in ksyms, copy to other tables */
- if ((s = find_symbol_name(&ss_ksyms_base,
- "Using_Versions", 0))) {
- if (ss_system_map.used) {
- add_symbol_n(&ss_system_map, s->address,
- s->type, s->keep, s->name);
- ss_sort_na(&ss_system_map);
- }
- if (ss_vmlinux.used) {
- add_symbol_n(&ss_vmlinux, s->address, s->type,
- s->keep, s->name);
- ss_sort_na(&ss_vmlinux);
- }
- }
-
- compare_Version(); /* highlight any version problems first */
- compare_ksyms_lsmod(); /* highlight any missing modules next */
- compare_maps(&ss_ksyms_base, &ss_vmlinux, 2);
- compare_maps(&ss_system_map, &ss_vmlinux, 2);
- compare_maps(&ss_vmlinux, &ss_system_map, 1);
- compare_maps(&ss_ksyms_base, &ss_system_map, 2);
-
- if (ss_objects) {
- map_ksyms_to_modules();
- }
-
- ss_init(&ss_merged, "merged");
- append_map(&ss_merged, &ss_vmlinux);
- append_map(&ss_merged, &ss_ksyms_base);
- append_map(&ss_merged, &ss_system_map);
- for (i = 0; i < ss_ksyms_modules; ++i)
- append_map(&ss_merged, (ss_ksyms_module+i)->related);
- if (!ss_merged.used) {
- fprintf(stderr, "Warning, no symbols in merged map\n");
- ++warnings;
- }
-
- /* drop duplicates, type a (registers) and gcc2_compiled. */
- ss_sort_atn(&ss_merged);
- s = ss_merged.symbol;
- for (i = 0; i < ss_merged.used-1; ++i) {
- if (s->type == 'a' ||
- (s->type == 't' && !strcmp(s->name, "gcc2_compiled.")))
- s->keep = 0;
- else if (strcmp(s->name, (s+1)->name) == 0 &&
- s->address == (s+1)->address) {
- if (s->type != ' ')
- (s+1)->keep = 0;
- else
- s->keep = 0;
- }
- ++s;
- }
- ss_sort_atn(&ss_merged); /* will remove dropped variables */
-
- if (save_system_map) {
- if (debug)
- fprintf(stderr, "DEBUG: writing merged map to %s\n",
- save_system_map);
- if (!(f = fopen_local(save_system_map, "w", procname)))
- return;
- s = ss_merged.symbol;
- for (i = 0; i < ss_merged.used; ++i) {
- if (s->keep)
- fprintf(f, "%s %c %s\n",
- format_address(s->address),
- s->type, s->name);
- ++s;
- }
- }
-
- /* The merged map may contain symbols with an address of 0, e.g.
- * Using_Versions. These give incorrect results for low addresses in
- * map_address, such addresses map to "Using_Versions+xxx". Remove
- * any addresses below (arbitrary) 4096 from the merged map. AFAIK,
- * Linux does not use the first page on any arch.
- */
- for (i = 0; i < ss_merged.used; ++i) {
- if ((ss_merged.symbol+i)->address < 4096)
- (ss_merged.symbol+i)->keep = 0;
- else
- break;
- }
- if (i)
- ss_sort_atn(&ss_merged); /* remove dropped variables */
-}
diff --git a/scripts/ksymoops/misc.c b/scripts/ksymoops/misc.c
deleted file mode 100644
index 7876f7e41..000000000
--- a/scripts/ksymoops/misc.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- misc.c.
-
- Miscellaneous routines for ksymoops.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- Convert from a.out to bfd, using same format as ksymoops.
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-void malloc_error(const char *msg)
-{
- fprintf(stderr, "%s: fatal malloc error for %s\n", prefix, msg);
- exit(2);
-}
-
-/* Format an address with the correct number of leading zeroes */
-const char *format_address(elf_addr_t address)
-{
- /* Well oversized */
- static char format[10], text[200];
- if (!*format)
- snprintf(format, sizeof(format), "%%0%dlx",
- 2*sizeof(address));
- snprintf(text, sizeof(text), format, address);
- return(text);
-}
-
-/* Find the full pathname of a program. Code heavily based on
- * glibc-2.0.5/posix/execvp.c.
- */
-char *find_fullpath(const char *program)
-{
- char *fullpath = NULL;
- char *path, *p;
- size_t len;
- static const char procname[] = "find_fullpath";
-
- /* Don't search when it contains a slash. */
- if (strchr(program, '/')) {
- if (!(fullpath = strdup(program)))
- malloc_error(procname);
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s %s\n", procname, fullpath);
- return(fullpath);
- }
-
- path = getenv ("PATH");
- if (!path) {
- /* There is no `PATH' in the environment. The default search
- path is the current directory followed by the path `confstr'
- returns for `_CS_PATH'.
- */
- len = confstr(_CS_PATH, (char *) NULL, 0);
- if (!(path = malloc(1 + len)))
- malloc_error(procname);
- path[0] = ':';
- confstr(_CS_PATH, path+1, len);
- }
-
- len = strlen(program) + 1;
- if (!(fullpath = malloc(strlen(path) + len)))
- malloc_error(procname);
- p = path;
- do {
- path = p;
- p = strchr(path, ':');
- if (p == NULL)
- p = strchr(path, '\0');
-
- /* Two adjacent colons, or a colon at the beginning or the end
- * of `PATH' means to search the current directory.
- */
- if (p == path)
- memcpy(fullpath, program, len);
- else {
- /* Construct the pathname to try. */
- memcpy(fullpath, path, p - path);
- fullpath[p - path] = '/';
- memcpy(&fullpath[(p - path) + 1], program, len);
- }
-
- /* If we have execute access, assume this is the program. */
- if (access(fullpath, X_OK) == 0) {
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s %s\n",
- procname, fullpath);
- return(fullpath);
- }
- } while (*p++ != '\0');
-
- fprintf(stderr, "Error: %s %s could not find executable %s\n",
- prefix, procname, program);
- ++errors;
- return(NULL);
-}
diff --git a/scripts/ksymoops/object.c b/scripts/ksymoops/object.c
deleted file mode 100644
index 7a44e4c35..000000000
--- a/scripts/ksymoops/object.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- object.c.
-
- object handling routines for ksymoops. Read modules, vmlinux, etc.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-#include <string.h>
-#include <sys/stat.h>
-
-/* Extract all symbols definitions from an object using nm */
-static void read_nm_symbols(SYMBOL_SET *ss, const char *file)
-{
- FILE *f;
- char *cmd, *line = NULL, **string = NULL;
- int i, size = 0;
- static char const procname[] = "read_nm_symbols";
-
- if (!regular_file(file, procname))
- return;
-
- cmd = malloc(strlen(path_nm)+strlen(file)+2);
- if (!cmd)
- malloc_error("nm command");
- strcpy(cmd, path_nm);
- strcat(cmd, " ");
- strcat(cmd, file);
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
- if (!(f = popen_local(cmd, procname)))
- return;
- free(cmd);
-
- while (fgets_local(&line, &size, f, procname)) {
- i = regexec(&re_nm, line, re_nm.re_nsub+1, re_nm_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i == 0) {
- re_strings(&re_nm, line, re_nm_pmatch, &string);
- add_symbol(ss, string[1], *string[2], 1, string[3]);
- }
- }
-
- pclose_local(f, procname);
- re_strings_free(&re_nm, &string);
- free(line);
- if (debug > 1)
- fprintf(stderr,
- "DEBUG: %s %s used %d out of %d entries\n",
- procname, ss->source, ss->used, ss->alloc);
-}
-
-/* Read the symbols from vmlinux */
-void read_vmlinux(const char *vmlinux)
-{
- if (!vmlinux)
- return;
- ss_init(&ss_vmlinux, "vmlinux");
- read_nm_symbols(&ss_vmlinux, vmlinux);
- if (ss_vmlinux.used) {
- ss_sort_na(&ss_vmlinux);
- extract_Version(&ss_vmlinux);
- }
- else {
- fprintf(stderr,
- "Warning, no kernel symbols in vmlinux, is %s a valid "
- "vmlinux file?\n",
- vmlinux);
- ++warnings;
- }
-}
-
-
-/* Read the symbols from one object (module) */
-void read_object(const char *object, int i)
-{
- ss_init(ss_object+i, object);
- read_nm_symbols(ss_object+i, object);
- if ((ss_object+i)->used) {
- ss_sort_na(ss_object+i);
- extract_Version(ss_object+i);
- }
- else {
- fprintf(stderr, "Warning, no symbols in %s\n", object);
- ++warnings;
- }
-}
-
-/* Add a new entry to the list of objects */
-static void add_ss_object(const char *file)
-{
- ++ss_objects;
- ss_object = realloc(ss_object, ss_objects*sizeof(*ss_object));
- if (!ss_object)
- malloc_error("realloc ss_object");
- ss_init(ss_object+ss_objects-1, file);
-}
-
-/* Run a directory and its subdirectories, looking for *.o files */
-static void find_objects(const char *dir)
-{
- FILE *f;
- char *cmd, *line = NULL;
- int size = 0, files = 0;
- static char const procname[] = "find_objects";
- static char const options[] = " -follow -name '*.o' -print";
-
- cmd = malloc(strlen(path_find)+1+strlen(dir)+strlen(options)+1);
- if (!cmd)
- malloc_error("find command");
- strcpy(cmd, path_find);
- strcat(cmd, " ");
- strcat(cmd, dir);
- strcat(cmd, options);
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
- if (!(f = popen_local(cmd, procname)))
- return;
- free(cmd);
-
- while (fgets_local(&line, &size, f, procname)) {
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s - %s\n", procname, line);
- add_ss_object(line);
- ++files;
- }
-
- pclose_local(f, procname);
- if (!files) {
- fprintf(stderr,
- "Warning: no *.o files in %s. "
- "Is %s a valid module directory?\n",
- dir, dir);
- ++warnings;
- }
-}
-
-/* Take the user supplied list of objects which can include directories.
- * Expand directories into any *.o files. The results are stored in
- * ss_object, leaving the user supplied options untouched.
- */
-void expand_objects(char * const *object, int objects)
-{
- struct stat statbuf;
- int i;
- const char *file;
- static char const procname[] = "expand_objects";
-
- for (i = 0; i < objects; ++i) {
- file = object[i];
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s checking '%s' - ",
- procname, file);
- if (!stat(file, &statbuf) && S_ISDIR(statbuf.st_mode)) {
- if (debug > 1)
- fprintf(stderr, "directory, expanding\n");
- find_objects(file);
- }
- else {
- if (debug > 1)
- fprintf(stderr, "not directory\n");
- add_ss_object(file);
- }
- }
-}
-
-/* Map a symbol type to a section code. 0 - text, 1 - data, 2 - read only data,
- * 3 - C (cannot relocate), 4 - the rest.
- */
-static int section(char type)
-{
- switch (type) {
- case 'T':
- case 't':
- return 0;
- case 'D':
- case 'd':
- return 1;
- case 'R':
- case 'r':
- return 2;
- case 'C':
- return 3;
- default:
- return 4;
- }
-}
-
-/* Given ksyms module data which has a related object, create a copy of the
- * object data, adjusting the offsets to match where the module was loaded.
- */
-SYMBOL_SET *adjust_object_offsets(SYMBOL_SET *ss)
-{
- int i;
- elf_addr_t adjust[] = {0, 0, 0, 0, 0};
- SYMBOL *sk, *so;
- SYMBOL_SET *ssc;
-
- if (debug > 1)
- fprintf(stderr,
- "DEBUG: adjust_object_offsets %s\n", ss->source);
-
- ssc = ss_copy(ss->related);
-
- /* For common symbols, calculate the adjustment */
- for (i = 0; i < ss->used; ++i) {
- sk = ss->symbol+i;
- if ((so = find_symbol_name(ssc, sk->name, NULL)))
- adjust[section(so->type)] = sk->address - so->address;
- }
- for (i = 0; i < ssc->used; ++i) {
- so = ssc->symbol+i;
- /* Type C does not relocate well, silently ignore */
- if (so->type != 'C' && adjust[section(so->type)])
- so->address += adjust[section(so->type)];
- else
- so->keep = 0; /* do not merge into final map */
- }
-
- ss->related = ssc; /* map using adjusted copy */
- return(ssc);
-}
diff --git a/scripts/ksymoops/oops.c b/scripts/ksymoops/oops.c
deleted file mode 100644
index 61107b144..000000000
--- a/scripts/ksymoops/oops.c
+++ /dev/null
@@ -1,1377 +0,0 @@
-/*
- oops.c.
-
- Oops processing for ksymoop.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Sun Jan 7 12:56:12 CET 1999
- Added SPARC64 support and some SPARC hacks by "Jakub Jelinek"
- <jj@ultra.linux.cz>
-
- Mon Jan 4 08:47:55 EST 1999
- Version 0.6d
- Add ARM support.
-
- Thu Nov 26 16:37:46 EST 1998
- Version 0.6c
- Typo in oops_code.
- Add -c option.
-
- Tue Nov 3 23:33:04 EST 1998
- Version 0.6a
- Performance inprovements.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- Oops file must be regular.
- Add "invalid operand" to Oops_print.
- Minor adjustment to re for ppc.
- Minor adjustment to re for objdump lines with <_EIP+xxx>.
- Convert from a.out to bfd, using same format as ksymoops.
- Added MIPS.
- PPC handling based on patches by "Ryan Nielsen" <ran@krazynet.com>
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into seperate sources.
- */
-
-#include "ksymoops.h"
-#include <bfd.h>
-#include <ctype.h>
-#include <errno.h>
-#include <malloc.h>
-#include <memory.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-enum oops_arch {
- OOPS_NOARCH,
- OOPS_I386,
- OOPS_SPARC,
- OOPS_SPARC64,
- OOPS_ARM,
- OOPS_ALPHA,
- OOPS_MIPS,
- OOPS_PPC,
- OOPS_M68K
-} oops_arch;
-
-char *eip_names[] = { "IP", "EIP", "PC", "PC", "PC", "PC", "PC", "NIP", "PC" };
-
-/* Error detected by bfd */
-static void Oops_bfd_perror(const char *msg)
-{
- fprintf(stderr, "Error ");
- bfd_perror(msg);
- ++errors;
-}
-
-/* Safest way to get correct output bfd format is to copy ksymoops' format. */
-static int Oops_copy_bfd_format(bfd **ibfd, bfd **obfd, asection **isec,
- const char *file)
-{
- char *me, **matches, **match;
-
- if (!(*obfd = bfd_openw(file, NULL))) {
- Oops_bfd_perror(file);
- return(0);
- }
-
- me = find_fullpath(prefix);
- if (!me)
- return(0);
-
- if (!(*ibfd = bfd_openr(me, NULL))) {
- Oops_bfd_perror(me);
- return(0);
- }
- free(me); /* Who is Tommy? */
-
- if (!bfd_check_format_matches(*ibfd, bfd_object, &matches)) {
- Oops_bfd_perror(me);
- if (bfd_get_error() == bfd_error_file_ambiguously_recognized) {
- fprintf(stderr, "Matching formats:");
- match = matches;
- while (*match)
- fprintf(stderr, " %s", *match++);
- fprintf(stderr, "\n");
- free(matches);
- }
- return(0);
- }
-
- if (!(*isec = bfd_get_section_by_name(*ibfd, ".text"))) {
- Oops_bfd_perror("get_section");
- return(0);
- }
-
- bfd_set_format(*obfd, bfd_object);
- bfd_set_arch_mach(*obfd, bfd_get_arch(*ibfd), bfd_get_mach(*ibfd));
-
- if (!bfd_set_file_flags(*obfd, bfd_get_file_flags(*ibfd))) {
- Oops_bfd_perror("set_file_flags");
- return(0);
- }
-
- return(1);
-}
-
-/* Write the code values to a file using bfd. */
-static int Oops_write_bfd_data(bfd *ibfd, bfd *obfd, asection *isec,
- const char *code, int size)
-{
- asection *osec;
- asymbol *osym;
-
- if (!bfd_set_start_address(obfd, 0)) {
- Oops_bfd_perror("set_start_address");
- return(0);
- }
- if (!(osec = bfd_make_section(obfd, ".text"))) {
- Oops_bfd_perror("make_section");
- return(0);
- }
- if (!bfd_set_section_flags(obfd, osec,
- bfd_get_section_flags(ibfd, isec))) {
- Oops_bfd_perror("set_section_flags");
- return(0);
- }
- if (!bfd_set_section_alignment(obfd, osec,
- bfd_get_section_alignment(ibfd, isec))) {
- Oops_bfd_perror("set_section_alignment");
- return(0);
- }
- osec->output_section = osec;
- if (!(osym = bfd_make_empty_symbol(obfd))) {
- Oops_bfd_perror("make_empty_symbol");
- return(0);
- }
- osym->name = "_EIP";
- osym->section = osec;
- osym->flags = BSF_GLOBAL;
- osym->value = 0;
- if (!bfd_set_symtab(obfd, &osym, 1)) {
- Oops_bfd_perror("set_symtab");
- return(0);
- }
- if (!bfd_set_section_size(obfd, osec, size)) {
- Oops_bfd_perror("set_section_size");
- return(0);
- }
- if (!bfd_set_section_vma(obfd, osec, 0)) {
- Oops_bfd_perror("set_section_vma");
- return(0);
- }
- if (!bfd_set_section_contents(obfd, osec, (PTR) code, 0, size)) {
- Oops_bfd_perror("set_section_contents");
- return(0);
- }
- if (!bfd_close(obfd)) {
- Oops_bfd_perror("close(obfd)");
- return(0);
- }
- if (!bfd_close(ibfd)) {
- Oops_bfd_perror("close(ibfd)");
- return(0);
- }
- return 1;
-}
-
-/* Write the Oops code to a temporary file with suitable header and trailer. */
-static char *Oops_code_to_file(const char *code, int size)
-{
- char *file;
- bfd *ibfd, *obfd;
- asection *isec;
-
- bfd_init();
- file = tmpnam(NULL);
- if (!Oops_copy_bfd_format(&ibfd, &obfd, &isec, file))
- return(NULL);
- if (!Oops_write_bfd_data(ibfd, obfd, isec, code, size))
- return(NULL);
- return(file);
-}
-
-/* Run objdump against the binary Oops code */
-static FILE *Oops_objdump(const char *file)
-{
- char *cmd;
- FILE *f;
- static char const options[] = "-dhf ";
- static char const procname[] = "Oops_objdump";
-
- cmd = malloc(strlen(path_objdump)+1+13+strlen(options)+strlen(file)+1);
- if (!cmd)
- malloc_error(procname);
- strcpy(cmd, path_objdump);
- strcat(cmd, " ");
- if (oops_arch == OOPS_SPARC64)
- strcat(cmd, "-m sparc:v9a ");
- strcat(cmd, options);
- strcat(cmd, file);
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s command '%s'\n", procname, cmd);
- f = popen_local(cmd, procname);
- free(cmd);
- return(f);
-}
-
-/* Process one code line from objdump, ignore everything else */
-static void Oops_decode_one(SYMBOL_SET *ss, const char *line, elf_addr_t eip,
- int adjust)
-{
- int i, j;
- elf_addr_t address, eip_relative;
- char *line2, *map, **string = NULL, *p;
- static regex_t re_Oops_objdump;
- static regmatch_t *re_Oops_objdump_pmatch;
- static char const procname[] = "Oops_decode_one";
-
- /* objdump output. Optional whitespace, hex digits, optional
- * ' <_EIP+offset>', ':'. The '+offset' after _EIP is also optional.
- * Older binutils output 'xxxxxxxx <_EIP+offset>:', newer versions do
- * '00000000 <_EIP>:' first followed by ' xx:' lines.
- *
- * Just to complicate things even more, objdump recognises jmp, call,
- * etc., converts the code to something like this :-
- * " f: e8 32 34 00 00 call 3446 <_EIP+0x3446>"
- * Recognise this and append the eip adjusted address, followed by the
- * map_address text for that address.
- *
- * With any luck, objdump will take care of all such references which
- * makes this routine architecture insensitive. No need to test for
- * i386 jmp, call or m68k swl etc.
- */
- re_compile(&re_Oops_objdump,
- "^[ \t]*"
- "([0-9a-fA-F]+)" /* 1 */
- "( <_EIP[^>]*>)?" /* 2 */
- ":"
- "(" /* 3 */
- ".* +"
- "(0?x?[0-9a-fA-F]+ +)" /* 4 */
- "<_EIP\\+0?x?([0-9a-fA-F]+)>[ \t]*$" /* 5 */
- ")?"
- ".*"
- ,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_objdump_pmatch);
-
- i = regexec(&re_Oops_objdump, line, re_Oops_objdump.re_nsub+1,
- re_Oops_objdump_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i != 0)
- return;
-
- re_strings(&re_Oops_objdump, line, re_Oops_objdump_pmatch, &string);
- errno = 0;
- address = strtoul(string[1], NULL, 16);
- if (errno) {
- fprintf(stderr,
- "%s Invalid hex value in objdump line, "
- "treated as zero - '%s'\n"
- " objdump line '%s'\n",
- procname, string[1], line);
- perror(" ");
- ++errors;
- address = 0;
- }
- address += eip + adjust;
- if (string[5]) {
- /* EIP relative data to be adjusted */
- errno = 0;
- eip_relative = strtoul(string[5], NULL, 16);
- if (errno) {
-#ifdef __sparc__
- /* Try strtoull also, e.g. sparc binutils print <_PC+0xfffffffffffffd58> */
- errno = 0;
- eip_relative = strtoull(string[5], NULL, 16);
-#endif
- if (errno) {
- fprintf(stderr,
- "%s Invalid hex value in objdump line, "
- "treated as zero - '%s'\n"
- " objdump line '%s'\n",
- procname, string[5], line);
- perror(" ");
- ++errors;
- eip_relative = 0;
- }
- }
- eip_relative += eip + adjust;
- map = map_address(&ss_merged, eip_relative);
- /* new text is original line, eip_relative in hex, map text */
- j = strlen(line);
- if (string[4])
- j = re_Oops_objdump_pmatch[4].rm_so;
- i = j+1+2*sizeof(eip_relative)+1+strlen(map)+1;
- line2 = malloc(i + 5);
- if (!line2)
- malloc_error(procname);
- snprintf(line2, i, "%.*s %s %s",
- j, line, format_address(eip_relative), map);
- } else {
- line2 = malloc(strlen(line) + 6);
- if (!line2)
- malloc_error(procname);
- strcpy(line2, line);
- }
- if (oops_arch != OOPS_I386) {
- p = line2;
- while ((p = strstr(p, "_EIP"))) {
- int l = strlen(eip_names[oops_arch]);
- memcpy(p + 1, eip_names[oops_arch], l);
- if (l < 3)
- strcpy(p + 1 + l, p + 4);
- p += 1 + l;
- }
- }
- if (address == eip)
- strcat(line2, " <==="); /* This makes it easier to locate visually the
- offending instruction */
- add_symbol_n(ss, address, 'C', 1, line2); /* as is */
- free(line2);
- re_strings_free(&re_Oops_objdump, &string);
-}
-
-/* Maximum number of code bytes to process. It needs to be a multiple of 2 for
- * code_byte (-c) swapping. Sparc and alpha dump 36 bytes so use 64.
- */
-#define CODE_SIZE 64
-
-/******************************************************************************/
-/* Start architecture sensitive code */
-/******************************************************************************/
-
-/* Extract the hex values from the Code: line and convert to binary */
-static int Oops_code_values(const unsigned char* code_text, char *code,
- int *adjust, char ***string, int string_max,
- int code_bytes)
-{
- int byte = 0, i, l;
- unsigned long c;
- char *value;
- const char *p;
- static regex_t re_Oops_code_value;
- static regmatch_t *re_Oops_code_value_pmatch;
- static const char procname[] = "Oops_code_values";
-
- /* Given by re_Oops_code: code_text is a message (e.g. "general
- * protection") or one or more hex fields separated by space or tab.
- * Some architectures bracket the current instruction with '<'
- * and '>', others use '(' and ')'. The first character is
- * nonblank.
- */
- if (!isxdigit(*code_text)) {
- fprintf(stderr,
- "Warning, Code looks like message, not hex digits. "
- "No disassembly attempted.\n");
- ++warnings;
- return(0);
- }
- memset(code, '\0', CODE_SIZE);
- p = code_text;
- *adjust = 0; /* EIP points to code byte 0 */
-
- /* Code values. Hex values separated by white space. On sparc, the
- * current instruction is bracketed in '<' and '>'.
- */
- re_compile(&re_Oops_code_value,
- "^"
- "([<(]?)" /* 1 */
- "([0-9a-fA-F]+)" /* 2 */
- "[>)]?"
- "[ \t]*"
- ,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_code_value_pmatch);
-
- re_string_check(re_Oops_code_value.re_nsub+1, string_max, procname);
- while (regexec(&re_Oops_code_value, p, re_Oops_code_value.re_nsub+1,
- re_Oops_code_value_pmatch, 0) == 0) {
- re_strings(&re_Oops_code_value, p,
- re_Oops_code_value_pmatch, string);
- if (byte >= CODE_SIZE)
- break;
- errno = 0;
- value = (*string)[2];
- c = strtoul(value, NULL, 16);
- if (errno) {
- fprintf(stderr,
- "%s Invalid hex value in code_value line, "
- "treated as zero - '%s'\n"
- " code_value line '%s'\n",
- procname, value, code_text);
- perror(" ");
- ++errors;
- c = 0;
- }
- if ((*string)[1] && *((*string)[1]))
- *adjust = -byte; /* this byte is EIP */
- /* i386 - 2 byte code, m68k - 4 byte, sparc - 8 byte.
- * On some architectures Code: is a stream of bytes, on some it
- * is a stream of shorts, on some it is a stream of ints.
- * Consistent we're not!
- */
- l = strlen(value);
- if (l%2) {
- fprintf(stderr,
- "%s invalid value 0x%s in Code line, not a "
- "multiple of 2 digits, value ignored\n",
- procname, value);
- ++errors;
- }
- else while (l) {
- if (byte >= CODE_SIZE) {
- fprintf(stderr,
- "%s Warning: extra values in Code "
- "line, ignored - '%s'\n",
- procname, value);
- ++warnings;
- break;
- }
- l -= 2;
- code[byte++] = (c >> l*4) & 0xff;
- value += 2;
- }
- p += re_Oops_code_value_pmatch[0].rm_eo;
- }
-
- if (*p) {
- fprintf(stderr,
- "Warning garbage '%s' at end of code line ignored "
- "by %s\n",
- p, procname);
- ++warnings;
- }
-
- /* The code_bytes parameter says how many readable bytes form a single
- * code unit in machine terms. -c 1 says that the text is already in
- * machine order, -c 2 (4, 8) says each chunk of 2 (4, 8) bytes must be
- * swapped to get back to machine order. Which end is up?
- */
- if (code_bytes != 1) {
- if (byte % code_bytes) {
- fprintf(stderr,
- "Warning: the number of code bytes (%d) is not "
- "a multiple of -c (%d)\n"
- "Byte swapping may not give sensible results\n",
- byte, code_bytes);
- ++warnings;
- }
- for (l = 0; l < byte; l+= code_bytes) {
- for (i = 0; i < code_bytes/2; ++i) {
- c = code[l+i];
- code[l+i] = code[l+code_bytes-i-1];
- code[l+code_bytes-i-1] = c;
- }
- }
- }
-
- return(1);
-}
-
-/* Look for the EIP: line, returns start of the relevant hex value */
-static char *Oops_eip(const char *line, char ***string, int string_max)
-{
- int i;
- static regex_t re_Oops_eip_sparc;
- static regmatch_t *re_Oops_eip_sparc_pmatch;
- static regex_t re_Oops_eip_sparc64;
- static regmatch_t *re_Oops_eip_sparc64_pmatch;
- static regex_t re_Oops_eip_ppc;
- static regmatch_t *re_Oops_eip_ppc_pmatch;
- static regex_t re_Oops_eip_mips;
- static regmatch_t *re_Oops_eip_mips_pmatch;
- static regex_t re_Oops_eip_other;
- static regmatch_t *re_Oops_eip_other_pmatch;
- static const char procname[] = "Oops_eip";
-
- /* Oops 'EIP:' line for sparc, actually PSR followed by PC */
- re_compile(&re_Oops_eip_sparc,
- "^PSR: [0-9a-fA-F]+ PC: " UNBRACKETED_ADDRESS,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_eip_sparc_pmatch);
-
- i = regexec(&re_Oops_eip_sparc, line, re_Oops_eip_sparc.re_nsub+1,
- re_Oops_eip_sparc_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec sparc %d\n", procname, i);
- if (i == 0) {
- re_string_check(re_Oops_eip_sparc.re_nsub+1, string_max,
- procname);
- re_strings(&re_Oops_eip_sparc, line, re_Oops_eip_sparc_pmatch,
- string);
- oops_arch = OOPS_SPARC;
- return((*string)[re_Oops_eip_sparc.re_nsub]);
- }
-
- /* Oops 'EIP:' line for sparc64, actually TSTATE followed by TPC */
- re_compile(&re_Oops_eip_sparc64,
- "^TSTATE: [0-9a-fA-F]{16} TPC: " UNBRACKETED_ADDRESS,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_eip_sparc64_pmatch);
-
- re_string_check(re_Oops_eip_sparc64.re_nsub+1, string_max, procname);
- i = regexec(&re_Oops_eip_sparc64, line, re_Oops_eip_sparc64.re_nsub+1,
- re_Oops_eip_sparc64_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec sparc64 %d\n", procname, i);
- if (i == 0) {
- re_strings(&re_Oops_eip_sparc64, line, re_Oops_eip_sparc64_pmatch,
- string);
- oops_arch = OOPS_SPARC64;
- return((*string)[re_Oops_eip_sparc64.re_nsub]);
- }
-
- /* Oops 'EIP:' line for PPC, all over the place */
- re_compile(&re_Oops_eip_ppc,
- "("
- "(kernel pc )"
- "|(trap at PC: )"
- "|(bad area pc )"
- "|(NIP: )"
- ")"
- UNBRACKETED_ADDRESS,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_eip_ppc_pmatch);
-
- i = regexec(&re_Oops_eip_ppc, line, re_Oops_eip_ppc.re_nsub+1,
- re_Oops_eip_ppc_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec ppc %d\n", procname, i);
- if (i == 0) {
- re_string_check(re_Oops_eip_ppc.re_nsub+1, string_max,
- procname);
- re_strings(&re_Oops_eip_ppc, line, re_Oops_eip_ppc_pmatch,
- string);
- oops_arch = OOPS_PPC;
- return((*string)[re_Oops_eip_ppc.re_nsub]);
- }
-
- /* Oops 'EIP:' line for MIPS, epc, optional white space, ':',
- * optional white space, unbracketed address.
- */
- re_compile(&re_Oops_eip_mips,
- "^(epc[ \t]*:+[ \t]*)"
- UNBRACKETED_ADDRESS,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_eip_mips_pmatch);
-
- i = regexec(&re_Oops_eip_mips, line, re_Oops_eip_mips.re_nsub+1,
- re_Oops_eip_mips_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec mips %d\n", procname, i);
- if (i == 0) {
- re_string_check(re_Oops_eip_mips.re_nsub+1, string_max,
- procname);
- re_strings(&re_Oops_eip_mips, line, re_Oops_eip_mips_pmatch,
- string);
- oops_arch = OOPS_MIPS;
- return((*string)[re_Oops_eip_mips.re_nsub]);
- }
-
- /* Oops 'EIP:' line for other architectures */
- re_compile(&re_Oops_eip_other,
- "^("
- /* i386 */ "(EIP:[ \t]+.*)"
- /* m68k */ "|(PC[ \t]*=[ \t]*)"
- /* ARM */ "|(pc *: *)"
- ")"
- BRACKETED_ADDRESS
- ,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_eip_other_pmatch);
-
- i = regexec(&re_Oops_eip_other, line, re_Oops_eip_other.re_nsub+1,
- re_Oops_eip_other_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec other %d\n", procname, i);
- if (i == 0) {
- re_string_check(re_Oops_eip_other.re_nsub+1, string_max,
- procname);
- re_strings(&re_Oops_eip_other, line, re_Oops_eip_other_pmatch,
- string);
- oops_arch = OOPS_I386;
- return((*string)[re_Oops_eip_other.re_nsub]);
- }
- return(NULL);
-}
-
-/* Set the eip from the EIP line */
-static void Oops_set_eip(const char *value, elf_addr_t *eip, SYMBOL_SET *ss)
-{
- static const char procname[] = "Oops_set_eip";
- char buf[10];
- errno = 0;
- *eip = strtoul(value, NULL, 16);
- if (errno) {
- fprintf(stderr,
- "%s Invalid hex value in EIP line, ignored - '%s'\n",
- procname, value);
- perror(" ");
- ++errors;
- *eip = 0;
- }
- sprintf(buf, ">>%s:", eip_names[oops_arch]);
- add_symbol_n(ss, *eip, 'E', 1, buf);
-}
-
-/* Look for the MIPS ra line, returns start of the relevant hex value */
-static char *Oops_ra(const char *line, char ***string, int string_max)
-{
- int i;
- static regex_t re_Oops_ra;
- static regmatch_t *re_Oops_ra_pmatch;
- static const char procname[] = "Oops_ra";
-
- /* Oops 'ra:' line for MIPS, ra, optional white space, one or
- * more '=', optional white space, unbracketed address.
- */
- re_compile(&re_Oops_ra,
- "(ra[ \t]*=+[ \t]*)"
- UNBRACKETED_ADDRESS,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_ra_pmatch);
-
- i = regexec(&re_Oops_ra, line, re_Oops_ra.re_nsub+1,
- re_Oops_ra_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i == 0) {
- re_string_check(re_Oops_ra.re_nsub+1, string_max, procname);
- re_strings(&re_Oops_ra, line, re_Oops_ra_pmatch,
- string);
- return((*string)[re_Oops_ra.re_nsub]);
- }
- return(NULL);
-}
-
-/* Set the MIPS ra from the ra line */
-static void Oops_set_ra(const char *value, SYMBOL_SET *ss)
-{
- static const char procname[] = "Oops_set_ra";
- elf_addr_t ra;
- errno = 0;
- ra = strtoul(value, NULL, 16);
- if (errno) {
- fprintf(stderr,
- "%s Invalid hex value in ra line, ignored - '%s'\n",
- procname, value);
- perror(" ");
- ++errors;
- ra = 0;
- }
- add_symbol_n(ss, ra, 'R', 1, ">>RA :");
-}
-
-/* Look for the SPARC o7/i7 registers line, returns start of the relevant hex value */
-static char *Oops_oi7(const char *line, char ***string, int string_max)
-{
- int i;
- static regex_t re_Oops_oi7;
- static regmatch_t *re_Oops_oi7_pmatch;
- static const char procname[] = "Oops_oi7";
-
- re_compile(&re_Oops_oi7,
- "^[io][04]: [0-9a-fA-F iosp:]+ ([io]7|ret_pc): "
- UNBRACKETED_ADDRESS,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_oi7_pmatch);
-
- re_string_check(re_Oops_oi7.re_nsub+1, string_max, procname);
- i = regexec(&re_Oops_oi7, line, re_Oops_oi7.re_nsub+1,
- re_Oops_oi7_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i == 0) {
- re_strings(&re_Oops_oi7, line, re_Oops_oi7_pmatch,
- string);
- return((*string)[re_Oops_oi7.re_nsub]);
- }
- return(NULL);
-}
-
-/* Set the SPARC o7/i7 from the oi7 line */
-static void Oops_set_oi7(const char *value, char ***string, SYMBOL_SET *ss)
-{
- static const char procname[] = "Oops_set_oi7";
- elf_addr_t oi7;
- int o7 = 1;
- errno = 0;
- oi7 = strtoul(value, NULL, 16);
- if ((*string)[1] && !strcmp((*string)[1], "i7"))
- o7 = 0;
- if (errno) {
- fprintf(stderr,
- "%s Invalid hex value in oi7 line, ignored - '%s'\n",
- procname, value);
- perror(" ");
- ++errors;
- oi7 = 0;
- }
- add_symbol_n(ss, oi7, 'O', 1, o7 ? ">>O7:" : ">>I7:");
-}
-
-/* Look for the SPARC register dump lines end */
-static int Oops_sparc_regdump(const char *line)
-{
- int i;
- static regex_t re_Oops_sparc_regdump;
- static regmatch_t *re_Oops_sparc_regdump_pmatch;
- static const char procname[] = "Oops_sparc_regdump";
-
- re_compile(&re_Oops_sparc_regdump,
- "^(i[04]: "
- "|Instruction DUMP: "
- "|Caller\\["
- ")",
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_sparc_regdump_pmatch);
-
- i = regexec(&re_Oops_sparc_regdump, line, re_Oops_sparc_regdump.re_nsub+1,
- re_Oops_sparc_regdump_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i == 0)
- return 1;
- return 0;
-}
-
-
-/* Look for the Trace multilines :(. Returns start of addresses. */
-static const char *Oops_trace(const char *line, char ***string, int string_max)
-{
- int i;
- const char *start = NULL;
- static int trace_line = 0;
- static regex_t re_Oops_trace;
- static regmatch_t *re_Oops_trace_pmatch;
- static const char procname[] = "Oops_trace";
-
- /* ppc is different, not a bracketed address, just an address */
- /* ARM is different, two bracketed addresses on each line */
-
- /* Oops 'Trace' lines */
- re_compile(&re_Oops_trace,
- "^(" /* 1 */
- "(Call Trace: )" /* 2 */
- /* alpha */ "|(Trace: )" /* 3 */
- /* various */ "|(" BRACKETED_ADDRESS ")" /* 4,5*/
- /* ppc */ "|(Call backtrace:)" /* 6 */
- /* ppc */ "|(" UNBRACKETED_ADDRESS ")" /* 7,8*/
- /* ARM */ "|(Function entered at (" BRACKETED_ADDRESS "))" /* 9,10,11 */
- /* sparc */
- /* sparc64 */ "|(Caller\\[" UNBRACKETED_ADDRESS "\\])"/*12,13*/
- ")",
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_trace_pmatch);
-
- i = regexec(&re_Oops_trace, line, re_Oops_trace.re_nsub+1,
- re_Oops_trace_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i == 0) {
-#undef MATCHED
-#define MATCHED(n) (re_Oops_trace_pmatch[n].rm_so != -1)
- if (MATCHED(2) || MATCHED(3)) {
- trace_line = 1;
- start = line + re_Oops_trace_pmatch[0].rm_eo;
- }
- else if (MATCHED(6)) {
- trace_line = 2; /* ppc */
- start = line + re_Oops_trace_pmatch[0].rm_eo;
- }
- else if (trace_line == 1 && MATCHED(5))
- start = line + re_Oops_trace_pmatch[5].rm_so;
- else if (trace_line == 2 && MATCHED(8)) /* ppc */
- start = line + re_Oops_trace_pmatch[8].rm_so;
- else if (MATCHED(10)){
- trace_line = 1; /* ARM */
- start = line + re_Oops_trace_pmatch[10].rm_so;
- } else if (MATCHED(12)) {
- trace_line = 0; /* sparc, sparc64 */
- start = line + re_Oops_trace_pmatch[13].rm_so;
- return start;
- } else
- trace_line = 0;
- }
- else
- trace_line = 0;
- if (trace_line)
- return(start);
- return(NULL);
-}
-
-/* Process a trace call line, extract addresses */
-static void Oops_trace_line(const char *line, const char *p, SYMBOL_SET *ss)
-{
- char **string = NULL;
- regex_t *pregex;
- regmatch_t *pregmatch;
- static const char procname[] = "Oops_trace_line";
-
- /* ppc does not bracket its addresses */
- if (isxdigit(*p)) {
- pregex = &re_unbracketed_address;
- pregmatch = re_unbracketed_address_pmatch;
- }
- else {
- pregex = &re_bracketed_address;
- pregmatch = re_bracketed_address_pmatch;
- }
-
- /* Loop over [un]?bracketed addresses */
- while (1) {
- if (regexec(pregex, p, pregex->re_nsub+1, pregmatch, 0) == 0) {
- re_strings(pregex, p, pregmatch, &string);
- add_symbol(ss, string[1], 'T', 1, "Trace:");
- p += pregmatch[0].rm_eo;
- }
- else if (strncmp(p, "from ", 5) == 0)
- p += 5; /* ARM does "address from address" */
- else
- break;
- }
-
- if (*p && !strcmp(p, "...")) {
- fprintf(stderr,
- "Warning garbage '%s' at end of trace line ignored "
- "by %s\n",
- p, procname);
- ++warnings;
- }
- re_strings_free(pregex, &string);
-}
-
-/* Do pattern matching to decide if the line should be printed. When reading a
- * syslog containing multiple Oops, you need the intermediate data (registers,
- * tss etc.) to go with the decoded text. Sets text to the start of the useful
- * text, after any prefix. Note that any leading white space is treated as part
- * of the prefix, later routines do not see any indentation.
- *
- * Note: If a line is not printed, it will not be scanned for any other text.
- */
-static int Oops_print(const char *line, const char **text, char ***string,
- int string_max)
-{
- int i, print = 0;
- static int stack_line = 0, trace_line = 0;
- static regex_t re_Oops_prefix;
- static regmatch_t *re_Oops_prefix_pmatch;
- static regex_t re_Oops_print_s;
- static regmatch_t *re_Oops_print_s_pmatch;
- static regex_t re_Oops_print_a;
- static regmatch_t *re_Oops_print_a_pmatch;
- static const char procname[] = "Oops_print";
-
- *text = line;
-
- /* Lines to be ignored. For some reason the "amuse the user" print in
- * some die_if_kernel routines causes regexec to run very slowly.
- */
-
- if (strstr(*text, "\\|/ ____ \\|/") ||
- strstr(*text, "\"@'/ ,. \\`@\"") ||
- strstr(*text, "/_| \\__/ |_\\") ||
- strstr(*text, " \\__U_/"))
- return(1); /* print but avoid regexec */
-
- /* Prefixes to be ignored */
- re_compile(&re_Oops_prefix,
- "^(" /* start of line */
- "([^ ]{3} [ 0-9][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} "
- "[^ ]+ kernel: +)" /* syslogd */
- "|(<[0-9]+>)" /* kmsg */
- "|([ \t]+)" /* leading white space */
- ")+" /* any prefixes, in any order */
- ,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_prefix_pmatch);
-
- i = regexec(&re_Oops_prefix, *text, re_Oops_prefix.re_nsub+1,
- re_Oops_prefix_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec prefix %d\n", procname, i);
- if (i == 0)
- *text += re_Oops_prefix_pmatch[0].rm_eo; /* step over prefix */
-
-
- /* Lots of possibilities. Expand as required for all architectures.
- *
- * Trial and error shows that regex does not like a lot of sub patterns
- * that start with "^". So split the patterns into two groups, one set
- * must appear at the start of the line, the other set can appear
- * anywhere.
- */
-
- /* These patterns must appear at the start of the line, after stripping
- * the prefix above.
- *
- * The order below is required to handle multiline outupt.
- * string 2 is defined if the text is 'Stack from '.
- * string 3 is defined if the text is 'Stack: '.
- * string 4 is defined if the text might be a stack continuation.
- * string 5 is defined if the text is 'Call Trace: '.
- * string 6 is defined if the text might be a trace continuation.
- * string 7 is the address part of the BRACKETED_ADDRESS.
- *
- * string 8 is defined if the text contains a version number. No Oops
- * report contains this as of 2.1.125 but IMHO it should be added. If
- * anybody wants to print a VERSION_nnnn line in their Oops, this code
- * is ready.
- *
- * string 9 is defined if the text is 'Trace: ' (alpha).
- * string 10 is defined if the text is 'Call backtrace:' (ppc).
- */
- re_compile(&re_Oops_print_s,
- /* arch type */ /* Required order */
- "^(" /* 1 */
- /* i386 */ "(Stack: )" /* 2 */
- /* m68k */ "|(Stack from )" /* 3 */
- /* various */ "|([0-9a-fA-F]{4,})" /* 4 */
- /* various */ "|(Call Trace: )" /* 5 */
- /* various */ "|(" BRACKETED_ADDRESS ")" /* 6,7*/
- /* various */ "|(Version_[0-9]+)" /* 8 */
- /* alpha */ "|(Trace: )" /* 9 */
- /* ppc */ "|(Call backtrace:)" /* 10 */
-
- /* order does not matter from here on */
-
- /* various */ "|(Process .*stackpage=)"
- /* various */ "|(Call Trace:[ \t])"
- /* various */ "|(Code *:[ \t])"
- /* various */ "|(Kernel panic)"
- /* various */ "|(In swapper task)"
-
- /* i386 2.0 */ "|(Corrupted stack page)"
- /* i386 */ "|(invalid operand: )"
- /* i386 */ "|(Oops: )"
- /* i386 */ "|(Cpu: +[0-9])"
- /* i386 */ "|(current->tss)"
- /* i386 */ "|(\\*pde +=)"
- /* i386 */ "|(EIP: )"
- /* i386 */ "|(EFLAGS: )"
- /* i386 */ "|(eax: )"
- /* i386 */ "|(esi: )"
- /* i386 */ "|(ds: )"
-
- /* m68k */ "|(pc[:=])"
- /* m68k */ "|(68060 access)"
- /* m68k */ "|(Exception at )"
- /* m68k */ "|(d[04]: )"
- /* m68k */ "|(Frame format=)"
- /* m68k */ "|(wb [0-9] stat)"
- /* m68k */ "|(push data: )"
- /* m68k */ "|(baddr=)"
- /* any other m68K lines to print? */
-
- /* alpha */ "|(Bad unaligned kernel)"
- /* alpha */ "|(Forwarding unaligned exception)"
- /* alpha */ "|(: unhandled unaligned exception)"
- /* alpha */ "|(<sc)"
- /* alpha */ "|(pc *=)"
- /* alpha */ "|(r[0-9]+ *=)"
- /* alpha */ "|(gp *=)"
- /* any other alpha lines to print? */
-
- /* sparc */ "|(tsk->)"
- /* sparc */ "|(PSR: )"
- /* sparc */ "|([goli][04]: )"
- /* sparc */ "|(Instruction DUMP: )"
- /* sparc */ "|(Caller\\[)"
- /* any other sparc lines to print? */
-
- /* sparc64 */ "|(TSTATE: )"
- /* any other sparc64 lines to print? */
-
- /* ppc */ "|(MSR: )"
- /* ppc */ "|(TASK = )"
- /* ppc */ "|(last math )"
- /* ppc */ "|(GPR[0-9]+: )"
- /* any other ppc lines to print? */
-
- /* MIPS */ "|(\\$[0-9 ]+:)"
- /* MIPS */ "|(epc )"
- /* MIPS */ "|(Status:)"
- /* MIPS */ "|(Cause :)"
- /* any other MIPS lines to print? */
-
- /* ARM */ "|(Backtrace:)"
- /* ARM */ "|(Function entered at)"
- /* ARM */ "|(\\*pgd =)"
- /* ARM */ "|(Internal error)"
- /* ARM */ "|(pc :)"
- /* ARM */ "|(sp :)"
- /* ARM */ "|(r[0-9][0-9 ]:)"
- /* ARM */ "|(Flags:)"
- /* ARM */ "|(Control:)"
- /* any other ARM lines to print? */
-
- ")",
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_print_s_pmatch);
-
- i = regexec(&re_Oops_print_s, *text, re_Oops_print_s.re_nsub+1,
- re_Oops_print_s_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec start %d\n", procname, i);
- print = 0;
- if (i == 0) {
-#undef MATCHED
-#define MATCHED(n) (re_Oops_print_s_pmatch[n].rm_so != -1)
- print = 1;
- /* Handle multiline messages, messy */
- if (!MATCHED(2) && !MATCHED(3) && !MATCHED(4))
- stack_line = 0;
- else if (MATCHED(2) || MATCHED(3))
- stack_line = 1;
- else if (stack_line && !MATCHED(4)) {
- print = 0;
- stack_line = 0;
- }
- if (!MATCHED(5) && !MATCHED(6) && !MATCHED(9) && !MATCHED(10))
- trace_line = 0;
- else if (MATCHED(5) || MATCHED(9) || MATCHED(10))
- trace_line = 1;
- else if (stack_line && !MATCHED(6)) {
- print = 0;
- trace_line = 0;
- }
- /* delay splitting into strings until we really them */
- if (MATCHED(8)) {
- re_string_check(re_Oops_print_s.re_nsub+1, string_max,
- procname);
- re_strings(&re_Oops_print_s, *text,
- re_Oops_print_s_pmatch,
- string);
- add_Version((*string)[8]+8, "Oops");
- }
- }
-
- /* These patterns can appear anywhere in the line, after stripping
- * the prefix above.
- */
- re_compile(&re_Oops_print_a,
- /* arch type */
-
- /* various */ "(Unable to handle kernel)"
- /* various */ "|(Aiee)" /* anywhere in text is a bad sign (TM) */
- /* various */ "|(die_if_kernel)" /* ditto */
-
- /* alpha */ "|(\\([0-9]\\): Oops )"
- /* alpha */ "|(: memory violation)"
- /* alpha */ "|(: Exception at)"
- /* alpha */ "|(: Arithmetic fault)"
- /* alpha */ "|(: Instruction fault)"
- /* alpha */ "|(: arithmetic trap)"
- /* alpha */ "|(: unaligned trap)"
-
- /* sparc die_if_kernel has no fixed text, identify by (pid): text.
- * Somebody has been playful with the texts.
- *
- * Alas adding this next pattern increases run time by 15% on
- * its own! It would be considerably faster if sparc had
- * consistent error texts.
- */
- /* sparc */ "|("
- "\\([0-9]+\\): "
- "("
- "(Whee)"
- "|(Oops)"
- "|(Kernel)"
- "|(Penguin)"
- "|(Too many Penguin)"
- "|(BOGUS)"
- ")"
- ")"
-
- /* ppc */ "|(kernel pc )"
- /* ppc */ "|(trap at PC: )"
- /* ppc */ "|(bad area pc )"
- /* ppc */ "|(NIP: )"
-
- /* MIPS */ "|( ra *=)"
-
- ")",
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_print_a_pmatch);
-
- i = regexec(&re_Oops_print_a, *text, re_Oops_print_a.re_nsub+1,
- re_Oops_print_a_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec anywhere %d\n", procname, i);
- if (i == 0)
- print = 1;
-
- return(print);
-}
-
-/* Look for the Code: line. Returns start of the code bytes. */
-static const char *Oops_code(const char *line, char ***string, int string_max)
-{
- int i;
- static regex_t re_Oops_code;
- static regmatch_t *re_Oops_code_pmatch;
- static const char procname[] = "Oops_code";
-
- /* Oops 'Code: ' hopefully followed by at least one hex code. sparc
- * brackets the PC in '<' and '>'. ARM brackets the PC in '(' and ')'.
- */
- re_compile(&re_Oops_code,
- "^(" /* 1 */
- /* sparc */ "(Instruction DUMP)" /* 2 */
- /* various */ "|(Code *)" /* 3 */
- ")"
- ":[ \t]+"
- "(" /* 4 */
- "(general protection.*)"
- "|(<[0-9]+>)"
- "|(([<(]?[0-9a-fA-F]+[>)]?[ \t]+)+[<(]?[0-9a-fA-F]+[>)]?)"
- ")"
- "(.*)$" /* trailing garbage */
- ,
- REG_NEWLINE|REG_EXTENDED|REG_ICASE,
- &re_Oops_code_pmatch);
-
- i = regexec(&re_Oops_code, line, re_Oops_code.re_nsub+1,
- re_Oops_code_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i == 0) {
- re_string_check(re_Oops_code.re_nsub+1, string_max, procname);
- re_strings(&re_Oops_code, line, re_Oops_code_pmatch,
- string);
- if ((*string)[re_Oops_code.re_nsub] &&
- *((*string)[re_Oops_code.re_nsub])) {
- fprintf(stderr,
- "Warning: trailing garbage ignored on Code: "
- "line\n"
- " Text: '%s'\n"
- " Garbage: '%s'\n",
- line, (*string)[re_Oops_code.re_nsub]);
- ++warnings;
- }
- return((*string)[4]);
- }
- return(NULL);
-}
-
-/******************************************************************************/
-/* End architecture sensitive code */
-/******************************************************************************/
-
-/* Decode the Oops Code: via objdump*/
-static void Oops_decode(const unsigned char* code_text, elf_addr_t eip,
- SYMBOL_SET *ss, char ***string, int string_max,
- int code_bytes)
-{
- FILE *f;
- char *file, *line = NULL, code[CODE_SIZE];
- int size = 0, adjust;
- static char const procname[] = "Oops_decode";
-
- if (debug)
- fprintf(stderr, "DEBUG: %s\n", procname);
- /* text to binary */
- if (!Oops_code_values(code_text, code, &adjust, string, string_max,
- code_bytes))
- return;
- /* binary to same format as ksymoops */
- if (!(file = Oops_code_to_file(code, CODE_SIZE)))
- return;
- /* objdump the pseudo object */
- if (!(f = Oops_objdump(file)))
- return;
- while (fgets_local(&line, &size, f, procname)) {
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s - %s\n", procname, line);
- Oops_decode_one(ss, line, eip, adjust);
- }
- pclose_local(f, procname); /* opened in Oops_objdump */
- free(line);
- if (unlink(file)) {
- fprintf(stderr, "%s could not unlink %s", prefix, file);
- perror(" ");
- }
-}
-
-/* Reached the end of an Oops report, format the extracted data. */
-static void Oops_format(const SYMBOL_SET *ss_format)
-{
- int i;
- SYMBOL *s;
- static const char procname[] = "Oops_format";
-
- if (debug)
- fprintf(stderr, "DEBUG: %s\n", procname);
-
- compare_Version(); /* Oops might have a version one day */
- printf("\n");
- for (s = ss_format->symbol, i = 0; i < ss_format->used; ++i, ++s) {
- /* For type C data, print Code:, address, map, "name" (actually
- * the text of an objdump line). For other types print name,
- * address, map.
- */
- if (s->type == 'C')
- printf("Code: %s %-30s %s\n",
- format_address(s->address),
- map_address(&ss_merged, s->address),
- s->name);
- else
- printf("%s %s %s\n",
- s->name,
- format_address(s->address),
- map_address(&ss_merged, s->address));
- }
- printf("\n");
-}
-
-/* Select next Oops input file */
-static FILE *Oops_next_file(int *filecount, char * const **filename)
-{
- static FILE *f = NULL;
- static const char procname[] = "Oops_next_file";
- static int first_file = 1;
-
- if (first_file) {
- f = stdin;
- first_file = 0;
- }
- while (*filecount) {
- if (f)
- fclose_local(f, procname);
- f = NULL;
- if (regular_file(**filename, procname))
- f = fopen_local(**filename, "r", procname);
- if (f) {
- if (debug)
- fprintf(stderr,
- "DEBUG: reading Oops report "
- "from %s\n", **filename);
- }
- ++*filename;
- --*filecount;
- if (f)
- return(f);
- }
- return(f);
-}
-
-/* Read the Oops report */
-#define MAX_STRINGS 300 /* Maximum strings in any Oops re */
-int Oops_read(int filecount, char * const *filename, int code_bytes,
- int one_shot)
-{
- char *line = NULL, **string = NULL;
- const char *start, *text;
- int i, size = 0, lineno = 0, lastprint = 0, print = 0;
- elf_addr_t eip = 0;
- int sparc_regdump = 0;
- FILE *f;
- SYMBOL_SET ss_format;
- static const char procname[] = "Oops_read";
-
- ss_init(&ss_format, "Oops log data");
-
- if (!filecount && isatty(0))
- printf("Reading Oops report from the terminal\n");
-
- string = malloc(MAX_STRINGS*sizeof(*string));
- if (!string)
- malloc_error(procname);
- memset(string, '\0', MAX_STRINGS*sizeof(*string));
-
- do {
- if (!(f = Oops_next_file(&filecount, &filename)))
- continue;
- while (fgets_local(&line, &size, f, procname)) {
- if (debug > 2)
- fprintf(stderr,
- "DEBUG: %s - %s\n", procname, line);
- ++lineno;
- print = Oops_print(line, &text, &string, MAX_STRINGS);
- if (Oops_sparc_regdump (text)) {
- sparc_regdump = 1;
- } else {
- if ((oops_arch == OOPS_SPARC ||
- oops_arch == OOPS_SPARC64) &&
- sparc_regdump && ss_format.used) {
- Oops_format(&ss_format);
- ss_free(&ss_format);
- }
- sparc_regdump = 0;
- }
- if (print) {
- puts(line);
- lastprint = lineno;
- if ((start = Oops_eip(text,
- &string, MAX_STRINGS)))
- Oops_set_eip(start, &eip, &ss_format);
- if ((start = Oops_ra(text,
- &string, MAX_STRINGS)))
- Oops_set_ra(start, &ss_format);
- if ((start = Oops_oi7(text,
- &string, MAX_STRINGS)))
- Oops_set_oi7(start, &string,
- &ss_format);
- if ((start = Oops_trace(text,
- &string, MAX_STRINGS)))
- Oops_trace_line(text, start,
- &ss_format);
- if ((start = Oops_code(text,
- &string, MAX_STRINGS))) {
- Oops_decode(start, eip, &ss_format,
- &string, MAX_STRINGS,
- code_bytes);
- Oops_format(&ss_format);
- ss_free(&ss_format);
- if (one_shot)
- return(0);
- }
- }
- /* More than 5 (arbitrary) lines which were not printed
- * and there is some saved data, assume we missed the
- * Code: line.
- */
- if (ss_format.used && lineno > lastprint+5) {
- fprintf(stderr,
- "Warning, Code line not seen, dumping "
- "what data is available\n");
- ++warnings;
- Oops_format(&ss_format);
- ss_free(&ss_format);
- if (one_shot)
- return(0);
- }
- }
- if (ss_format.used) {
- if ((oops_arch != OOPS_SPARC &&
- oops_arch != OOPS_SPARC64) || !sparc_regdump) {
- fprintf(stderr,
- "Warning, Code line not seen, dumping "
- "what data is available\n");
- ++warnings;
- }
- Oops_format(&ss_format);
- ss_free(&ss_format);
- if (one_shot)
- return(0);
- }
- } while (filecount != 0);
-
- for (i = 0; i < sizeof(string); ++i) {
- free(string[i]);
- string[i] = NULL;
- }
- free(line);
- if (one_shot)
- return(3); /* one shot mode, end of input, no data */
- return(0);
-}
diff --git a/scripts/ksymoops/re.c b/scripts/ksymoops/re.c
deleted file mode 100644
index 9c65832f7..000000000
--- a/scripts/ksymoops/re.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- re.c.
-
- Regular expression processing for ksymoops.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- PPC trace addresses are not bracketed, add new re.
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <malloc.h>
-#include <string.h>
-
-/* Compile a regular expression */
-void re_compile(regex_t *preg, const char *regex, int cflags,
- regmatch_t **pmatch)
-{
- int i, l;
- char *p;
- static char const procname[] = "re_compile";
-
- if (preg->re_nsub)
- return; /* already compiled */
-
- if (debug)
- fprintf(stderr, "DEBUG: %s '%s'", procname, regex);
- if ((i = regcomp(preg, regex, cflags))) {
- l = regerror(i, preg, NULL, 0);
- ++l; /* doc is ambiguous, be safe */
- p = malloc(l);
- if (!p)
- malloc_error("regerror text");
- regerror(i, preg, p, l);
- fprintf(stderr,
- "%s: fatal %s error on '%s' - %s\n",
- prefix, procname, regex, p);
- exit(2);
- }
- if (debug)
- fprintf(stderr, " %d sub expression(s)\n", preg->re_nsub);
- /* [0] is entire match, [1] is first substring */
- *pmatch = malloc((preg->re_nsub+1)*sizeof(**pmatch));
- if (!*pmatch)
- malloc_error("pmatch");
-
-}
-
-/* Compile common regular expressions */
-void re_compile_common(void)
-{
-
- /* nm: address, type, symbol */
- re_compile(&re_nm,
- "^([0-9a-fA-F]{4,}) +([^ ]) +([^ ]+)$",
- REG_NEWLINE|REG_EXTENDED,
- &re_nm_pmatch);
-
- /* bracketed address preceded by optional white space */
- re_compile(&re_bracketed_address,
- "^[ \t]*" BRACKETED_ADDRESS,
- REG_NEWLINE|REG_EXTENDED,
- &re_bracketed_address_pmatch);
-
- /* unbracketed address preceded by optional white space */
- re_compile(&re_unbracketed_address,
- "^[ \t*]*" UNBRACKETED_ADDRESS,
- REG_NEWLINE|REG_EXTENDED,
- &re_unbracketed_address_pmatch);
-
-}
-
-/* Split text into the matching re substrings - Perl is so much easier :).
- * Each element of *string is set to a malloced copy of the substring or
- * NULL if the substring did not match (undef). A zero length substring match
- * is represented by a zero length **string.
- */
-void re_strings(regex_t *preg, const char *text, regmatch_t *pmatch,
- char ***string)
-{
- int i;
- if (!*string) {
- *string = malloc((preg->re_nsub+1)*sizeof(**string));
- if (!*string)
- malloc_error("re_strings base");
- for (i = 0; i < preg->re_nsub+1; ++i)
- (*string)[i] = NULL;
- }
- for (i = 0; i < preg->re_nsub+1; ++i) {
- if (debug > 4)
- fprintf(stderr,
- "DEBUG: re_string %d offsets %d %d",
- i, pmatch[i].rm_so, pmatch[i].rm_eo);
- if (pmatch[i].rm_so == -1) {
- /* no match for this sub expression */
- free((*string)[i]);
- (*string)[i] = NULL;
- if (debug > 4)
- fprintf(stderr, " (undef)\n");
- }
- else {
- int l = pmatch[i].rm_eo - pmatch[i].rm_so + 1;
- char *p;
- p = malloc(l);
- if (!p)
- malloc_error("re_strings");
- strncpy(p, text+pmatch[i].rm_so, l-1);
- *(p+l-1) = '\0';
- (*string)[i] = p;
- if (debug > 4)
- fprintf(stderr, " '%s'\n", p);
- }
- }
-}
-
-/* Free the matching re substrings */
-void re_strings_free(const regex_t *preg, char ***string)
-{
- if (*string) {
- int i;
- for (i = 0; i < preg->re_nsub+1; ++i)
- free((*string)[i]);
- free(*string);
- *string = NULL;
- }
-}
-
-/* Check that there are enough strings for an re */
-void re_string_check(int need, int available, const char *msg)
-{
- if (need > available) {
- fprintf(stderr,
- "%s: fatal not enough re_strings in %s. "
- "Need %d, available %d\n",
- prefix, msg, need, available);
- exit(2);
- }
-}
diff --git a/scripts/ksymoops/symbol.c b/scripts/ksymoops/symbol.c
deleted file mode 100644
index 5c66cc994..000000000
--- a/scripts/ksymoops/symbol.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- symbol.c.
-
- Symbol handling routines for ksymoops.
-
- Copyright Keith Owens <kaos@ocs.com.au>.
- Released under the GNU Public Licence, Version 2.
-
- Mon Jan 4 09:08:19 EST 1999
- Version 0.6d
- Cast Version to int, glibc 2.1 made elf_addr_t a long.
-
- Tue Nov 3 02:31:01 EST 1998
- Version 0.6
- Fix end of code calculation.
-
- Wed Oct 28 13:47:23 EST 1998
- Version 0.4
- Split into separate sources.
- */
-
-#include "ksymoops.h"
-#include <errno.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Initialise a symbol source */
-void ss_init(SYMBOL_SET *ss, const char *msg)
-{
- memset(ss, '\0', sizeof(*ss));
- ss->source = strdup(msg);
- if (!ss->source)
- malloc_error(msg);
-}
-
-/* Free dynamic data from a symbol source */
-void ss_free(SYMBOL_SET *ss)
-{
- int i;
- SYMBOL *s;
- for (s = ss->symbol, i = 0; i < ss->used; ++i, ++s)
- free(s->name);
- free(ss->symbol);
- free(ss->source);
- memset(ss, '\0', sizeof(*ss));
-}
-
-/* Initialise common symbol sets */
-void ss_init_common(void)
-{
- ss_init(&ss_Version, "Version_");
-}
-
-/* Find a symbol name in a symbol source. Brute force ascending order search,
- * no hashing. If start is not NULL, it contains the starting point for the
- * scan and is updated to point to the found entry. If the entry is not found,
- * return NULL with start pointing to the next highest entry.
- * NOTE: Assumes that ss is sorted by name.
- */
-SYMBOL *find_symbol_name(const SYMBOL_SET *ss, const char *symbol, int *start)
-{
- int i, l;
- SYMBOL *s;
- for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
- if ((l = strcmp(symbol, s->name)) == 0) {
- if (start)
- *start = i;
- return(s);
- }
- if (l < 0)
- break;
- }
- if (start)
- *start = i;
- return NULL;
-}
-
-/* Find an address in a symbol source. Brute force ascending order search, no
- * hashing. If start is not NULL, it contains the starting point for the scan
- * and is updated to point to the found entry. If the entry is not found,
- * return NULL with start pointing to the next highest entry.
- * NOTE: Assumes that ss is sorted by address.
- */
-static SYMBOL *find_symbol_address(const SYMBOL_SET *ss,
- const elf_addr_t address, int *start)
-{
- int i;
- SYMBOL *s;
- for (i = start ? *start : 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
- if (address > s->address)
- continue;
- else if (address == s->address) {
- if (start)
- *start = i;
- return(s);
- }
- else
- break;
- }
- if (start)
- *start = i;
- return NULL;
-}
-
-/* Add a symbol to a symbol set, address in binary */
-void add_symbol_n(SYMBOL_SET *ss, const elf_addr_t address,
- const char type, const char keep, const char *symbol)
-{
- int i;
- char **string = NULL;
- SYMBOL *s;
- static regex_t re_symbol_ver;
- static regmatch_t *re_symbol_ver_pmatch;
- static const char procname[] = "add_symbol_n";
-
- /* Strip out any trailing symbol version _Rxxxxxxxx. */
- re_compile(&re_symbol_ver,
- "^(.*)_R[0-9a-fA-F]{8,}$",
- REG_NEWLINE|REG_EXTENDED,
- &re_symbol_ver_pmatch);
-
- i = regexec(&re_symbol_ver, symbol,
- re_symbol_ver.re_nsub+1, re_symbol_ver_pmatch, 0);
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s regexec %d\n", procname, i);
- if (i == 0)
- re_strings(&re_symbol_ver, symbol, re_symbol_ver_pmatch,
- &string);
-
- if (debug > 3)
- fprintf(stderr, "DEBUG: %s %s %s '%c' %d '%s'\n",
- procname, ss->source, format_address(address),
- type, keep, i == 0 ? string[1] : symbol);
- if (ss->used > ss->alloc) {
- fprintf(stderr,
- "%s: fatal %s ss %s used (%d) > alloc (%d)\n",
- procname, prefix, ss->source, ss->used, ss->alloc);
- exit(2);
- }
- if (ss->used == ss->alloc) {
- /* increase by 20% or 10, whichever is larger, arbitrary */
- int newsize = ss->alloc*120/100;
- if (newsize < ss->alloc+10)
- newsize = ss->alloc+10;
- if (debug > 3)
- fprintf(stderr,
- "DEBUG: %s increasing %s from %d to %d "
- "entries\n",
- procname, ss->source, ss->alloc, newsize);
- ss->symbol = realloc(ss->symbol, newsize*sizeof(*(ss->symbol)));
- if (!ss->symbol)
- malloc_error("realloc ss");
- ss->alloc = newsize;
- }
- s = ss->symbol+ss->used;
- if (i == 0) {
- s->name = string[1];
- string[1] = NULL; /* don't free this one */
- }
- else {
- s->name = strdup(symbol);
- if (!s->name)
- malloc_error("strdup symbol");
- }
- s->type = type;
- s->keep = keep;
- s->address = address;
- ++ss->used;
- re_strings_free(&re_symbol_ver, &string);
-}
-
-/* Add a symbol to a symbol set, address in character */
-void add_symbol(SYMBOL_SET *ss, const char *address, const char type,
- const char keep, const char *symbol)
-{
- elf_addr_t a;
- static char const procname[] = "add_symbol";
- errno = 0;
- a = strtoul(address, NULL, 16);
- if (errno) {
- fprintf(stderr,
- "%s: %s address '%s' is in error",
- prefix, procname, address);
- perror(" ");
- ++errors;
- }
- add_symbol_n(ss, a, type, 1, symbol);
-}
-
-/* Map an address to symbol, offset and length, address in binary */
-char *map_address(const SYMBOL_SET *ss, const elf_addr_t address)
-{
- int i = 0, l;
- SYMBOL *s;
- static char *map = NULL;
- static int size = 0;
- static const char procname[] = "map_address_n";
-
- if (debug > 2)
- fprintf(stderr, "DEBUG: %s %s %s\n",
- procname, ss->source, format_address(address));
- s = find_symbol_address(ss, address, &i);
- if (!s && --i >= 0)
- s = ss->symbol+i; /* address is between s and s+1 */
-
- /* Extra map text is always < 100 bytes */
- if (s)
- l = strlen(s->name) + 100;
- else
- l = 100;
- if (l > size) {
- map = realloc(map, l);
- if (!map)
- malloc_error(procname);
- size = l;
- }
- if (!s) {
- if (ss->used == 0)
- snprintf(map, size, "No symbols available");
- else
- snprintf(map, size, "Before first symbol");
- }
- else if ((i+1) >= ss->used) {
- /* Somewhere past last symbol. Length of last section of code
- * is unknown, arbitrary cutoff at 32K.
- */
- elf_addr_t offset = address - s->address;
- if (offset > 32768)
- snprintf(map, size, "<END_OF_CODE+%lx/????>", offset);
- else
- snprintf(map, size, "<%s+%lx/????>", s->name, offset);
- }
- else
- snprintf(map, size,
- "<%s+%lx/%lx>",
- s->name, address - s->address,
- (s+1)->address - s->address);
- return(map);
-}
-
-/* After sorting, obsolete symbols are at the top. Delete them. */
-static void ss_compress(SYMBOL_SET *ss)
-{
- int i, j;
- SYMBOL *s;
- static const char procname[] = "ss_compress";
-
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s on table %s, before %d ",
- procname, ss->source, ss->used);
- for (i = 0, s = ss->symbol+i; i < ss->used; ++i, ++s) {
- if (!s->keep) {
- for (j = i; j < ss->used; ++j, ++s) {
- if (s->keep) {
- fprintf(stderr,
- "%s: fatal %s table %s is not "
- "sorted\n",
- prefix, procname, ss->source);
- exit(2);
- }
- }
- break;
- }
- }
- for (j = i, s = ss->symbol+j; j < ss->used; ++j, ++s)
- free(s->name);
- ss->used = i;
- if (debug > 1)
- fprintf(stderr, "after %d\n", ss->used);
-}
-
-static int ss_compare_atn(const void *a, const void *b)
-{
- SYMBOL *c = (SYMBOL *) a;
- SYMBOL *d = (SYMBOL *) b;
- int i;
-
- /* obsolete symbols to the top */
- if (c->keep != d->keep)
- return(d->keep - c->keep);
- if (c->address > d->address)
- return(1);
- if (c->address < d->address)
- return(-1);
- if (c->type > d->type)
- return(1);
- if (c->type < d->type)
- return(-1);
- if ((i = strcmp(c->name, d->name)))
- return(i);
- return(0);
-}
-
-/* Sort a symbol set by address, type and name */
-void ss_sort_atn(SYMBOL_SET *ss)
-{
- if (debug)
- fprintf(stderr, "DEBUG: sorting symbols for %s (atn)\n",
- ss->source);
- qsort((char *) ss->symbol, (unsigned) ss->used,
- sizeof(*(ss->symbol)), ss_compare_atn);
- ss_compress(ss);
-}
-
-static int ss_compare_na(const void *a, const void *b)
-{
- SYMBOL *c = (SYMBOL *) a;
- SYMBOL *d = (SYMBOL *) b;
- int i;
-
- /* obsolete symbols to the top */
- if (c->keep != d->keep)
- return(d->keep - c->keep);
- if ((i = strcmp(c->name, d->name)))
- return(i);
- if (c->address > d->address)
- return(1);
- if (c->address < d->address)
- return(-1);
- return(0);
-}
-
-/* Sort a symbol set by name and address, drop duplicates. There should be
- * no duplicates but I have seen duplicates in ksyms on 2.0.35.
- */
-void ss_sort_na(SYMBOL_SET *ss)
-{
- int i;
- SYMBOL *s;
- if (debug)
- fprintf(stderr, "DEBUG: sorting symbols for %s (na)\n",
- ss->source);
- qsort((char *) ss->symbol, (unsigned) ss->used,
- sizeof(*(ss->symbol)), ss_compare_na);
- ss_compress(ss);
- s = ss->symbol;
- for (i = 0; i < ss->used-1; ++i) {
- if (strcmp(s->name, (s+1)->name) == 0 &&
- s->address == (s+1)->address) {
- if (s->type != ' ')
- (s+1)->keep = 0;
- else
- s->keep = 0;
- }
- ++s;
- }
- qsort((char *) ss->symbol, (unsigned) ss->used,
- sizeof(*(ss->symbol)), ss_compare_na);
- ss_compress(ss);
-}
-
-/* Copy a symbol set, including all its strings */
-SYMBOL_SET *ss_copy(const SYMBOL_SET *ss)
-{
- SYMBOL_SET *ssc;
- if (debug > 3)
- fprintf(stderr,
- "DEBUG: ss_copy %s\n", ss->source);
- ssc = malloc(sizeof(*ssc));
- if (!ssc)
- malloc_error("copy ssc");
- ss_init(ssc, ss->source);
- ssc->used = ss->used;
- ssc->alloc = ss->used; /* shrink the copy */
- ssc->symbol = malloc(ssc->used*sizeof(*(ssc->symbol)));
- if (!(ssc->symbol))
- malloc_error("copy ssc symbols");
- memcpy(ssc->symbol, ss->symbol, ssc->used*sizeof(*(ssc->symbol)));
- return(ssc);
-}
-
-/* Convert version number to major, minor string. */
-static const char *format_Version(elf_addr_t Version)
-{
- static char string[12]; /* 255.255.255\0 worst case */
- snprintf(string, sizeof(string), "%d.%d.%d",
- (int) ((Version >> 16) & 0xff),
- (int) ((Version >> 8) & 0xff),
- (int) ((Version) & 0xff));
- return(string);
-}
-
-/* Save version number. The "address" is the version number, the "symbol" is
- * the source of the version.
- */
-void add_Version(const char *version, const char *source)
-{
- static char const procname[] = "add_Version";
- int i = atoi(version);
- if (debug > 1)
- fprintf(stderr, "DEBUG: %s %s %s %s\n",
- procname, source, version, format_Version(i));
- add_symbol_n(&ss_Version, i, 'V', 1, source);
-}
-
-/* Extract Version_ number from a symbol set and save it. */
-void extract_Version(SYMBOL_SET *ss)
-{
- int i = 0;
- SYMBOL *s;
-
- s = find_symbol_name(ss, "Version_", &i);
- if (!s && i < ss->used)
- s = ss->symbol+i; /* first symbol after "Version_" */
- if (!s || strncmp(s->name, "Version_", 8))
- return;
- add_Version(s->name+8, ss->source);
-}
-
-/* Compare all extracted Version numbers. Silent unless there is a problem. */
-void compare_Version(void)
-{
- int i = 0;
- SYMBOL *s, *s0;
- static int prev_used = 0;
-
- if (!ss_Version.used)
- return;
- /* Only check if the Version table has changed in size */
- if (prev_used == ss_Version.used)
- return;
-
- ss_sort_na(&ss_Version);
- s0 = s = ss_Version.symbol;
- if (debug)
- fprintf(stderr, "DEBUG: Version %s\n",
- format_Version(s0->address));
- for (i = 0; i < ss_Version.used; ++i, ++s) {
- if (s->address != s0->address) {
- fprintf(stderr,
- "Version mismatch error. %s says %s, ",
- s0->name,
- format_Version(s0->address));
- fprintf(stderr,
- "%s says %s. Expect lots of address "
- "mismatches.\n",
- s->name,
- format_Version(s->address));
- ++errors;
- }
- }
- prev_used = ss_Version.used;
-}
diff --git a/scripts/ver_linux b/scripts/ver_linux
index 4725ebfeb..a1b8642a4 100644
--- a/scripts/ver_linux
+++ b/scripts/ver_linux
@@ -21,10 +21,12 @@ ls -l /usr/lib/lib{g,stdc}++.so 2>/dev/null | awk -F. \
ps --version 2>&1 | awk 'NR==1{print "Procps ", $NF}'
mount --version | awk -F\- '{print "Mount ", $NF}'
hostname -V 2>&1 | awk 'NR==1{print "Net-tools ", $NF}'
+# Kbd needs 'loadkeys -h',
loadkeys -h 2>&1 | awk \
-'(NR==1 && $3) {ver=$3}
- (NR==2 && $1 ~ /console-tools/) {print "Console-tools ",$3; done=1}
- END {if (!done) print "Kbd ",ver}'
+'(NR==1 && ($3 !~ /option/)) {print "Kbd ", $3}'
+# while console-tools needs 'loadkeys -V'.
+loadkeys -V 2>&1 | awk \
+'(NR==1 && ($2 ~ /console-tools/)) {print "Console-tools ", $3}'
expr --v | awk '{print "Sh-utils ", $NF}'
X=`cat /proc/modules | sed -e "s/ .*$//"`
echo "Modules Loaded "$X