diff -Nur ksymoops-2.4.4/Changelog ksymoops-2.4.5/Changelog --- ksymoops-2.4.4/Changelog Fri Mar 1 13:00:46 2002 +++ ksymoops-2.4.5/Changelog Mon Mar 18 20:56:29 2002 @@ -1,3 +1,11 @@ +2002-03-18 Keith Owens + + ksymoops 2.4.5 + + * Add x86-64 support. Andi Kleen. + * Clean up and generalize register dumps. + * Print blank lines between each major block of output for readability. + 2002-03-01 Keith Owens ksymoops 2.4.4 diff -Nur ksymoops-2.4.4/ksymoops.8 ksymoops-2.4.5/ksymoops.8 --- ksymoops-2.4.4/ksymoops.8 Fri Sep 21 18:48:33 2001 +++ ksymoops-2.4.5/ksymoops.8 Mon Mar 18 20:35:33 2002 @@ -1,4 +1,4 @@ -.TH KSYMOOPS 8 "September 2001" +.TH KSYMOOPS 8 "March 18, 2002" .hy 0 .UC 4 .SH NAME @@ -458,10 +458,11 @@ .P An input line can have a prefix which ksymoops will print as part of the line but ignore during analysis. A prefix can be from syslogd(8) -(consisting of date, time, hostname, 'kernel:'), it can be '<\fIn\fR>' -from /proc/kmsg or the prefix can just be leading spaces. "start of -line" means the first character after skipping all prefixes, including -all leading space. +(consisting of date, time, hostname, 'kernel:'), from syslog-ng +(numbers and three other strings separated by '|'), it can be +'<\fIn\fR>' from /proc/kmsg or the prefix can just be leading spaces. +"start of line" means the first character after skipping all prefixes, +including all leading space. .P Every kernel architecture team uses different messages for kernel problems, see Oops_read in oops.c for the full, gory list. If you are @@ -493,6 +494,9 @@ The ix86 EIP line is 'EIP:' at start of line, at least one space, any text, bracketed address. +The x86_64 EIP line is 'RIP:' at start of line, at least one space, any +text, bracketed address. + The m68k PC line is 'PC' at start of line, optional spaces, '=', optional spaces, bracketed address. @@ -505,16 +509,20 @@ A mips ra line is 'ra', optional spaces, one or more '=', optional spaces, unbracketed address. -A sparc o7 or i7 line is 'i' or 'o', '0' or '4', ':', space, one or -more occurrences of (hex digit, space, 'iosp:'), space, ('i' or 'o', -\'7') or ('ret_pc'). - A sparc register dump line is ('i', '0' or '4', ':', space) or ('Instruction DUMP:', space) or ('Caller['). The IA64 b0 line is 'b0', optional space, ':', optional space, unbracketed address. This can be repeated for other b registers, e.g. b6, b7. + +Register dumps have a plethora of formats. Most are of the form \'name: +value' repeated across a line, some architectures use \'=' instead of +\':'. See Oops_regs for the current list of recognised register names. +Besides the Oops_regs list, i370, mips, ppc and s390 have special +register dump formats, typically one register name is printed followed +by multiple values. ksymoops extracts all register contents and +decodes those values above an arbitrary cutoff of 1024. A set of call trace lines starts with 'Trace:' or 'Call\ Trace:' or \'Call\ Backtrace:' (ppc only) or 'Function\ entered\ at' (arm only) or diff -Nur ksymoops-2.4.4/ksymoops.c ksymoops-2.4.5/ksymoops.c --- ksymoops-2.4.4/ksymoops.c Sat Jan 26 12:44:46 2002 +++ ksymoops-2.4.5/ksymoops.c Fri Mar 1 18:19:32 2002 @@ -9,7 +9,7 @@ Released under the GNU Public Licence, Version 2. */ -#define VERSION "2.4.4" +#define VERSION "2.4.5" #include "ksymoops.h" #include diff -Nur ksymoops-2.4.4/ksymoops.spec ksymoops-2.4.5/ksymoops.spec --- ksymoops-2.4.4/ksymoops.spec Sat Sep 22 12:00:40 2001 +++ ksymoops-2.4.5/ksymoops.spec Fri Mar 1 18:19:32 2002 @@ -1,6 +1,6 @@ Summary: Kernel oops and error message decoder Name: ksymoops -Version: 2.4.4 +Version: 2.4.5 Release: 1 Copyright: GPL Group: Utilities/System diff -Nur ksymoops-2.4.4/oops.c ksymoops-2.4.5/oops.c --- ksymoops-2.4.4/oops.c Fri Mar 1 13:00:46 2002 +++ ksymoops-2.4.5/oops.c Mon Mar 18 19:22:11 2002 @@ -543,14 +543,102 @@ return(1); } +static regex_t re_Oops_regs; +static regmatch_t *re_Oops_regs_pmatch; + +/* Decide if the line contains registers. Returns first register name. */ +static const char *Oops_regs(const char *line) +{ + int i; + const char *p; + static const char procname[] = "Oops_regs"; + + RE_COMPILE(&re_Oops_regs, + "^(" /* 1 */ + "(GP|o)?r[0-9]{1,2}" /* 2 */ + "|[goli][0-9]{1,2}" + "|[eR][ABCD]X" + "|[eR][DS]I" + "|RBP" + "|e[bs]p" + "|[fsi]p" + "|IRP" + "|SRP" + "|D?CCR" + "|USP" + "|MOF" + "|ret_pc" + ")" + " *[:=] *" + UNBRACKETED_ADDRESS /* 3 */ + " *" + , + REG_NEWLINE|REG_EXTENDED|REG_ICASE, + &re_Oops_regs_pmatch); + + i = regexec(&re_Oops_regs, line, re_Oops_regs.re_nsub+1, + re_Oops_regs_pmatch, 0); + DEBUG(4, "regexec %d", i); + if (i) + return(NULL); + /* Some lines just have one register at the start followed by a set of + * values, those lines are handled as special cases because I have to + * generate the register numbers. This code only routines lines that + * contain exactly one value or each value is preceded by ':' or '='. + * Lazy check, any ':' or '=' in the rest of the line will do. + */ + p = line + re_Oops_regs_pmatch[0].rm_eo; + if (*p && !index(p, ':') && !index(p, '=')) + return(NULL); + return(line + re_Oops_regs_pmatch[0].rm_so); +} + +/* Process a register line, extract addresses */ +static void Oops_set_regs(const char *line, const char *p, + SYMBOL_SET *ss, const OPTIONS *options) +{ + addr_t reg; + char regname[20]; + char **string = NULL; + static const char procname[] = "Oops_set_regs"; + + /* Loop over register names and unbracketed addresses */ + while (1) { + if (regexec(&re_Oops_regs, p, re_Oops_regs.re_nsub+1, + re_Oops_regs_pmatch, 0) == 0) { + re_strings(&re_Oops_regs, p, re_Oops_regs_pmatch, &string); + reg = hexstring(string[3]); /* contents */ + if (errno) { + ERROR(" Invalid hex value in register line, ignored - '%s'", + string[3]); + perror(prefix); + reg = 0; + } + reg = Oops_truncate_address(reg, options); + if (reg > 1024) { + strcpy(regname, ">>"); + strncpy(regname+2, string[1], sizeof(regname)-2); + if (strlen(regname) < sizeof(regname)-1) + strcat(regname, ";"); + add_symbol_n(ss, reg, 'R', 1, regname); + } + p += re_Oops_regs_pmatch[0].rm_eo; + } + else + break; + } + + if (*p) + WARNING("garbage '%s' at end of register line ignored", p); + re_strings_free(&re_Oops_regs, &string); +} + /******************************************************************************/ /* Start architecture sensitive code */ /******************************************************************************/ static regex_t re_Oops_cris_regs; static regmatch_t *re_Oops_cris_regs_pmatch; -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 @@ -598,6 +686,10 @@ return("PSW"); if (strstr(options->target, "ia64")) return("IP"); + if (strstr(options->target, "x86_64") || + strstr(options->target, "x86-64") || + strstr(options->target, "x8664")) + return("RIP"); return("???"); } @@ -787,6 +879,7 @@ RE_COMPILE(&re_Oops_eip_other, "^(" "EIP: +.*" /* i386 */ + "|RIP: +.*" /* x86_64 */ "|PC *= *" /* m68k, alpha */ "|pc *: *" /* arm */ ")" @@ -995,6 +1088,62 @@ add_symbol_n(ss, ra, 'R', 1, ">>RA; "); } +/* Extract mips registers. */ +static void Oops_mips_regs(const char *line, SYMBOL_SET *ss, const OPTIONS *options) +{ + int i, reg_num; + addr_t reg; + char regname[7]; + char **string = NULL; + const char *p; + static regex_t re_Oops_mips_regs; + static regmatch_t *re_Oops_mips_regs_pmatch; + static const char procname[] = "Oops_mips_regs"; + + RE_COMPILE(&re_Oops_mips_regs, + "^(\\$[0-9]{1,2}) *: *" /* 1 */ + UNBRACKETED_ADDRESS /* 2 */ + , + REG_NEWLINE|REG_EXTENDED|REG_ICASE, + &re_Oops_mips_regs_pmatch); + + i = regexec(&re_Oops_mips_regs, line, re_Oops_mips_regs.re_nsub+1, + re_Oops_mips_regs_pmatch, 0); + DEBUG(4, "regexec %d", i); + if (i) + return; + p = line + re_Oops_mips_regs_pmatch[0].rm_so + 1; + reg_num = strtoul(p, NULL, 10); + p = line + re_Oops_mips_regs_pmatch[2].rm_so; + /* Loop over unbracketed addresses */ + 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 register line, ignored - '%s'", + string[1]); + perror(prefix); + break; + } + reg = Oops_truncate_address(reg, options); + if (reg > 1024) { + snprintf(regname, sizeof(regname), ">>$%d;", reg_num); + add_symbol_n(ss, reg, 'R', 1, regname); + } + p += re_unbracketed_address_pmatch[0].rm_eo; + ++reg_num; + } + else + break; + } + + if (*p) + WARNING("garbage '%s' at end of mips register line ignored", p); + re_strings_free(&re_unbracketed_address, &string); +} + /* Look for the ia64 b0 line and set all the values */ static void Oops_set_ia64_b0(const char *line, char ***string, int string_max, SYMBOL_SET *ss) { @@ -1037,52 +1186,6 @@ } } -/* Look for the sparc o7/i7 registers line, returns start of the relevant hex - * value. - */ -static char *Oops_sparc_oi7(const char *line, char ***string, int string_max) -{ - int i; - static regex_t re_Oops_sparc_oi7; - static regmatch_t *re_Oops_sparc_oi7_pmatch; - static const char procname[] = "Oops_sparc_oi7"; - - RE_COMPILE(&re_Oops_sparc_oi7, - "^[io][04]: [0-9a-fA-F iosp:]+ ([io]7|ret_pc): " - UNBRACKETED_ADDRESS, - REG_NEWLINE|REG_EXTENDED|REG_ICASE, - &re_Oops_sparc_oi7_pmatch); - - re_string_check(re_Oops_sparc_oi7.re_nsub+1, string_max, procname); - i = regexec(&re_Oops_sparc_oi7, line, re_Oops_sparc_oi7.re_nsub+1, - re_Oops_sparc_oi7_pmatch, 0); - DEBUG(4, "regexec %d", i); - if (i == 0) { - re_strings(&re_Oops_sparc_oi7, line, re_Oops_sparc_oi7_pmatch, - string); - return((*string)[re_Oops_sparc_oi7.re_nsub]); - } - return(NULL); -} - -/* Set the sparc o7/i7 from the oi7 line */ -static void Oops_set_sparc_oi7(const char *value, char ***string, - SYMBOL_SET *ss) -{ - static const char procname[] = "Oops_set_sparc_oi7"; - addr_t oi7; - int o7 = 1; - if ((*string)[1] && !strcmp((*string)[1], "i7")) - o7 = 0; - oi7 = hexstring(value); - if (errno) { - ERROR("Invalid hex value in oi7 line, ignored - '%s'", value); - perror(prefix); - 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, char ***string) { @@ -1192,6 +1295,62 @@ #define Oops_set_s390_psw(line, string, me, ibfd, options) \ Oops_set_i370_psw(line, string, me, ibfd, options) +/* Extract ppc registers. */ +static void Oops_ppc_regs(const char *line, SYMBOL_SET *ss, const OPTIONS *options) +{ + int i, reg_num; + addr_t reg; + char regname[9]; + char **string = NULL; + const char *p; + static regex_t re_Oops_ppc_regs; + static regmatch_t *re_Oops_ppc_regs_pmatch; + static const char procname[] = "Oops_ppc_regs"; + + RE_COMPILE(&re_Oops_ppc_regs, + "^(GPR[0-9]{1,2}) *: *" /* 1 */ + UNBRACKETED_ADDRESS /* 2 */ + , + REG_NEWLINE|REG_EXTENDED|REG_ICASE, + &re_Oops_ppc_regs_pmatch); + + i = regexec(&re_Oops_ppc_regs, line, re_Oops_ppc_regs.re_nsub+1, + re_Oops_ppc_regs_pmatch, 0); + DEBUG(4, "regexec %d", i); + if (i) + return; + p = line + re_Oops_ppc_regs_pmatch[0].rm_so + 3; + reg_num = strtoul(p, NULL, 10); + p = line + re_Oops_ppc_regs_pmatch[2].rm_so; + /* Loop over unbracketed addresses */ + 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 register line, ignored - '%s'", + string[1]); + perror(prefix); + break; + } + reg = Oops_truncate_address(reg, options); + if (reg > 1024) { + snprintf(regname, sizeof(regname), ">>GPR%d;", reg_num); + add_symbol_n(ss, reg, 'R', 1, regname); + } + p += re_unbracketed_address_pmatch[0].rm_eo; + ++reg_num; + } + else + break; + } + + if (*p) + WARNING("garbage '%s' at end of ppc register line ignored", p); + re_strings_free(&re_unbracketed_address, &string); +} + /* Look for the Trace multilines :(. Returns start of addresses. */ static const char *Oops_trace(const char *line) { @@ -1351,7 +1510,7 @@ static const char procname[] = "Oops_cris_regs"; /* Note that most of the register dump, the r0: to oR10: lines, are - handled by Oops_i370_regs. */ + handled by Oops_regs. */ RE_COMPILE(&re_Oops_cris_regs, "^(IRP|SRP|D?CCR|USP|MOF): *" UNBRACKETED_ADDRESS, REG_NEWLINE|REG_EXTENDED|REG_ICASE, @@ -1404,73 +1563,6 @@ re_strings_free(&re_Oops_cris_regs, &string); } -/* Decide if the line contains i370 registers. Returns first register name. */ -static const char *Oops_i370_regs(const char *line) -{ - int i; - static const char procname[] = "Oops_i370_regs"; - - /* Matching "oR10: unbracketed address" enables us to also match a - CRIS register dump for the lines that overlap with the i370 - register dump format. This can match arm lines by mistake, check - for a second register after the address. Only if the second register - is missing is this i370/cris. */ - RE_COMPILE(&re_Oops_i370_regs, - "^(o?r[0-9]{1,2}): *" /* 1 */ - UNBRACKETED_ADDRESS /* 2 */ - "( *r[0-9]{1,2})?" /* 3 */ - , - REG_NEWLINE|REG_EXTENDED|REG_ICASE, - &re_Oops_i370_regs_pmatch); - - i = regexec(&re_Oops_i370_regs, line, re_Oops_i370_regs.re_nsub+1, - re_Oops_i370_regs_pmatch, 0); - DEBUG(4, "regexec %d", i); - if (i == 0 && re_Oops_i370_regs_pmatch[3].rm_so == -1) - return(line + re_Oops_i370_regs_pmatch[0].rm_so); - return(NULL); -} - -/* Process a i370 register line, extract addresses */ -static void Oops_set_i370_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_i370_regs"; - - /* Loop over i370 register names and unbracketed addresses */ - while (1) { - if (regexec(&re_Oops_i370_regs, p, re_Oops_i370_regs.re_nsub+1, - re_Oops_i370_regs_pmatch, 0) == 0) { - re_strings(&re_Oops_i370_regs, p, re_Oops_i370_regs_pmatch, &string); - reg = hexstring(string[2]); /* contents */ - if (errno) { - ERROR(" Invalid hex value in i370 register line, ignored - '%s'", - string[2]); - perror(prefix); - reg = 0; - } - reg = Oops_truncate_address(reg, options); - if (reg > 1024) { - strcpy(regname, ">>"); - strncpy(regname+2, string[1], sizeof(regname)-2); - if (strlen(regname) < sizeof(regname)-1) - strcat(regname, ";"); - add_symbol_n(ss, reg, 'R', 1, regname); - } - p += re_Oops_i370_regs_pmatch[0].rm_eo; - } - else - break; - } - - if (*p) - WARNING("garbage '%s' at end of i370 register line ignored", p); - 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 @@ -1726,6 +1818,7 @@ /* various */ "|kmem_free" /* various */ "|swapper" /* various */ "|Pid:" + /* various */ "|r[0-9]{1,2} *[:=]" /* generic register dump */ /* i386 2.0 */ "|Corrupted stack page" /* i386 */ "|invalid operand: " @@ -1743,6 +1836,16 @@ /* i386 */ "|irq: " /* i386 */ "|Stack dumps:" + /* x86_64 */ "|RAX: " + /* x86_64 */ "|RSP: " + /* x86_64 */ "|RIP: " + /* x86_64 */ "|RDX: " + /* x86_64 */ "|RBP: " + /* x86_64 */ "|FS: " + /* x86_64 */ "|CS: " + /* x86_64 */ "|CR2: " + /* x86_64 */ "|PML4" + /* m68k */ "|pc[:=]" /* m68k */ "|68060 access" /* m68k */ "|Exception at " @@ -1795,7 +1898,6 @@ /* arm */ "|Internal error" /* arm */ "|pc :" /* arm */ "|sp :" - /* arm */ "|r[0-9][0-9 ]:" /* arm */ "|Flags:" /* arm */ "|Control:" /* any other arm lines to print? */ @@ -1807,7 +1909,6 @@ /* i370 */ "|PSW" /* i370 */ "|cr[0-9]+:" - /* i370 */ "|r[0-9]+:" /* i370 */ "|machine check" /* i370 */ "|Exception in " /* i370 */ "|Program Check " @@ -2002,7 +2103,7 @@ RE_COMPILE(&re_Oops_code, "^(" /* 1 */ /* various */ "(Instruction DUMP)" /* 2 */ - /* various */ "|(Code *)" /* 3 */ + /* various */ "|(Code:? *)" /* 3 */ ")" ": +" "(" /* 4 */ @@ -2088,7 +2189,7 @@ int i; SYMBOL *s; addr_t eip = 0; - char *eye_catcher; + char *eye_catcher, prev_type = '\0'; static const char procname[] = "Oops_format"; DEBUG(1, "%s", ""); @@ -2101,6 +2202,8 @@ * For other types print name, address, map. */ if (s->type == 'C') { + if (prev_type != s->type) + printf("\n"); eye_catcher = ""; if (eip && i < ss_format->used-1 && (s+1)->type == 'C' && eip >= s->address && eip < (s+1)->address) @@ -2120,6 +2223,8 @@ printf("%s\n", s->name); } else { + if (prev_type != s->type) + printf("\n"); printf("%s %s %s", s->name, format_address(s->address, options), @@ -2131,6 +2236,7 @@ } printf("\n"); } + prev_type = s->type; } printf("\n"); } @@ -2249,16 +2355,16 @@ } if ((start = Oops_mips_ra(text, &string, MAX_STRINGS))) Oops_set_mips_ra(start, &ss_format); - if ((start = Oops_sparc_oi7(text, &string, MAX_STRINGS))) - Oops_set_sparc_oi7(start, &string, &ss_format); + Oops_mips_regs(text, &ss_format, options); + Oops_ppc_regs(text, &ss_format, options); if ((start = Oops_i370_psw(text, &string, MAX_STRINGS))) Oops_set_i370_psw(start, &ss_format, me, ibfd, options); if ((start = Oops_s390_psw(text, &string, MAX_STRINGS))) Oops_set_s390_psw(start, &ss_format, me, ibfd, 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_regs(text))) + Oops_set_regs(text, start, &ss_format, options); if ((start = Oops_s390_regs(text))) Oops_set_s390_regs(text, start, &ss_format, options); if ((start = Oops_cris_regs(text)))