From 0ae8dceaebe3659ee0c3352c08125f403e77ebca Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 28 Sep 1999 22:25:29 +0000 Subject: Merge with 2.3.10. --- scripts/ksymoops/Makefile | 79 --- scripts/ksymoops/README | 404 +------------ scripts/ksymoops/io.c | 139 ----- scripts/ksymoops/ksymoops.c | 678 --------------------- scripts/ksymoops/ksymoops.h | 146 ----- scripts/ksymoops/ksyms.c | 294 --------- scripts/ksymoops/map.c | 251 -------- scripts/ksymoops/misc.c | 108 ---- scripts/ksymoops/object.c | 230 -------- scripts/ksymoops/oops.c | 1377 ------------------------------------------- scripts/ksymoops/re.c | 145 ----- scripts/ksymoops/symbol.c | 444 -------------- scripts/ver_linux | 8 +- 13 files changed, 11 insertions(+), 4292 deletions(-) delete mode 100644 scripts/ksymoops/Makefile delete mode 100644 scripts/ksymoops/io.c delete mode 100644 scripts/ksymoops/ksymoops.c delete mode 100644 scripts/ksymoops/ksymoops.h delete mode 100644 scripts/ksymoops/ksyms.c delete mode 100644 scripts/ksymoops/map.c delete mode 100644 scripts/ksymoops/misc.c delete mode 100644 scripts/ksymoops/object.c delete mode 100644 scripts/ksymoops/oops.c delete mode 100644 scripts/ksymoops/re.c delete mode 100644 scripts/ksymoops/symbol.c (limited to 'scripts') 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 . - 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 /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 . - 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 - m68k code based on ksymoops.cc changes by - Andreas Schwab - - 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 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: ' - 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 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 . - 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 -#include -#include -#include - -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 . - 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" - - 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 - m68k code based on ksymoops.cc changes by - Andreas Schwab - */ - -#include "ksymoops.h" -#include -#include -#include -#include -#include -#include -#include - -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 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 . - 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 -#include -#include - - -/* 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 . - 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 -#include - -/* 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 . - 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 - -/* 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 . - 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 -#include -#include - -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 . - 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 -#include -#include - -/* 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 . - 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" - - - 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" - - Wed Oct 28 13:47:23 EST 1998 - Version 0.4 - Split into seperate sources. - */ - -#include "ksymoops.h" -#include -#include -#include -#include -#include -#include -#include -#include - -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 */ "|()" - /* 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 . - 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 -#include - -/* 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 . - 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 -#include -#include -#include - -/* 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, "", 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 -- cgit v1.2.3