diff -Nur ksymoops-2.3.3/Changelog ksymoops-2.3.4/Changelog --- ksymoops-2.3.3/Changelog Sun Jan 9 20:05:08 2000 +++ ksymoops-2.3.4/Changelog Sat Apr 8 23:41:57 2000 @@ -1,3 +1,18 @@ +2000-03-29 Keith Owens + + ksymoops 2.3.4 + + * Support for s390 messages. + * Handle Bad EIP value. + * Allow any genksyms prefix. + * Handle SGI kdb backtrace. + * Detect merged system map and extract module data. + * Replace tmpnam with mkstemp and honour TMPDIR. Requested by + Joseph S. Myers. + * Document how to use ksymoops to decode XFree86 error reports. + * Fix Makefile bug that stopped the use of RPM_OPT_FLAGS. + Reported by Ingo Oeser. + 1999-10-21 Keith Owens ksymoops 2.3.3 diff -Nur ksymoops-2.3.3/Makefile ksymoops-2.3.4/Makefile --- ksymoops-2.3.3/Makefile Sun Jan 9 20:07:42 2000 +++ ksymoops-2.3.4/Makefile Sat Apr 8 23:41:57 2000 @@ -30,7 +30,7 @@ PROGS = ksymoops CC=gcc -CFLAGS = -Dlinux \ +CFLAGS += -Dlinux \ -Wall \ -Wno-conversion \ -Waggregate-return \ diff -Nur ksymoops-2.3.3/README.XFree86 ksymoops-2.3.4/README.XFree86 --- ksymoops-2.3.3/README.XFree86 Thu Jan 1 10:00:00 1970 +++ ksymoops-2.3.4/README.XFree86 Sat Apr 8 23:35:53 2000 @@ -0,0 +1,32 @@ +XFree86 produces error reports very much like the kernel output. For +example, this is a sample XFree86 report. + +eip: 080b3cdc eflags: 00013286 +eax: 082e4268 ebx: caaee805 ecx: 000000ed edx: 0828ffd8 +esi: 082e41b0 edi: 082ae628 ebp: bffffa4c esp: bffffa14 +Stack: 08348794 082e41b0 bffffa4c 0809c4be 082ae628 02400014 c0000001 00000002 + 08348794 082e41b0 082ae628 05bf64a0 08348794 02000000 bffffa7c 080b43bc + 082e41b0 000000ed 000000ed 00000004 082ae628 00000000 bffffa94 00000000 + 00000000 082906a8 bffffcac 080968d3 082ae628 00000020 bffffcac 0809695b + +Call Trace: 0809c4be 080b43bc 080968d3 0809695b 080783b1 0806f7a5 080ba1e7 + 080a53bd 080a5628 080a5314 0815f734 08096848 080a51e2 080a51fb 081b844c + 0806b1b0 0806b1d1 080a4d58 081b844c 0806b1b0 + +Code: 39 4b 04 75 ef 85 db 74 76 85 d2 75 1a 8b 56 78 8b 03 89 42 + +All you need is a small adjustment to the EIP line (ksymoops expects +kernel format with a bracketed address) plus something that looks like +a System.map but is actually generated from the failing program and you +can use ksymoops on XFree86 programs. + +Generate the map by + +objdump -T /usr/X11R6/bin/failing_program | \ + fgrep -v '*UND*' | \ + awk '{print $1, $2, $NF}' > map + +Feed the oops with an adjusted EIP plus the map to ksymoops and send +the decoded result to the person responsible for the failing program. + +sed -e 's/\(eip: *\)\([^ ]*\)/\1[<\2>]/' < oops | ksymoops -VKLO -m map diff -Nur ksymoops-2.3.3/ksymoops.c ksymoops-2.3.4/ksymoops.c --- ksymoops-2.3.3/ksymoops.c Tue Oct 19 17:41:05 1999 +++ ksymoops-2.3.4/ksymoops.c Wed Mar 29 11:13:18 2000 @@ -9,7 +9,7 @@ Released under the GNU Public Licence, Version 2. */ -#define VERSION "2.3.3" +#define VERSION "2.3.4" #include "ksymoops.h" #include diff -Nur ksymoops-2.3.3/ksymoops.h ksymoops-2.3.4/ksymoops.h --- ksymoops-2.3.3/ksymoops.h Tue Oct 19 08:21:36 1999 +++ ksymoops-2.3.4/ksymoops.h Mon Apr 3 11:38:13 2000 @@ -185,6 +185,7 @@ extern void map_ksyms_to_modules(void); extern void read_lsmod(const char *lsmod); extern void compare_ksyms_lsmod(void); +extern void add_ksyms(const char *, char, const char *, const char *); /* misc.c */ extern void malloc_error(const char *msg); diff -Nur ksymoops-2.3.3/ksymoops.spec ksymoops-2.3.4/ksymoops.spec --- ksymoops-2.3.3/ksymoops.spec Sun Jan 9 20:05:08 2000 +++ ksymoops-2.3.4/ksymoops.spec Wed Mar 29 11:13:18 2000 @@ -1,6 +1,6 @@ Summary: Kernel oops and error message decoder Name: ksymoops -Version: 2.3.3 +Version: 2.3.4 Release: 1 Copyright: GPL Group: Utilities/System diff -Nur ksymoops-2.3.3/ksyms.c ksymoops-2.3.4/ksyms.c --- ksymoops-2.3.3/ksyms.c Tue Oct 19 08:21:36 1999 +++ ksymoops-2.3.4/ksyms.c Mon Apr 3 11:38:13 2000 @@ -92,37 +92,14 @@ re_strings_free(&re_modutils, &string); } -/* 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) +void add_ksyms(const char *address, char type, const char *symbol, const char *module) { - int i, n; - char **string = NULL, type; + int n; 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,})" /* 1 address */ - " +" /* white space */ - "([^ ]+)" /* 2 symbol */ - "( +\\[([^ ]+)\\])?$", /* 3,4 space, module (optional) */ - REG_NEWLINE|REG_EXTENDED, - &re_ksyms_pmatch); - - i = regexec(&re_ksyms, line, - re_ksyms.re_nsub+1, re_ksyms_pmatch, 0); - DEBUG(4, "regexec %d", i); - if (i) - return; - - re_strings(&re_ksyms, line, re_ksyms_pmatch, &string); - if (string[4]) { - if (!prev_module || strcmp(prev_module, string[4])) { + if (module) { + if (!prev_module || strcmp(prev_module, module)) { /* start of a new module in ksyms */ ++ss_ksyms_modules; ss_ksyms_module = realloc(ss_ksyms_module, @@ -133,8 +110,8 @@ malloc(sizeof(*(ss_ksyms_module[0]))); if (!ssp) malloc_error("alloc ss_ksyms_module[n]"); - ss_init(ssp, string[4]); - prev_module = strdup(string[4]); + ss_init(ssp, module); + prev_module = strdup(module); if (!prev_module) malloc_error("strdup prev_module"); } @@ -143,16 +120,41 @@ else ssp = &ss_ksyms_base; - type = ' '; - if (strncmp(string[2], MODUTILS_PREFIX, sizeof(MODUTILS_PREFIX)-1) == 0) + if (type == ' ' && strncmp(symbol, MODUTILS_PREFIX, sizeof(MODUTILS_PREFIX)-1) == 0) type = 'G'; /* generated symbol to assist ksymoops */ - else - type = ' '; /* no type available for ksyms symbols */ - n = add_symbol(ssp, string[1], type, 1, string[2]); - + n = add_symbol(ssp, address, type, 1, symbol); if (type == 'G') assist_ksyms(ssp, n); +} +/* 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; + 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,})" /* 1 address */ + " +" /* white space */ + "([^ ]+)" /* 2 symbol */ + "( +\\[([^ ]+)\\])?$", /* 3,4 space, module (optional) */ + REG_NEWLINE|REG_EXTENDED, + &re_ksyms_pmatch); + + i = regexec(&re_ksyms, line, + re_ksyms.re_nsub+1, re_ksyms_pmatch, 0); + DEBUG(4, "regexec %d", i); + if (i) + return; + + re_strings(&re_ksyms, line, re_ksyms_pmatch, &string); + add_ksyms(string[1], ' ', string[2], string[4]); re_strings_free(&re_ksyms, &string); } diff -Nur ksymoops-2.3.3/map.c ksymoops-2.3.4/map.c --- ksymoops-2.3.3/map.c Sun Jan 9 18:19:54 2000 +++ ksymoops-2.3.4/map.c Mon Apr 3 11:38:13 2000 @@ -18,6 +18,7 @@ FILE *f; char *line = NULL, **string = NULL; int i, size = 0; + static int merged = 0; static char const procname[] = "read_system_map"; if (!system_map) @@ -36,8 +37,23 @@ DEBUG(4, "regexec %d", 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]); + /* If the input is a merged system map then it can contain module + * data, add these as if they came from ksyms. The system map is + * read last so we can check if there is any other module data, + * reading from both a merged map and module data doe snot make + * sense. + */ + if (string[5]) { + if (++merged == 1 && ss_ksyms_modules) + ERROR("%s appears to be a merged System.map, it contains [module] names.\n" + "\t\tYou also supplied ksyms, this combination makes no sense.\n" + "\t\tPlease use -VKLO -m %s.", + system_map, system_map); + add_ksyms(string[1], string[2][0], string[3], string[5]); + } + else + add_symbol(&ss_system_map, string[1], *string[2], + 1, string[3]); } } @@ -123,25 +139,25 @@ } /* Append the second symbol set onto the first */ -static void append_map(SYMBOL_SET *ss1, const SYMBOL_SET *ss2, char *module) +static void append_map(SYMBOL_SET *symbol, const SYMBOL_SET *related, char *module) { int i, symnum; SYMBOL *s; static char const procname[] = "append_map"; - if (!ss2 || !ss2->used) + if (!related || !related->used) return; - DEBUG_S(2, "%s to %s", ss2->source, ss1->source); + DEBUG_S(2, "%s to %s", related->source, symbol->source); if (module) DEBUG_E(2, " [%s]", module); else DEBUG_E(2, ""); - for (i = 0; i < ss2->used; ++i) { - s = ss2->symbol+i; + for (i = 0; i < related->used; ++i) { + s = related->symbol+i; if (s->keep) { - symnum = add_symbol_n(ss1, s->address, s->type, 1, s->name); - (ss1->symbol)[symnum].module = module; + symnum = add_symbol_n(symbol, s->address, s->type, 1, s->name); + (symbol->symbol)[symnum].module = module; } } } @@ -187,8 +203,11 @@ append_map(&ss_merged, &ss_ksyms_base, NULL); append_map(&ss_merged, &ss_system_map, NULL); for (i = 0; i < ss_ksyms_modules; ++i) - append_map(&ss_merged, (ss_ksyms_module[i])->related, - (ss_ksyms_module[i])->source); + append_map(&ss_merged, + (ss_ksyms_module[i]->related ? + ss_ksyms_module[i]->related : + ss_ksyms_module[i]), + ss_ksyms_module[i]->source); if (!ss_merged.used) WARNING("no symbols in merged map"); diff -Nur ksymoops-2.3.3/object.c ksymoops-2.3.4/object.c --- ksymoops-2.3.3/object.c Tue Oct 19 08:21:36 1999 +++ ksymoops-2.3.4/object.c Mon Apr 3 11:38:13 2000 @@ -67,7 +67,6 @@ vmlinux); } - /* Read the symbols from one object (module) */ void read_object(const char *object, int i) { diff -Nur ksymoops-2.3.3/oops.c ksymoops-2.3.4/oops.c --- ksymoops-2.3.3/oops.c Sun Jan 9 18:32:32 2000 +++ ksymoops-2.3.4/oops.c Sat Apr 8 23:35:53 2000 @@ -159,11 +159,32 @@ static char *Oops_code_to_file(const char *code, int size, const bfd *ibfd, OPTIONS *options) { - char *file; + char *file, *tmpdir; + int fd; bfd *obfd; const bfd_arch_info_type *bai; + static const char temp_suffix[] = "/ksymoops.XXXXXX"; + static char const procname[] = "Oops_code_to_file"; - file = tmpnam(NULL); + /* Security fix, use mkstemp and honour TMPDIR */ + if (!(tmpdir = getenv("TMPDIR")) || !*tmpdir) { +#ifdef P_tmpdir + tmpdir = P_tmpdir; +#else + tmpdir = "/tmp"; +#endif + } + file = malloc(strlen(tmpdir) + sizeof(temp_suffix)); + if (!file) + malloc_error(procname); + strcpy(file, tmpdir); + strcat(file, temp_suffix); + if ((fd = mkstemp(file)) < 0) { + ERROR("Unable to open mkstemp file '%s'\n", file); + perror(prefix); + return(NULL); + } + close(fd); /* Set the target on the output file */ if (!(obfd = bfd_openw(file, options->target))) { @@ -311,13 +332,13 @@ * this proc cares who created the Code: line. */ static int Oops_code_values(const unsigned char* code_text, unsigned char *code, - int *adjust, char ***string, int string_max, - const OPTIONS *options) + int *adjust, const OPTIONS *options) { - int byte = 0, byte_prev, len; + int byte = 0, byte_prev, len, ret = 1; U16 u16; U32 u32; U64 u64, value; + char **string = NULL; const char *p; static regex_t re_Oops_code_value; static regmatch_t *re_Oops_code_value_pmatch; @@ -342,38 +363,44 @@ */ RE_COMPILE(&re_Oops_code_value, "^" - "([<(]?)" /* 1 */ - "([0-9a-fA-F]+)" /* 2 */ - "[)>]?" - " *" + "(" /* 1 */ + "([<(]?)" /* 2 */ + "([0-9a-fA-F]+)" /* 3 */ + "[)>]?" + " *" + ")" + "|(Bad EIP value)" /* 4 */ , 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); + re_Oops_code_value_pmatch, &string); + if (string[4] && *(string[4])) { + ret = 0; + break; /* Bad EIP value, no code bytes */ + } if (byte >= CODE_SIZE) break; - value = hexstring((*string)[2]); + value = hexstring(string[3]); if (errno) { ERROR("Invalid hex value in code_value line, treated as zero - " - "'%s'\ncode_value line '%s'", (*string)[2], code_text); + "'%s'\ncode_value line '%s'", string[3], code_text); perror(prefix); value = 0; } - if ((*string)[1] && *((*string)[1])) + if (string[2] && *(string[2])) *adjust = -byte; /* this byte is EIP */ /* 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! */ - len = strlen((*string)[2]); + len = strlen(string[3]); byte_prev = byte; if (byte+len/2 > CODE_SIZE) { - WARNING("extra values in Code line, ignored - '%s'", (*string)[2]); + WARNING("extra values in Code line, ignored - '%s'", string[3]); break; } switch (len) { @@ -397,7 +424,7 @@ break; default: ERROR("invalid value 0x%s in Code line, must be 2, 4, 8 or 16 " - "digits, value ignored", (*string)[2]); + "digits, value ignored", string[3]); break; } if (options->endianess && len != 2) { @@ -415,10 +442,11 @@ p += re_Oops_code_value_pmatch[0].rm_eo; } - if (*p) + if (ret && *p) WARNING("garbage '%s' at end of code line ignored", p); - return(1); + re_strings_free(&re_Oops_code_value, &string); + return(ret); } /* Add an objdump line to the symbol table. Just to keep the non-ix86 users @@ -492,16 +520,21 @@ static regex_t re_Oops_i370_regs; static regmatch_t *re_Oops_i370_regs_pmatch; +static int s390_reg_num = -1; /* All address arithmetic is done in 64 bit mode, truncate to the result to * a valid range for the target. */ static addr_t Oops_truncate_address(addr_t address, const OPTIONS *options) { - if (options->address_bits == 32 || strstr(options->target, "i370")) { + if (options->address_bits == 32 || + (options->target && ( + strstr(options->target, "i370") || + strstr(options->target, "s390")))) { U32 u32 = address; - if (strstr(options->target, "i370")) - u32 &= 0x7fffffff; /* Really 31 bit addressing on i370 */ + if (strstr(options->target, "i370") || + strstr(options->target, "s390")) + u32 &= 0x7fffffff; /* Really 31 bit addressing on i370/s390 */ return(u32); } return(address); /* 0, 64, anything else */ @@ -527,7 +560,8 @@ } if (strstr(options->target, "powerpc")) return("NIP"); - if (strstr(options->target, "i370")) + if (strstr(options->target, "i370") || + strstr(options->target, "s390")) return("PSW"); return("???"); } @@ -545,6 +579,8 @@ 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_kdb; + static regmatch_t *re_Oops_eip_kdb_pmatch; static regex_t re_Oops_eip_other; static regmatch_t *re_Oops_eip_other_pmatch; static const char procname[] = "Oops_eip"; @@ -635,6 +671,28 @@ return((*string)[re_Oops_eip_mips.re_nsub]); } + /* SGI kdb backtrace EIP. At start of line, 0x unbracketed + * address, 0x unbracketed address, anything, '+0x'. The second + * unbracketed address is the EIP. + */ + RE_COMPILE(&re_Oops_eip_kdb, + "^0x" UNBRACKETED_ADDRESS /* 1 */ + "0x" UNBRACKETED_ADDRESS /* 2 */ + ".*+0x", + REG_NEWLINE|REG_EXTENDED|REG_ICASE, + &re_Oops_eip_kdb_pmatch); + + i = regexec(&re_Oops_eip_kdb, line, re_Oops_eip_kdb.re_nsub+1, + re_Oops_eip_kdb_pmatch, 0); + DEBUG(4, "regexec kdb %d", i); + if (i == 0) { + re_string_check(re_Oops_eip_kdb.re_nsub+1, string_max, + procname); + re_strings(&re_Oops_eip_kdb, line, re_Oops_eip_kdb_pmatch, + string); + return((*string)[2]); + } + /* Oops 'EIP:' line for other architectures */ RE_COMPILE(&re_Oops_eip_other, "^(" @@ -885,6 +943,40 @@ add_symbol_n(ss, PSW, 'E', 1, ">>PSW;"); } +/* Look for the s390 PSW line, returns start of the relevant hex value */ +static char *Oops_s390_psw(const char *line, char ***string, int string_max) +{ + int i; + static regex_t re_Oops_s390_psw; + static regmatch_t *re_Oops_s390_psw_pmatch; + static const char procname[] = "Oops_s390_psw"; + + /* Oops 'User PSW:' line for s390, PSW at start of line, value is + * second address. + */ + RE_COMPILE(&re_Oops_s390_psw, + "^User PSW: *" + UNBRACKETED_ADDRESS /* flags */ + UNBRACKETED_ADDRESS, + REG_NEWLINE|REG_EXTENDED|REG_ICASE, + &re_Oops_s390_psw_pmatch); + + i = regexec(&re_Oops_s390_psw, line, re_Oops_s390_psw.re_nsub+1, + re_Oops_s390_psw_pmatch, 0); + DEBUG(4, "regexec %d", i); + if (i == 0) { + re_string_check(re_Oops_s390_psw.re_nsub+1, string_max, procname); + re_strings(&re_Oops_s390_psw, line, re_Oops_s390_psw_pmatch, + string); + return((*string)[re_Oops_s390_psw.re_nsub]); + } + return(NULL); +} + +/* No need for Oops_set_s390_psw, can use Oops_set_i370_psw for both */ +#define Oops_set_s390_psw(line, string, string_max) \ + Oops_set_i370_psw(line, string, string_max) + /* Look for the Trace multilines :(. Returns start of addresses. */ static const char *Oops_trace(const char *line) { @@ -900,6 +992,11 @@ * bracketed address. Alas users have been known to split lines so "(nn)" * appears at the start of the continuation line, look for that as well. * Life would be so much easier without users. + * The person who did the s390 trace obviously did not like any of the ways + * that other Linux kernels report problems so they invented a system all on + * their own. It is different from the i370 trace and even more ambiguous + * than the other trace formats. That is what happens when code is written + * in secret! */ RE_COMPILE(&re_Oops_trace, "^(" /* 1 */ @@ -907,12 +1004,13 @@ /* alpha */ "|(Trace: )" /* 3 */ /* various */ "|(" BRACKETED_ADDRESS ")" /* 4,5 */ /* ppc */ "|(Call backtrace:)" /* 6 */ - /* ppc */ "|" UNBRACKETED_ADDRESS /* 7 */ + /* ppc, s390 */ "|" UNBRACKETED_ADDRESS /* 7 */ /* arm */ "|Function entered at (" BRACKETED_ADDRESS ")" /* 8,9 */ /* sparc64 */ "|Caller\\[" UNBRACKETED_ADDRESS "\\]" /* 10 */ /* i386 */ "|(" REVBRACKETED_ADDRESS ")" /* 11,12 */ /* ikd patch */ "|(\\([0-9]+\\) *(" BRACKETED_ADDRESS "))" /* 13,14,15 */ /* i370 */ "|([0-9]+ +base=0x" UNBRACKETED_ADDRESS ")" /* 16,17 */ + /* s390 */ "|(Kernel BackChain.*)" /* 18 */ ")", REG_NEWLINE|REG_EXTENDED|REG_ICASE, &re_Oops_trace_pmatch); @@ -948,6 +1046,11 @@ trace_line = 3; start = line + re_Oops_trace_pmatch[17].rm_so; } + else if (MATCHED(18)) { + /* s390 only line, no addresses on this line */ + trace_line = 4; + start = line + re_Oops_trace_pmatch[18].rm_eo; + } else if (MATCHED(11)) { /* Reversed addresses for spinloops :( */ trace_line = 1; @@ -959,8 +1062,8 @@ else if (trace_line == 1 && MATCHED(14)) /* incorrectly split trace lines from ikd patch */ start = line + re_Oops_trace_pmatch[14].rm_so; - else if (trace_line == 2 && MATCHED(7)) - /* ppc continuation line */ + else if ((trace_line == 2 || trace_line == 4) && MATCHED(7)) + /* ppc/s390 continuation line */ start = line + re_Oops_trace_pmatch[7].rm_so; else trace_line = 0; @@ -991,7 +1094,7 @@ REG_NEWLINE|REG_EXTENDED, &re_ikd_pmatch); - /* ppc does not bracket its addresses */ + /* ppc/s390 does not bracket its addresses */ if (isxdigit(*p)) { pregex = &re_unbracketed_address; pregmatch = re_unbracketed_address_pmatch; @@ -1033,7 +1136,7 @@ static const char procname[] = "Oops_i370_regs"; RE_COMPILE(&re_Oops_i370_regs, - "^ *(r[0-9]{1,2}): *" UNBRACKETED_ADDRESS, /* 1, 2 */ + "^(r[0-9]{1,2}): *" UNBRACKETED_ADDRESS, /* 1, 2 */ REG_NEWLINE|REG_EXTENDED|REG_ICASE, &re_Oops_i370_regs_pmatch); @@ -1087,6 +1190,85 @@ re_strings_free(&re_Oops_i370_regs, &string); } +/* Decide if the line contains s390 registers. Returns first register value. + * This is messier than the trace lines. The heading is on one line followed by + * the registers with *NO* keywords. Fine for a dedicated JESMSG file, very + * poor design for a multi-user log system. + */ +static const char *Oops_s390_regs(const char *line) +{ + int i; + static regex_t re_Oops_s390_regs; + static regmatch_t *re_Oops_s390_regs_pmatch; + static const char procname[] = "Oops_s390_regs"; + + RE_COMPILE(&re_Oops_s390_regs, + "^(User GPRS.*)", + REG_NEWLINE|REG_EXTENDED|REG_ICASE, + &re_Oops_s390_regs_pmatch); + + i = regexec(&re_Oops_s390_regs, line, re_Oops_s390_regs.re_nsub+1, + re_Oops_s390_regs_pmatch, 0); + DEBUG(4, "regexec %d", i); + if (i == 0) { + s390_reg_num = 0; /* Start with R0 */ + return(line + re_Oops_s390_regs_pmatch[0].rm_eo); + } + else if (s390_reg_num >= 0) /* Header already seen */ { + i = regexec(&re_unbracketed_address, line, + re_unbracketed_address.re_nsub+1, + re_unbracketed_address_pmatch, 0); + DEBUG(4, "regexec %d", i); + if (i == 0) + return(line + re_unbracketed_address_pmatch[0].rm_so); + } + s390_reg_num = -1; /* Not processing s390 registers */ + return(NULL); +} + +/* Process a s390 register line, extract addresses */ +static void Oops_set_s390_regs(const char *line, const char *p, + SYMBOL_SET *ss, const OPTIONS *options) +{ + addr_t reg; + char regname[7]; + char **string = NULL; + static const char procname[] = "Oops_set_s390_regs"; + + /* Loop over s390 unbracketed register values. No keywords so we have to + * synthesize the register numbers ourselves, yuck! + */ + while (1) { + if (regexec(&re_unbracketed_address, p, + re_unbracketed_address.re_nsub+1, + re_unbracketed_address_pmatch, 0) == 0) { + re_strings(&re_unbracketed_address, p, + re_unbracketed_address_pmatch, &string); + reg = hexstring(string[1]); /* contents */ + if (errno) { + ERROR(" Invalid hex value in s390 register line, ignored - '%s'", + string[1]); + perror(prefix); + reg = 0; + } + reg = Oops_truncate_address(reg, options); + if (reg > 1024) { + strcpy(regname, ">>"); + snprintf(regname, sizeof(regname), "r%-2d; ", s390_reg_num); + add_symbol_n(ss, reg, 'R', 1, regname); + } + p += re_unbracketed_address_pmatch[0].rm_eo; + ++s390_reg_num; + } + else + break; + } + + if (*p) + WARNING("garbage '%s' at end of s390 register line ignored", p); + re_strings_free(&re_unbracketed_address, &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 @@ -1223,6 +1405,13 @@ * of multiple lines, each containing a number (trace depth), base=, link=, * stack=. * + * s390 decided to do their own thing instead of using the same format as + * i370. A bad case of "not invented here". s390 data starts on a separate + * line and consists of multiple addresses. + * + * The SGI kdb backtrace for ix86 prints EBP and EIP, one per line after the + * header. + * * Some strings indicate stack data (S), some indicate trace data (T). */ RE_COMPILE(&re_Oops_print_s, @@ -1230,7 +1419,7 @@ "^(" /* 1 */ /* i386 */ "(Stack: )" /* 2 S */ /* m68k */ "|(Stack from )" /* 3 S */ - /* various */ "|([0-9a-fA-F]{4,})" /* 4 S */ + /* various */ "|([0-9a-fA-F]{4,})" /* 4 S,T */ /* various */ "|(Call Trace: )" /* 5 T */ /* various */ "|(" BRACKETED_ADDRESS ")" /* 6,7 T */ /* various */ "|(Version_[0-9]+)" /* 8 */ @@ -1241,6 +1430,9 @@ /* ikd/AK */ "|(\\([^ ]+\\) *" /* 13 T */ BRACKETED_ADDRESS ")" /* 14 */ /* i370 */ "|([0-9]+ +base=)" /* 15 T */ + /* s390 */ "|(Kernel BackChain)" /* 16 T */ + /* kdb ix86 */ "|EBP *EIP" /* 17 T */ + /* kdb ix86 */ "|0x" UNBRACKETED_ADDRESS "0x" UNBRACKETED_ADDRESS /* 18, 19 T */ /* order does not matter from here on */ @@ -1341,6 +1533,13 @@ /* i370 */ "|Kernel stack " /* any other i370 lines to print? */ + /* s390 */ "|User PSW" + /* s390 */ "|User GPRS" + /* s390 */ "|User ACRS" + /* s390 */ "|illegal operation" + /* s390 */ "|task:" + /* any other s390 lines to print? */ + ")", REG_NEWLINE|REG_EXTENDED|REG_ICASE, &re_Oops_print_s_pmatch); @@ -1356,6 +1555,9 @@ /* Handle multiline messages, messy. Only treat strings that look like * addresses as useful when they immediately follow a definite stack or * trace header or a previously valid stack or trace line. + * Because of the horribly ambiguous s390 register dump, unbracketed + * addresses (string 4) can now be either stack or trace. How not to design + * dump output. */ /* Stack lines */ if (!MATCHED(2) && !MATCHED(3) && !MATCHED(4)) @@ -1365,19 +1567,21 @@ else if (stack_line && !MATCHED(4)) stack_line = 0; /* Trace lines */ - if (!MATCHED(5) && !MATCHED(6) && !MATCHED(9) && !MATCHED(10) && - !MATCHED(11) && !MATCHED(12) && !MATCHED(13) && !MATCHED(15)) + if (!MATCHED(4) && !MATCHED(5) && !MATCHED(6) && !MATCHED(9) && + !MATCHED(10) && !MATCHED(11) && !MATCHED(12) && !MATCHED(13) && + !MATCHED(15) && !MATCHED(16) && !MATCHED(17) && !MATCHED(19)) trace_line = 0; - else if (MATCHED(5) || MATCHED(9) || MATCHED(10) || MATCHED(11) || - MATCHED(15)) + else if (MATCHED(4) || MATCHED(5) || MATCHED(9) || MATCHED(10) || + MATCHED(11) || MATCHED(15) || MATCHED(16) || MATCHED(17)) trace_line = 1; - else if (trace_line && !MATCHED(6) && !MATCHED(12) && !MATCHED(13)) + else if (trace_line && !MATCHED(4) && !MATCHED(6) && !MATCHED(12) && + !MATCHED(13) && !MATCHED(19)) trace_line = 0; if (i == 0) { print = 1; - if (MATCHED(4) && !stack_line) { + if (MATCHED(4) && !stack_line && !trace_line) { print = 0; - DEBUG(4, "ambiguous stack line ignored"); + DEBUG(4, "ambiguous stack/trace line ignored"); } if ((MATCHED(6) || MATCHED(12) || MATCHED(13)) && !trace_line) { print = 0; @@ -1493,6 +1697,7 @@ ": +" "(" /* 4 */ "(general protection.*)" + "|(Bad EIP value.*)" "|(<[0-9]+>)" "|(([<(]?[0-9a-fA-F]+[>)]? +)+[<(]?[0-9a-fA-F]+[>)]?)" ")" @@ -1544,8 +1749,7 @@ DEBUG(1, ""); /* text to binary */ - if (!Oops_code_values(code_text, code, &adjust, string, string_max, - options)) + if (!Oops_code_values(code_text, code, &adjust, options)) return; /* binary to same format as ksymoops */ if (!(file = Oops_code_to_file(code, CODE_SIZE, ibfd, options))) @@ -1722,10 +1926,14 @@ Oops_set_sparc_oi7(start, &string, &ss_format); if ((start = Oops_i370_psw(text, &string, MAX_STRINGS))) Oops_set_i370_psw(start, &ss_format, options); + if ((start = Oops_s390_psw(text, &string, MAX_STRINGS))) + Oops_set_s390_psw(start, &ss_format, options); if ((start = Oops_trace(text))) Oops_trace_line(text, start, &ss_format); if ((start = Oops_i370_regs(text))) Oops_set_i370_regs(text, start, &ss_format, options); + if ((start = Oops_s390_regs(text))) + Oops_set_s390_regs(text, start, &ss_format, options); if ((start = Oops_code(text, &string, MAX_STRINGS))) { /* In case no EIP line was seen */ Oops_set_default_ta(me, ibfd, options); diff -Nur ksymoops-2.3.3/re.c ksymoops-2.3.4/re.c --- ksymoops-2.3.3/re.c Tue Oct 19 08:21:36 1999 +++ ksymoops-2.3.4/re.c Mon Apr 3 11:38:13 2000 @@ -42,9 +42,9 @@ void re_compile_common(void) { - /* nm: address, type, symbol */ + /* nm: address, type, symbol, optional [module] */ RE_COMPILE(&re_nm, - "^([0-9a-fA-F]{4,}) +([^ ]) +([^ ]+)$", + "^([0-9a-fA-F]{4,}) +([^ ]) +([^ ]+)( +\\[([^ ]+)\\])?$", REG_NEWLINE|REG_EXTENDED, &re_nm_pmatch); diff -Nur ksymoops-2.3.3/symbol.c ksymoops-2.3.4/symbol.c --- ksymoops-2.3.3/symbol.c Sun Jan 9 18:01:58 2000 +++ ksymoops-2.3.4/symbol.c Wed Mar 29 11:09:32 2000 @@ -109,9 +109,9 @@ static regmatch_t *re_symbol_ver_pmatch; static const char procname[] = "add_symbol_n"; - /* Strip out any trailing symbol version _R(smp_|smp2gig_|2gig_)?xxxxxxxx. */ + /* Strip out any trailing symbol version _R.*xxxxxxxx. */ RE_COMPILE(&re_symbol_ver, - "^(.*)_R(smp_|smp2gig_|2gig_)?[0-9a-fA-F]{8,}$", + "^(.*)_R.*[0-9a-fA-F]{8,}$", REG_NEWLINE|REG_EXTENDED, &re_symbol_ver_pmatch);