diff options
Diffstat (limited to 'scripts/ksymoops/ksymoops.c')
-rw-r--r-- | scripts/ksymoops/ksymoops.c | 678 |
1 files changed, 0 insertions, 678 deletions
diff --git a/scripts/ksymoops/ksymoops.c b/scripts/ksymoops/ksymoops.c deleted file mode 100644 index 0cd65795b..000000000 --- a/scripts/ksymoops/ksymoops.c +++ /dev/null @@ -1,678 +0,0 @@ -/* - ksymoops.c. - - Read a kernel Oops file and make the best stab at converting the code to - instructions and mapping stack values to kernel symbols. - - Copyright Keith Owens <kaos@ocs.com.au>. - Released under the GNU Public Licence, Version 2. -*/ - -#define VERSION "0.6e" - -/* - - Tue Jan 5 19:26:02 EST 1999 - Version 0.6e - Added to kernel. - - Mon Jan 4 09:48:13 EST 1999 - Version 0.6d - Add ARM support. - - Thu Nov 26 16:37:46 EST 1998 - Version 0.6c - Typo in oops_code. - Add -c option. - Add -1 option. - Report if options were specified or defaulted. - - Fri Nov 6 10:38:42 EST 1998 - Version 0.6b - Remove false warnings when comparing ksyms and lsmod. - - Tue Nov 3 23:33:04 EST 1998 - Version 0.6a - Performance inprovements. - - Tue Nov 3 02:31:01 EST 1998 - Version 0.6 - Read lsmod (/proc/modules). - Ignore addresses 0-4095 when mapping address to symbol. - Discard default objects if -o specified. - Oops file must be regular. - Add "invalid operand" to Oops_print. - Move "Using_Version" copy to map.c. - Add Makefile defaults for vmlinux, ksyms, objects, System.map, lsmod. - Minor adjustment to re for ppc. - Minor adjustment to re for objdump lines with <_EIP+xxx>. - Convert from a.out to bfd, using same format as ksymoops. - Added MIPS. - PPC handling based on patches by "Ryan Nielsen" <ran@krazynet.com> - - Wed Oct 28 23:14:55 EST 1998 - Version 0.5 - No longer read vmlinux by default, it only duplicates System.map. - - Wed Oct 28 13:47:38 EST 1998 - Version 0.4 - Split into separate sources. - - Mon Oct 26 00:01:47 EST 1998 - Version 0.3c - Add alpha (arm) processing. - - Mon Oct 26 00:01:47 EST 1998 - Version 0.3b - Add sparc processing. - Handle kernel symbol versions. - - Fri Oct 23 13:11:20 EST 1998 - Version 0.3 - Add -follow to find command for people who use symlinks to modules. - Add Version_ checking. - - Thu Oct 22 22:28:30 EST 1998 - Version 0.2. - Generalise text prefix handling. - Handle messages on Code: line. - Format addresses with leading zeroes. - Minor bug fixes. - - Wed Oct 21 23:28:48 EST 1998 - Version 0.1. Rewrite from scratch in C. - - CREDITS. - Oops disassembly based on ksymoops.cc, - Copyright (C) 1995 Greg McGary <gkm@magilla.cichlid.com> - m68k code based on ksymoops.cc changes by - Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> - */ - -#include "ksymoops.h" -#include <ctype.h> -#include <errno.h> -#include <malloc.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/utsname.h> - -char *prefix; -char *path_nm = "/usr/bin/nm"; /* env KSYMOOPS_NM */ -char *path_find = "/usr/bin/find"; /* env KSYMOOPS_FIND */ -char *path_objdump = "/usr/bin/objdump"; /* env KSYMOOPS_OBJDUMP */ -int debug = 0; -int errors = 0; -int warnings = 0; - -SYMBOL_SET ss_vmlinux; -SYMBOL_SET ss_ksyms_base; -SYMBOL_SET *ss_ksyms_module; -int ss_ksyms_modules; -SYMBOL_SET ss_lsmod; -SYMBOL_SET *ss_object; -int ss_objects; -SYMBOL_SET ss_system_map; - -SYMBOL_SET ss_merged; /* merged map with info from all sources */ -SYMBOL_SET ss_Version; /* Version_ numbers where available */ - -/* Regular expression stuff */ - -regex_t re_nm; -regmatch_t *re_nm_pmatch; -regex_t re_bracketed_address; -regmatch_t *re_bracketed_address_pmatch; -regex_t re_unbracketed_address; -regmatch_t *re_unbracketed_address_pmatch; - -static void usage(void) -{ - fprintf(stderr, "Version " VERSION "\n"); - fprintf(stderr, "usage: %s\n", prefix); - fprintf(stderr, - "\t\t[-v vmlinux]\tWhere to read vmlinux\n" - "\t\t[-V]\t\tNo vmlinux is available\n" - "\t\t[-o object_dir]\tDirectory containing modules\n" - "\t\t[-O]\t\tNo modules is available\n" - "\t\t[-k ksyms]\tWhere to read ksyms\n" - "\t\t[-K]\t\tNo ksyms is available\n" - "\t\t[-l lsmod]\tWhere to read lsmod\n" - "\t\t[-L]\t\tNo lsmod is available\n" - "\t\t[-m system.map]\tWhere to read System.map\n" - "\t\t[-M]\t\tNo System.map is available\n" - "\t\t[-s save.map]\tSave consolidated map\n" - "\t\t[-d]\t\tIncrease debug level by 1\n" - "\t\t[-h]\t\tPrint help text\n" - "\t\t[-c code_bytes]\tHow many bytes in each unit of code\n" - "\t\t[-1]\t\tOne shot toggle (exit after first Oops)\n" - "\t\t<Oops.file\tOops report to decode\n" - "\n" - "\t\tAll flags can occur more than once. With the exception " - "of -o\n" - "\t\tand -d which are cumulative, the last occurrence of each " - "flag is\n" - "\t\tused. Note that \"-v my.vmlinux -V\" will be taken as " - "\"No vmlinux\n" - "\t\tavailable\" but \"-V -v my.vmlinux\" will read " - "my.vmlinux. You\n" - "\t\twill be warned about such combinations.\n" - "\n" - "\t\tEach occurrence of -d increases the debug level.\n" - "\n" - "\t\tEach -o flag can refer to a directory or to a single " - "object\n" - "\t\tfile. If a directory is specified then all *.o files in " - "that\n" - "\t\tdirectory and its subdirectories are assumed to be " - "modules.\n" - "\n" - "\t\tIf any of the vmlinux, object_dir, ksyms or system.map " - "options\n" - "\t\tcontain the string *r (*m, *n, *s) then it is replaced " - "at run\n" - "\t\ttime by the current value of `uname -r` (-m, -n, -s).\n" - "\n" - "\t\tThe defaults can be changed in the Makefile, current " - "defaults\n" - "\t\tare\n\n" - "\t\t\t" -#ifdef DEF_VMLINUX - "-v " DEF_LINUX -#else - "-V" -#endif - "\n" - "\t\t\t" -#ifdef DEF_OBJECTS - "-o " DEF_OBJECTS -#else - "-O" -#endif - "\n" - "\t\t\t" -#ifdef DEF_KSYMS - "-k " DEF_KSYMS -#else - "-K" -#endif - "\n" - "\t\t\t" -#ifdef DEF_LSMOD - "-l " DEF_LSMOD -#else - "-L" -#endif - "\n" - "\t\t\t" -#ifdef DEF_MAP - "-m " DEF_MAP -#else - "-M" -#endif - "\n" - "\t\t\t-c %d\n" /* DEF_CODE_BYTES */ - "\t\t\tOops report is read from stdin\n" - "\n", - DEF_CODE_BYTES - ); -} - -/* Check if possibly conflicting options were specified */ -static void multi_opt(int specl, int specu, char type, const char *using) -{ - if (specl && specu) { - fprintf(stderr, - "Warning - you specified both -%c and -%c. Using '", - type, toupper(type)); - ++warnings; - if (using) { - fprintf(stderr, "-%c %s", type, using); - if (type == 'o') - fprintf(stderr, " ..."); - fprintf(stderr, "'\n"); - } - else - fprintf(stderr, "-%c'\n", toupper(type)); - } - else if (specl > 1 && type != 'o') { - fprintf(stderr, - "Warning - you specified -%c more than once. " - "Using '-%c %s'\n", - type, type, using); - ++warnings; - } - else if (specu > 1) { - fprintf(stderr, - "Warning - you specified -%c more than once. " - "Second and subsequent '-%c' ignored\n", - toupper(type), toupper(type)); - ++warnings; - } -} - -/* If a name contains *r (*m, *n, *s), replace with the current value of - * `uname -r` (-m, -n, -s). Actually uses uname system call rather than the - * uname command but the result is the same. - */ -static void convert_uname(char **name) -{ - char *p, *newname, *oldname, *replacement; - unsigned len; - int free_oldname = 0; - static char procname[] = "convert_uname"; - - if (!*name) - return; - - while ((p = strchr(*name, '*'))) { - struct utsname buf; - int i = uname(&buf); - if (debug) - fprintf(stderr, "DEBUG: %s %s in\n", procname, *name); - if (i) { - fprintf(stderr, - "%s: uname failed, %s will not be processed\n", - prefix, *name); - perror(prefix); - ++errors; - return; - } - switch (*(p+1)) { - case 'r': - replacement = buf.release; - break; - case 'm': - replacement = buf.machine; - break; - case 'n': - replacement = buf.nodename; - break; - case 's': - replacement = buf.sysname; - break; - default: - fprintf(stderr, - "%s: invalid replacement character '*%c' " - "in %s\n", - prefix, *(p+1), *name); - ++errors; - return; - } - len = strlen(*name)-2+strlen(replacement)+1; - if (!(newname = malloc(len))) - malloc_error(procname); - strncpy(newname, *name, (p-*name)); - strcpy(newname+(p-*name), replacement); - strcpy(newname+(p-*name)+strlen(replacement), p+2); - p = newname+(p-*name)+strlen(replacement); /* no rescan */ - oldname = *name; - *name = newname; - if (free_oldname) - free(oldname); - free_oldname = 1; - if (debug) - fprintf(stderr, "DEBUG: %s %s out\n", procname, *name); - } - return; -} - -/* Report if the option was specified or defaulted */ -static void spec_or_default(int spec, int *some_spec) { - if (spec) { - printf(" (specified)\n"); - if (some_spec) - *some_spec = 1; - } - else - printf(" (default)\n"); -} - -/* Parse the options. Verbose but what's new with getopt? */ -static void parse(int argc, - char **argv, - char **vmlinux, - char ***object, - int *objects, - char **ksyms, - char **lsmod, - char **system_map, - char **save_system_map, - char ***filename, - int *filecount, - int *spec_h, - int *code_bytes, - int *one_shot - ) -{ - int spec_v = 0, spec_V = 0; - int spec_o = 0, spec_O = 0; - int spec_k = 0, spec_K = 0; - int spec_l = 0, spec_L = 0; - int spec_m = 0, spec_M = 0; - int spec_s = 0; - int spec_c = 0; - - int c, i, some_spec = 0; - char *p; - - while ((c = getopt(argc, argv, "v:Vo:Ok:Kl:Lm:Ms:dhc:1")) != EOF) { - if (debug && c != 'd') - fprintf(stderr, "DEBUG: getopt '%c' '%s'\n", c, optarg); - switch(c) { - case 'v': - *vmlinux = optarg; - ++spec_v; - break; - case 'V': - *vmlinux = NULL; - ++spec_V; - break; - case 'o': - if (!spec_o) { - /* First -o, discard default value(s) */ - for (i = 0; i < *objects; ++i) - free((*object)[i]); - free(*object); - *object = NULL; - *objects = 0; - } - *object = realloc(*object, - ((*objects)+1)*sizeof(**object)); - if (!*object) - malloc_error("object"); - if (!(p = strdup(optarg))) - malloc_error("strdup -o"); - else { - (*object)[(*objects)++] = p; - ++spec_o; - } - break; - case 'O': - ++spec_O; - for (i = 0; i < *objects; ++i) - free((*object)[i]); - free(*object); - *object = NULL; - *objects = 0; - break; - case 'k': - *ksyms = optarg; - ++spec_k; - break; - case 'K': - *ksyms = NULL; - ++spec_K; - break; - case 'l': - *lsmod = optarg; - ++spec_l; - break; - case 'L': - *lsmod = NULL; - ++spec_L; - break; - case 'm': - *system_map = optarg; - ++spec_m; - break; - case 'M': - *system_map = NULL; - ++spec_M; - break; - case 's': - *save_system_map = optarg; - ++spec_s; - break; - case 'd': - ++debug; - break; - case 'h': - usage(); - ++*spec_h; - break; - case 'c': - ++spec_c; - errno = 0; - *code_bytes = strtoul(optarg, &p, 10); - /* Oops_code_values assumes that code_bytes is a - * multiple of 2. - */ - if (!*optarg || *p || errno || - (*code_bytes != 1 && - *code_bytes != 2 && - *code_bytes != 4 && - *code_bytes != 8)) { - fprintf(stderr, - "%s Invalid value for -c '%s'\n", - prefix, optarg); - ++errors; - if (errno) - perror(" "); - *code_bytes = DEF_CODE_BYTES; - } - break; - case '1': - *one_shot = !*one_shot; - break; - case '?': - usage(); - exit(2); - } - } - - *filecount = argc - optind; - *filename = argv + optind; - - /* Expand any requests for the current uname values */ - convert_uname(vmlinux); - if (*objects) { - for (i = 0; i < *objects; ++i) - convert_uname(*object+i); - } - convert_uname(ksyms); - convert_uname(lsmod); - convert_uname(system_map); - - /* Check for multiple options specified */ - multi_opt(spec_v, spec_V, 'v', *vmlinux); - multi_opt(spec_o, spec_O, 'o', *object ? **object : NULL); - multi_opt(spec_k, spec_K, 'k', *ksyms); - multi_opt(spec_l, spec_L, 'l', *lsmod); - multi_opt(spec_m, spec_M, 'm', *system_map); - - printf("Options used:"); - if (*vmlinux) - printf(" -v %s", *vmlinux); - else - printf(" -V"); - spec_or_default(spec_v || spec_V, &some_spec); - - printf(" "); - if (*objects) { - for (i = 0; i < *objects; ++i) - printf(" -o %s", (*object)[i]); - } - else - printf(" -O"); - spec_or_default(spec_o || spec_O, &some_spec); - - printf(" "); - if (*ksyms) - printf(" -k %s", *ksyms); - else - printf(" -K"); - spec_or_default(spec_k || spec_K, &some_spec); - - printf(" "); - if (*lsmod) - printf(" -l %s", *lsmod); - else - printf(" -L"); - spec_or_default(spec_l || spec_L, &some_spec); - - printf(" "); - if (*system_map) - printf(" -m %s", *system_map); - else - printf(" -M"); - spec_or_default(spec_m || spec_M, &some_spec); - - printf(" "); - printf(" -c %d", *code_bytes); - spec_or_default(spec_c, NULL); - - if (*one_shot) { - printf(" "); - printf(" -1"); - } - - printf("\n"); - - if (!some_spec) { - printf( -"You did not tell me where to find symbol information. I will assume\n" -"that the log matches the kernel and modules that are running right now\n" -"and I'll use the default options above for symbol resolution.\n" -"If the current kernel and/or modules do not match the log, you can get\n" -"more accurate output by telling me the kernel version and where to find\n" -"map, modules, ksyms etc. ksymoops -h explains the options.\n" - "\n"); - ++warnings; - } -} - -/* Read environment variables */ -static void read_env(const char *external, char **internal) -{ - char *p; - if ((p = getenv(external))) { - *internal = p; - if (debug) - fprintf(stderr, - "DEBUG: env override %s=%s\n", - external, *internal); - } - else { - if (debug) - fprintf(stderr, - "DEBUG: env default %s=%s\n", - external, *internal); - } -} - - -int main(int argc, char **argv) -{ - char *vmlinux = NULL; - char **object = NULL; - int objects = 0; - char *ksyms = NULL; - char *lsmod = NULL; - char *system_map = NULL; - char *save_system_map = NULL; - char **filename; - int filecount = 0; - int spec_h = 0; /* -h was specified */ - int code_bytes = DEF_CODE_BYTES; - int one_shot = 0; - int i, ret; - - prefix = *argv; - setvbuf(stdout, NULL, _IONBF, 0); - -#ifdef DEF_VMLINUX - vmlinux = DEF_LINUX; -#endif -#ifdef DEF_OBJECTS - { - char *p; - object = realloc(object, (objects+1)*sizeof(*object)); - if (!object) - malloc_error("DEF_OBJECTS"); - if (!(p = strdup(DEF_OBJECTS))) - malloc_error("DEF_OBJECTS"); - else - object[objects++] = p; - } -#endif -#ifdef DEF_KSYMS - ksyms = DEF_KSYMS; -#endif -#ifdef DEF_LSMOD - lsmod = DEF_LSMOD; -#endif -#ifdef DEF_MAP - system_map = DEF_MAP; -#endif - - parse(argc, - argv, - &vmlinux, - &object, - &objects, - &ksyms, - &lsmod, - &system_map, - &save_system_map, - &filename, - &filecount, - &spec_h, - &code_bytes, - &one_shot - ); - - if (spec_h && filecount == 0) - return(0); /* just the help text */ - - if (errors) - return(1); - - if (debug) - fprintf(stderr, "DEBUG: level %d\n", debug); - - read_env("KSYMOOPS_NM", &path_nm); - read_env("KSYMOOPS_FIND", &path_find); - read_env("KSYMOOPS_OBJDUMP", &path_objdump); - - re_compile_common(); - ss_init_common(); - - read_vmlinux(vmlinux); - read_ksyms(ksyms); - /* No point in reading modules unless ksyms shows modules loaded */ - if (ss_ksyms_modules) { - expand_objects(object, objects); - for (i = 0; i < ss_objects; ++i) - read_object(ss_object[i].source, i); - } - else if (objects) - printf("No modules in ksyms, skipping objects\n"); - /* No point in reading lsmod without ksyms */ - if (ss_ksyms_modules || ss_ksyms_base.used) - read_lsmod(lsmod); - else if (lsmod) - printf("No ksyms, skipping lsmod\n"); - read_system_map(system_map); - merge_maps(save_system_map); - - /* After all that work, it is finally time to read the Oops report */ - ret = Oops_read(filecount, filename, code_bytes, one_shot); - - if (warnings || errors) { - printf("\n"); - if (warnings) - printf("%d warning%s ", - warnings, warnings == 1 ? "" : "s"); - if (warnings && errors) - printf("and "); - if (errors) - printf("%d error%s ", errors, errors == 1 ? "" : "s"); - printf("issued. Results may not be reliable.\n"); - if (!ret) - return(1); - } - - return(ret); -} |