|
Packit Service |
8a8a03 |
/*
|
|
Packit Service |
8a8a03 |
Copyright (C) 2011 ABRT team
|
|
Packit Service |
8a8a03 |
Copyright (C) 2011 RedHat Inc
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
8a8a03 |
it under the terms of the GNU General Public License as published by
|
|
Packit Service |
8a8a03 |
the Free Software Foundation; either version 2 of the License, or
|
|
Packit Service |
8a8a03 |
(at your option) any later version.
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
This program is distributed in the hope that it will be useful,
|
|
Packit Service |
8a8a03 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
8a8a03 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
8a8a03 |
GNU General Public License for more details.
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
You should have received a copy of the GNU General Public License along
|
|
Packit Service |
8a8a03 |
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit Service |
8a8a03 |
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
#include <satyr/stacktrace.h>
|
|
Packit Service |
8a8a03 |
#include <satyr/thread.h>
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
#include <regex.h>
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
#define _GNU_SOURCE 1 /* for strcasestr */
|
|
Packit Service |
8a8a03 |
#include "libabrt.h"
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* Used to be 100, but some MCE oopses are short:
|
|
Packit Service |
8a8a03 |
* "CPU 0: Machine Check Exception: 0000000000000007"
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
#define SANE_MIN_OOPS_LEN 30
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
static void record_oops(GList **oops_list, const struct abrt_koops_line_info* lines_info, int oopsstart, int oopsend)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
int q;
|
|
Packit Service |
8a8a03 |
int len;
|
|
Packit Service |
8a8a03 |
int rv = 1;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
len = 2;
|
|
Packit Service |
8a8a03 |
for (q = oopsstart; q <= oopsend; q++)
|
|
Packit Service |
8a8a03 |
len += strlen(lines_info[q].ptr) + 1;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* too short oopses are invalid */
|
|
Packit Service |
8a8a03 |
if (len > SANE_MIN_OOPS_LEN)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
char *oops = (char*)xzalloc(len);
|
|
Packit Service |
8a8a03 |
char *dst = oops;
|
|
Packit Service |
8a8a03 |
char *version = NULL;
|
|
Packit Service |
8a8a03 |
for (q = oopsstart; q <= oopsend; q++)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (!version)
|
|
Packit Service |
8a8a03 |
version = koops_extract_version(lines_info[q].ptr);
|
|
Packit Service |
8a8a03 |
if (lines_info[q].ptr[0])
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
dst = stpcpy(dst, lines_info[q].ptr);
|
|
Packit Service |
8a8a03 |
dst = stpcpy(dst, "\n");
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
if ((dst - oops) > SANE_MIN_OOPS_LEN)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
*oops_list = g_list_append(
|
|
Packit Service |
8a8a03 |
*oops_list,
|
|
Packit Service |
8a8a03 |
xasprintf("%s\n%s", (version ? version : ""), oops)
|
|
Packit Service |
8a8a03 |
);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
else
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* too short oopses are invalid */
|
|
Packit Service |
8a8a03 |
rv = 0;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
free(oops);
|
|
Packit Service |
8a8a03 |
free(version);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
VERB3 if (rv == 0) log_warning("Dropped oops: too short");
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* In some comparisons, we skip 1st letter, to avoid dealing with
|
|
Packit Service |
8a8a03 |
* changes in capitalization in kernel. For example, I see that
|
|
Packit Service |
8a8a03 |
* current kernel git (at 2011-01-01) has both "kernel BUG at ..."
|
|
Packit Service |
8a8a03 |
* and "Kernel BUG at ..." messages, and I don't want to change
|
|
Packit Service |
8a8a03 |
* the code below whenever kernel is changed to use "K" (or "k")
|
|
Packit Service |
8a8a03 |
* uniformly.
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
static const char *const s_koops_suspicious_strings[] = {
|
|
Packit Service |
8a8a03 |
"BUG:",
|
|
Packit Service |
8a8a03 |
"WARNING: at",
|
|
Packit Service |
8a8a03 |
"WARNING: CPU:",
|
|
Packit Service |
8a8a03 |
"INFO: possible recursive locking detected",
|
|
Packit Service |
8a8a03 |
/*k*/"ernel BUG at",
|
|
Packit Service |
8a8a03 |
"list_del corruption",
|
|
Packit Service |
8a8a03 |
"list_add corruption",
|
|
Packit Service |
8a8a03 |
"do_IRQ: stack overflow:",
|
|
Packit Service |
8a8a03 |
/*n*/"ear stack overflow (cur:",
|
|
Packit Service |
8a8a03 |
/*g*/"eneral protection fault",
|
|
Packit Service |
8a8a03 |
/*u*/"nable to handle kernel",
|
|
Packit Service |
8a8a03 |
/*d*/"ouble fault:",
|
|
Packit Service |
8a8a03 |
"RTNL: assertion failed",
|
|
Packit Service |
8a8a03 |
/*e*/"eek! page_mapcount(page) went negative!",
|
|
Packit Service |
8a8a03 |
/*b*/"adness at",
|
|
Packit Service |
8a8a03 |
"NETDEV WATCHDOG",
|
|
Packit Service |
8a8a03 |
/*s*/"ysctl table check failed",
|
|
Packit Service |
8a8a03 |
": nobody cared",
|
|
Packit Service |
8a8a03 |
"IRQ handler type mismatch",
|
|
Packit Service |
8a8a03 |
"Kernel panic - not syncing:",
|
|
Packit Service |
8a8a03 |
/*
|
|
Packit Service |
8a8a03 |
* MCE examples for various CPUs/architectures (collected 2013-04):
|
|
Packit Service |
8a8a03 |
* arch/arc/kernel/traps.c: die("Machine Check Exception", regs, address, cause);
|
|
Packit Service |
8a8a03 |
* arch/x86/kernel/cpu/mcheck/winchip.c: printk(KERN_EMERG "CPU0: Machine Check Exception.\n");
|
|
Packit Service |
8a8a03 |
* arch/x86/kernel/cpu/mcheck/p5.c: "CPU#%d: Machine Check Exception: 0x%8X (type 0x%8X).\n",
|
|
Packit Service |
8a8a03 |
* arch/x86/kernel/cpu/mcheck/mce.c: pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
|
|
Packit Service |
8a8a03 |
* drivers/edac/sb_edac.c: printk("CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
|
|
Packit Service |
8a8a03 |
*
|
|
Packit Service |
8a8a03 |
* MCEs can be fatal (they panic kernel) or not.
|
|
Packit Service |
8a8a03 |
* Fatal MCE are delivered as exception#18 to the CPU.
|
|
Packit Service |
8a8a03 |
* Non-fatal ones sometimes are delivered as exception#18;
|
|
Packit Service |
8a8a03 |
* other times they are silently recorded in magic MSRs, CPU is not alerted.
|
|
Packit Service |
8a8a03 |
* Linux kernel periodically (up to 5 mins interval) reads those MSRs
|
|
Packit Service |
8a8a03 |
* and if MCE is seen there, it is piped in binary form through
|
|
Packit Service |
8a8a03 |
* /dev/mcelog to whoever listens on it. (Such as mcelog tool in --daemon
|
|
Packit Service |
8a8a03 |
* mode; but cat
|
|
Packit Service |
8a8a03 |
*
|
|
Packit Service |
8a8a03 |
* "Machine Check Exception:" message is printed *only*
|
|
Packit Service |
8a8a03 |
* by fatal MCEs (so far, future kernels may be different).
|
|
Packit Service |
8a8a03 |
* It will be caught as vmcore if kdump is configured.
|
|
Packit Service |
8a8a03 |
*
|
|
Packit Service |
8a8a03 |
* Non-fatal MCEs have "[Hardware Error]: Machine check events logged"
|
|
Packit Service |
8a8a03 |
* message in kernel log.
|
|
Packit Service |
8a8a03 |
* When /dev/mcelog is read, *no additional kernel log messages appear*:
|
|
Packit Service |
8a8a03 |
* if we want more readable data, we must rely on other tools
|
|
Packit Service |
8a8a03 |
* (such as mcelog daemon consuming binary /dev/mcelog and writing
|
|
Packit Service |
8a8a03 |
* human-readable /var/log/mcelog).
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
"Machine Check Exception:",
|
|
Packit Service |
8a8a03 |
"Machine check events logged",
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* X86 TRAPs */
|
|
Packit Service |
8a8a03 |
"divide error:",
|
|
Packit Service |
8a8a03 |
"bounds:",
|
|
Packit Service |
8a8a03 |
"coprocessor segment overrun:",
|
|
Packit Service |
8a8a03 |
"invalid TSS:",
|
|
Packit Service |
8a8a03 |
"segment not present:",
|
|
Packit Service |
8a8a03 |
"invalid opcode",
|
|
Packit Service |
8a8a03 |
"alignment check:",
|
|
Packit Service |
8a8a03 |
"stack segment:",
|
|
Packit Service |
8a8a03 |
"fpu exception:",
|
|
Packit Service |
8a8a03 |
"simd exception:",
|
|
Packit Service |
8a8a03 |
"iret exception:",
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* Termination */
|
|
Packit Service |
8a8a03 |
NULL
|
|
Packit Service |
8a8a03 |
};
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
static const char *const s_koops_suspicious_strings_blacklist[] = {
|
|
Packit Service |
8a8a03 |
/* "BUG:" and "DEBUG:" overlaps, we don't want to recognize DEBUG messages as BUG */
|
|
Packit Service |
8a8a03 |
"DEBUG:",
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* Termination */
|
|
Packit Service |
8a8a03 |
NULL
|
|
Packit Service |
8a8a03 |
};
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
static bool suspicious_line(const char *line)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
const char *const *str = s_koops_suspicious_strings;
|
|
Packit Service |
8a8a03 |
for ( ; *str; ++str)
|
|
Packit Service |
8a8a03 |
if (strstr(line, *str))
|
|
Packit Service |
8a8a03 |
break;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (!*str)
|
|
Packit Service |
8a8a03 |
return false;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
str = s_koops_suspicious_strings_blacklist;
|
|
Packit Service |
8a8a03 |
for ( ; *str; ++str)
|
|
Packit Service |
8a8a03 |
if (strstr(line, *str))
|
|
Packit Service |
8a8a03 |
break;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
return !*str;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
void koops_print_suspicious_strings(void)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
koops_print_suspicious_strings_filtered(NULL);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
GList *koops_suspicious_strings_list(void)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
GList *strings = NULL;
|
|
Packit Service |
8a8a03 |
for (const char *const *str = s_koops_suspicious_strings; *str; ++str)
|
|
Packit Service |
8a8a03 |
strings = g_list_prepend(strings, (gpointer)*str);
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
return strings;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
GList *koops_suspicious_strings_blacklist(void)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
GList *strings = NULL;
|
|
Packit Service |
8a8a03 |
for (const char *const *str = s_koops_suspicious_strings_blacklist; *str; ++str)
|
|
Packit Service |
8a8a03 |
strings = g_list_prepend(strings, (gpointer)*str);
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
return strings;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
static bool match_any(const regex_t **res, const char *str)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
for (const regex_t **r = res; *r != NULL; ++r)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* Regular expressions compiled with REG_NOSUB */
|
|
Packit Service |
8a8a03 |
const int reti = regexec(*r, str, 0, NULL, 0);
|
|
Packit Service |
8a8a03 |
if (reti == 0)
|
|
Packit Service |
8a8a03 |
return true;
|
|
Packit Service |
8a8a03 |
else if (reti != REG_NOMATCH)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
char msgbuf[100];
|
|
Packit Service |
8a8a03 |
regerror(reti, *r, msgbuf, sizeof(msgbuf));
|
|
Packit Service |
8a8a03 |
error_msg_and_die("Regex match failed: %s", msgbuf);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
return false;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
void koops_print_suspicious_strings_filtered(const regex_t **filterout)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
for (const char *const *str = s_koops_suspicious_strings; *str; ++str)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (filterout == NULL || !match_any(filterout, *str))
|
|
Packit Service |
8a8a03 |
puts(*str);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
void koops_line_skip_jiffies(const char **c)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* remove jiffies time stamp counter if present
|
|
Packit Service |
8a8a03 |
* jiffies are unsigned long, so it can be 2^64 long, which is
|
|
Packit Service |
8a8a03 |
* 20 decimal digits
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
if (**c == '[')
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
const char *c2 = strchr(*c, '.');
|
|
Packit Service |
8a8a03 |
const char *c3 = strchr(*c, ']');
|
|
Packit Service |
8a8a03 |
if (c2 && c3 && (c2 < c3) && (c3-*c) < 21)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
*c = c3 + 1;
|
|
Packit Service |
8a8a03 |
if (**c == ' ')
|
|
Packit Service |
8a8a03 |
(*c)++;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
int koops_line_skip_level(const char **c)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
int linelevel = 0;
|
|
Packit Service |
8a8a03 |
if (**c == '<')
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
const char *ptr = *c + 1;
|
|
Packit Service |
8a8a03 |
while (isdigit(*ptr))
|
|
Packit Service |
8a8a03 |
++ptr;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (*ptr == '>' && (ptr - *c > 1))
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
const char *const bck = ptr + 1;
|
|
Packit Service |
8a8a03 |
unsigned exp = 1;
|
|
Packit Service |
8a8a03 |
while (--ptr != *c)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
linelevel += (*ptr - '0') * exp;
|
|
Packit Service |
8a8a03 |
exp *= 10;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
*c = bck;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
return linelevel;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
void koops_extract_oopses(GList **oops_list, char *buffer, size_t buflen)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
char *c;
|
|
Packit Service |
8a8a03 |
int linecount = 0;
|
|
Packit Service |
8a8a03 |
int lines_info_size = 0;
|
|
Packit Service |
8a8a03 |
struct abrt_koops_line_info *lines_info = NULL;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* Split buffer into lines */
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (buflen != 0)
|
|
Packit Service |
8a8a03 |
buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but let's make sure */
|
|
Packit Service |
8a8a03 |
c = buffer;
|
|
Packit Service |
8a8a03 |
while (c < buffer + buflen)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
char linelevel;
|
|
Packit Service |
8a8a03 |
char *c9;
|
|
Packit Service |
8a8a03 |
char *colon;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
linecount++;
|
|
Packit Service |
8a8a03 |
c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be found */
|
|
Packit Service |
8a8a03 |
assert(c9);
|
|
Packit Service |
8a8a03 |
*c9 = '\0'; /* turn the \n into a string termination */
|
|
Packit Service |
8a8a03 |
if (c9 == c)
|
|
Packit Service |
8a8a03 |
goto next_line;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* Is it a syslog file (/var/log/messages or similar)?
|
|
Packit Service |
8a8a03 |
* Even though _usually_ it looks like "Nov 19 12:34:38 localhost kernel: xxx",
|
|
Packit Service |
8a8a03 |
* some users run syslog in non-C locale:
|
|
Packit Service |
8a8a03 |
* "2010-02-22T09:24:08.156534-08:00 gnu-4 gnome-session[2048]: blah blah"
|
|
Packit Service |
8a8a03 |
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !!!
|
|
Packit Service |
8a8a03 |
* We detect it by checking for N:NN:NN pattern in first 15 chars
|
|
Packit Service |
8a8a03 |
* (and this still is not good enough... false positive: "pci 0000:15:00.0: PME# disabled")
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
colon = strchr(c, ':');
|
|
Packit Service |
8a8a03 |
if (colon && colon > c && colon < c + 15
|
|
Packit Service |
8a8a03 |
&& isdigit(colon[-1]) /* N:... */
|
|
Packit Service |
8a8a03 |
&& isdigit(colon[1]) /* ...N:NN:... */
|
|
Packit Service |
8a8a03 |
&& isdigit(colon[2])
|
|
Packit Service |
8a8a03 |
&& colon[3] == ':'
|
|
Packit Service |
8a8a03 |
&& isdigit(colon[4]) /* ...N:NN:NN... */
|
|
Packit Service |
8a8a03 |
&& isdigit(colon[5])
|
|
Packit Service |
8a8a03 |
) {
|
|
Packit Service |
8a8a03 |
/* It's syslog file, not a bare dmesg */
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* Skip non-kernel lines */
|
|
Packit Service |
8a8a03 |
char *kernel_str = strstr(c, "kernel: ");
|
|
Packit Service |
8a8a03 |
if (!kernel_str)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* if we see our own marker:
|
|
Packit Service |
8a8a03 |
* "hostname abrt: Kerneloops: Reported 1 kernel oopses to Abrt"
|
|
Packit Service |
8a8a03 |
* we know we submitted everything upto here already */
|
|
Packit Service |
8a8a03 |
if (strstr(c, "kernel oopses to Abrt"))
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
log_debug("Found our marker at line %d", linecount);
|
|
Packit Service |
8a8a03 |
free(lines_info);
|
|
Packit Service |
8a8a03 |
lines_info = NULL;
|
|
Packit Service |
8a8a03 |
lines_info_size = 0;
|
|
Packit Service |
8a8a03 |
list_free_with_free(*oops_list);
|
|
Packit Service |
8a8a03 |
*oops_list = NULL;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
goto next_line;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
c = kernel_str + sizeof("kernel: ")-1;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* store and remove kernel log level */
|
|
Packit Service |
8a8a03 |
linelevel = koops_line_skip_level((const char **)&c);
|
|
Packit Service |
8a8a03 |
koops_line_skip_jiffies((const char **)&c);
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if ((lines_info_size & 0xfff) == 0)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
lines_info = xrealloc(lines_info, (lines_info_size + 0x1000) * sizeof(lines_info[0]));
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
lines_info[lines_info_size].ptr = c;
|
|
Packit Service |
8a8a03 |
lines_info[lines_info_size].level = linelevel;
|
|
Packit Service |
8a8a03 |
lines_info_size++;
|
|
Packit Service |
8a8a03 |
next_line:
|
|
Packit Service |
8a8a03 |
c = c9 + 1;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
koops_extract_oopses_from_lines(oops_list, lines_info, lines_info_size);
|
|
Packit Service |
8a8a03 |
free(lines_info);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
void koops_extract_oopses_from_lines(GList **oops_list, const struct abrt_koops_line_info *lines_info, int lines_info_size)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* Analyze lines */
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
int i;
|
|
Packit Service |
8a8a03 |
char prevlevel = 0;
|
|
Packit Service |
8a8a03 |
int oopsstart = -1;
|
|
Packit Service |
8a8a03 |
int inbacktrace = 0;
|
|
Packit Service |
8a8a03 |
regex_t arm_regex;
|
|
Packit Service |
8a8a03 |
int arm_regex_rc = 0;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* ARM backtrace regex, match a string similar to r7:df912310 */
|
|
Packit Service |
8a8a03 |
arm_regex_rc = regcomp(&arm_regex, "r[[:digit:]]{1,}:[a-f[:digit:]]{8}", REG_EXTENDED | REG_NOSUB);
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
i = 0;
|
|
Packit Service |
8a8a03 |
while (i < lines_info_size)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
char *curline = lines_info[i].ptr;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (curline == NULL)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
i++;
|
|
Packit Service |
8a8a03 |
continue;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
while (*curline == ' ')
|
|
Packit Service |
8a8a03 |
curline++;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (oopsstart < 0)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* Find start-of-oops markers */
|
|
Packit Service |
8a8a03 |
if (suspicious_line(curline))
|
|
Packit Service |
8a8a03 |
oopsstart = i;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (oopsstart >= 0)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* debug information */
|
|
Packit Service |
8a8a03 |
log_debug("Found oops at line %d: '%s'", oopsstart, lines_info[oopsstart].ptr);
|
|
Packit Service |
8a8a03 |
/* try to find the end marker */
|
|
Packit Service |
8a8a03 |
int i2 = i + 1;
|
|
Packit Service |
8a8a03 |
while (i2 < lines_info_size && i2 < (i+50))
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (strstr(lines_info[i2].ptr, "---[ end trace"))
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
inbacktrace = 1;
|
|
Packit Service |
8a8a03 |
i = i2;
|
|
Packit Service |
8a8a03 |
break;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
i2++;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* Are we entering a call trace part? */
|
|
Packit Service |
8a8a03 |
/* a call trace starts with "Call Trace:" or with the " [<.......>] function+0xFF/0xAA" pattern */
|
|
Packit Service |
8a8a03 |
if (oopsstart >= 0 && !inbacktrace)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (strcasestr(curline, "Call Trace:")) /* yes, it must be case-insensitive */
|
|
Packit Service |
8a8a03 |
inbacktrace = 1;
|
|
Packit Service |
8a8a03 |
else
|
|
Packit Service |
8a8a03 |
/* Fatal MCE's have a few lines of useful information between
|
|
Packit Service |
8a8a03 |
* first "Machine check exception:" line and the final "Kernel panic"
|
|
Packit Service |
8a8a03 |
* line. Such oops, of course, is only detectable in kdumps (tested)
|
|
Packit Service |
8a8a03 |
* or possibly pstore-saved logs (I did not try this yet).
|
|
Packit Service |
8a8a03 |
* In order to capture all these lines, we treat final line
|
|
Packit Service |
8a8a03 |
* as "backtrace" (which is admittedly a hack):
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
if (strstr(curline, "Kernel panic - not syncing:") && strcasestr(curline, "Machine check"))
|
|
Packit Service |
8a8a03 |
inbacktrace = 1;
|
|
Packit Service |
8a8a03 |
else
|
|
Packit Service |
8a8a03 |
if (strnlen(curline, 9) > 8
|
|
Packit Service |
8a8a03 |
&& ( (curline[0] == '(' && curline[1] == '[' && curline[2] == '<')
|
|
Packit Service |
8a8a03 |
|| (curline[0] == '[' && curline[1] == '<'))
|
|
Packit Service |
8a8a03 |
&& strstr(curline, ">]")
|
|
Packit Service |
8a8a03 |
&& strstr(curline, "+0x")
|
|
Packit Service |
8a8a03 |
&& strstr(curline, "/0x")
|
|
Packit Service |
8a8a03 |
) {
|
|
Packit Service |
8a8a03 |
inbacktrace = 1;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* Are we at the end of an oops? */
|
|
Packit Service |
8a8a03 |
else if (oopsstart >= 0 && inbacktrace)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
int oopsend = INT_MAX;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* line needs to start with " [" or have "] [" if it is still a call trace */
|
|
Packit Service |
8a8a03 |
/* example: "[<ffffffffa006c156>] radeon_get_ring_head+0x16/0x41 [radeon]" */
|
|
Packit Service |
8a8a03 |
/* example s390: "([<ffffffffa006c156>] 0xdeadbeaf)" */
|
|
Packit Service |
8a8a03 |
if ((curline[0] != '[' && (curline[0] != '(' || curline[1] != '['))
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "] [")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "--- Exception")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "LR =")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "<#DF>")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "<IRQ>")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "<EOI>")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "<NMI>")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "<<EOE>>")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "Comm:")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "Hardware name:")
|
|
Packit Service |
8a8a03 |
&& !strstr(curline, "Backtrace:")
|
|
Packit Service |
8a8a03 |
&& strncmp(curline, "Code: ", 6) != 0
|
|
Packit Service |
8a8a03 |
&& strncmp(curline, "RIP ", 4) != 0
|
|
Packit Service |
8a8a03 |
&& strncmp(curline, "RSP ", 4) != 0
|
|
Packit Service |
8a8a03 |
/* s390 Call Trace ends with 'Last Breaking-Event-Address:'
|
|
Packit Service |
8a8a03 |
* which is followed by a single frame */
|
|
Packit Service |
8a8a03 |
&& strncmp(curline, "Last Breaking-Event-Address:", strlen("Last Breaking-Event-Address:")) != 0
|
|
Packit Service |
8a8a03 |
/* ARM dumps registers intertwined with the backtrace */
|
|
Packit Service |
8a8a03 |
&& (arm_regex_rc == 0 ? regexec(&arm_regex, curline, 0, NULL, 0) == REG_NOMATCH : 1)
|
|
Packit Service |
8a8a03 |
) {
|
|
Packit Service |
8a8a03 |
oopsend = i-1; /* not a call trace line */
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
/* oops lines are always more than 8 chars long */
|
|
Packit Service |
8a8a03 |
else if (strnlen(curline, 8) < 8)
|
|
Packit Service |
8a8a03 |
oopsend = i-1;
|
|
Packit Service |
8a8a03 |
/* single oopses are of the same loglevel */
|
|
Packit Service |
8a8a03 |
else if (lines_info[i].level != prevlevel)
|
|
Packit Service |
8a8a03 |
oopsend = i-1;
|
|
Packit Service |
8a8a03 |
else if (strstr(curline, "Instruction dump:"))
|
|
Packit Service |
8a8a03 |
oopsend = i;
|
|
Packit Service |
8a8a03 |
/* kernel end-of-oops marker (not including marker itself) */
|
|
Packit Service |
8a8a03 |
else if (strstr(curline, "---[ end trace"))
|
|
Packit Service |
8a8a03 |
oopsend = i-1;
|
|
Packit Service |
8a8a03 |
/* if a new oops starts, this one has ended */
|
|
Packit Service |
8a8a03 |
else if (suspicious_line(curline))
|
|
Packit Service |
8a8a03 |
oopsend = i-1;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (oopsend <= i)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
log_debug("End of oops at line %d (%d): '%s'", oopsend, i, lines_info[oopsend].ptr);
|
|
Packit Service |
8a8a03 |
record_oops(oops_list, lines_info, oopsstart, oopsend);
|
|
Packit Service |
8a8a03 |
oopsstart = -1;
|
|
Packit Service |
8a8a03 |
inbacktrace = 0;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
prevlevel = lines_info[i].level;
|
|
Packit Service |
8a8a03 |
i++;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (oopsstart >= 0)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* Do we have a suspiciously long oops? Cancel it.
|
|
Packit Service |
8a8a03 |
* Bumped from 60 to 80 (see examples/oops_recursive_locking1.test)
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
if (i - oopsstart > 80)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
inbacktrace = 0;
|
|
Packit Service |
8a8a03 |
oopsstart = -1;
|
|
Packit Service |
8a8a03 |
log_debug("Dropped oops, too long");
|
|
Packit Service |
8a8a03 |
continue;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
if (!inbacktrace && i - oopsstart > 40)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* Used to drop oopses w/o backtraces, but some of them
|
|
Packit Service |
8a8a03 |
* (MCEs, for example) don't have backtrace yet we still want to file them.
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
log_debug("One-line oops at line %d: '%s'", oopsstart, lines_info[oopsstart].ptr);
|
|
Packit Service |
8a8a03 |
record_oops(oops_list, lines_info, oopsstart, oopsstart);
|
|
Packit Service |
8a8a03 |
/*inbacktrace = 0; - already is */
|
|
Packit Service |
8a8a03 |
oopsstart = -1;
|
|
Packit Service |
8a8a03 |
continue;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
} /* while (i < lines_info_size) */
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
regfree(&arm_regex);
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* process last oops if we have one */
|
|
Packit Service |
8a8a03 |
if (oopsstart >= 0)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (inbacktrace)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
int oopsend = i-1;
|
|
Packit Service |
8a8a03 |
log_debug("End of oops at line %d (end of file): '%s'", oopsend, lines_info[oopsend].ptr);
|
|
Packit Service |
8a8a03 |
record_oops(oops_list, lines_info, oopsstart, oopsend);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
else
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
log_debug("One-line oops at line %d: '%s'", oopsstart, lines_info[oopsstart].ptr);
|
|
Packit Service |
8a8a03 |
record_oops(oops_list, lines_info, oopsstart, oopsstart);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
int koops_hash_str_ext(char result[SHA1_RESULT_LEN*2 + 1], const char *oops_buf, int frame_count, int duphash_flags)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
char *hash_str = NULL, *error = NULL;
|
|
Packit Service |
8a8a03 |
int bad = 0;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
struct sr_stacktrace *stacktrace = sr_stacktrace_parse(SR_REPORT_KERNELOOPS,
|
|
Packit Service |
8a8a03 |
oops_buf, &error);
|
|
Packit Service |
8a8a03 |
if (!stacktrace)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
log_debug("Failed to parse koops: %s", error);
|
|
Packit Service |
8a8a03 |
free(error);
|
|
Packit Service |
8a8a03 |
bad = 1;
|
|
Packit Service |
8a8a03 |
goto end;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
struct sr_thread *thread = sr_stacktrace_find_crash_thread(stacktrace);
|
|
Packit Service |
8a8a03 |
if (!thread)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
log_debug("Failed to find crash thread");
|
|
Packit Service |
8a8a03 |
bad = 1;
|
|
Packit Service |
8a8a03 |
goto end;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (g_verbose >= 3)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
hash_str = sr_thread_get_duphash(thread, frame_count, NULL,
|
|
Packit Service |
8a8a03 |
duphash_flags|SR_DUPHASH_NOHASH);
|
|
Packit Service |
8a8a03 |
if (hash_str)
|
|
Packit Service |
8a8a03 |
log_warning("Generating duphash: '%s'", hash_str);
|
|
Packit Service |
8a8a03 |
else
|
|
Packit Service |
8a8a03 |
log_warning("Nothing useful for duphash");
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
free(hash_str);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
hash_str = sr_thread_get_duphash(thread, frame_count, NULL, duphash_flags);
|
|
Packit Service |
8a8a03 |
if (hash_str)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
strncpy(result, hash_str, SHA1_RESULT_LEN*2);
|
|
Packit Service |
8a8a03 |
result[SHA1_RESULT_LEN*2] = '\0';
|
|
Packit Service |
8a8a03 |
free(hash_str);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
else
|
|
Packit Service |
8a8a03 |
bad = 1;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
end:
|
|
Packit Service |
8a8a03 |
sr_stacktrace_free(stacktrace);
|
|
Packit Service |
8a8a03 |
return bad;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
int koops_hash_str(char result[SHA1_RESULT_LEN*2 + 1], const char *oops_buf)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
const int frame_count = 6;
|
|
Packit Service |
8a8a03 |
const int duphash_flags = SR_DUPHASH_NONORMALIZE|SR_DUPHASH_KOOPS_COMPAT;
|
|
Packit Service |
8a8a03 |
return koops_hash_str_ext(result, oops_buf, frame_count, duphash_flags);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
char *koops_extract_version(const char *linepointer)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (strstr(linepointer, "Pid")
|
|
Packit Service |
8a8a03 |
|| strstr(linepointer, "comm")
|
|
Packit Service |
8a8a03 |
|| strstr(linepointer, "CPU")
|
|
Packit Service |
8a8a03 |
|| strstr(linepointer, "REGS")
|
|
Packit Service |
8a8a03 |
|| strstr(linepointer, "EFLAGS")
|
|
Packit Service |
8a8a03 |
) {
|
|
Packit Service |
8a8a03 |
/* "(4.7.0-2.x86_64.fc25) #" */
|
|
Packit Service |
8a8a03 |
/* " 4.7.0-2.x86_64.fc25 #" */
|
|
Packit Service |
8a8a03 |
/* " 2.6.3.4.5-2.x86_64.fc22 #" */
|
|
Packit Service |
8a8a03 |
const char *regexp = "([ \\(]|kernel-)([0-9]+\\.[0-9]+\\.[0-9]+(\\.[^.-]+)*-[^ \\)]+)\\)? #";
|
|
Packit Service |
8a8a03 |
regex_t re;
|
|
Packit Service |
8a8a03 |
int r = regcomp(&re, regexp, REG_EXTENDED);
|
|
Packit Service |
8a8a03 |
if (r != 0)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
char buf[LINE_MAX];
|
|
Packit Service |
8a8a03 |
regerror(r, &re, buf, sizeof(buf));
|
|
Packit Service |
8a8a03 |
error_msg("BUG: invalid kernel version regexp: %s", buf);
|
|
Packit Service |
8a8a03 |
return NULL;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
regmatch_t matchptr[3];
|
|
Packit Service |
8a8a03 |
r = regexec(&re, linepointer, sizeof(matchptr)/sizeof(matchptr[0]), matchptr, 0);
|
|
Packit Service |
8a8a03 |
if (r != 0)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (r != REG_NOMATCH)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
char buf[LINE_MAX];
|
|
Packit Service |
8a8a03 |
regerror(r, &re, buf, sizeof(buf));
|
|
Packit Service |
8a8a03 |
error_msg("BUG: kernel version regexp failed: %s", buf);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
else
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
log_debug("A kernel version candidate line didn't match kernel oops regexp:");
|
|
Packit Service |
8a8a03 |
log_debug("\t'%s'", linepointer);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
regfree(&re);
|
|
Packit Service |
8a8a03 |
return NULL;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* 0: entire string */
|
|
Packit Service |
8a8a03 |
/* 1: version prefix */
|
|
Packit Service |
8a8a03 |
/* 2: version string */
|
|
Packit Service |
8a8a03 |
const regmatch_t *const ver = matchptr + 2;
|
|
Packit Service |
8a8a03 |
char *ret = xstrndup(linepointer + ver->rm_so, ver->rm_eo - ver->rm_so);
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
regfree(&re);
|
|
Packit Service |
8a8a03 |
return ret;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
return NULL;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/* reading /proc/sys/kernel/tainted file after an oops is ALWAYS going
|
|
Packit Service |
8a8a03 |
* to show it as tainted.
|
|
Packit Service |
8a8a03 |
*
|
|
Packit Service |
8a8a03 |
* https://bugzilla.redhat.com/show_bug.cgi?id=724838
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
/**
|
|
Packit Service |
8a8a03 |
* print_tainted - return a string to represent the kernel taint state.
|
|
Packit Service |
8a8a03 |
*
|
|
Packit Service |
8a8a03 |
* 'P' - Proprietary module has been loaded.
|
|
Packit Service |
8a8a03 |
* 'F' - Module has been forcibly loaded.
|
|
Packit Service |
8a8a03 |
* 'S' - SMP with CPUs not designed for SMP.
|
|
Packit Service |
8a8a03 |
* 'R' - User forced a module unload.
|
|
Packit Service |
8a8a03 |
* 'M' - System experienced a machine check exception.
|
|
Packit Service |
8a8a03 |
* 'B' - System has hit bad_page.
|
|
Packit Service |
8a8a03 |
* 'U' - Userspace-defined naughtiness.
|
|
Packit Service |
8a8a03 |
* 'D' - Kernel has oopsed before
|
|
Packit Service |
8a8a03 |
* 'A' - ACPI table overridden.
|
|
Packit Service |
8a8a03 |
* 'W' - Taint on warning.
|
|
Packit Service |
8a8a03 |
* 'C' - modules from drivers/staging are loaded.
|
|
Packit Service |
8a8a03 |
* 'I' - Working around severe firmware bug.
|
|
Packit Service |
8a8a03 |
* 'O' - Out-of-tree module has been loaded.
|
|
Packit Service |
8a8a03 |
* 'E' - Unsigned module has been loaded.
|
|
Packit Service |
8a8a03 |
* 'L' - A soft lockup has previously occurred.
|
|
Packit Service |
8a8a03 |
* 'K' - Kernel has been live patched.
|
|
Packit Service |
8a8a03 |
*
|
|
Packit Service |
8a8a03 |
* Compatibility flags from older versions and downstream sources:
|
|
Packit Service |
8a8a03 |
* 'H' - Hardware is unsupported.
|
|
Packit Service |
8a8a03 |
* 'T' - Tech_preview
|
|
Packit Service |
8a8a03 |
*/
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
#if 0 /* unused */
|
|
Packit Service |
8a8a03 |
static char *turn_off_flag(char *flags, char flag)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
size_t len = strlen(flags);
|
|
Packit Service |
8a8a03 |
for (int i = 0; i < len; ++i)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (flags[i] == flag)
|
|
Packit Service |
8a8a03 |
flags[i] = ' ';
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
return flags;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
#endif
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
char *kernel_tainted_short(const char *kernel_bt)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
/* example of flags: 'Tainted: G B ' */
|
|
Packit Service |
8a8a03 |
char *tainted = strstr(kernel_bt, "Tainted: ");
|
|
Packit Service |
8a8a03 |
if (!tainted)
|
|
Packit Service |
8a8a03 |
return NULL;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
tainted += strlen("Tainted: ");
|
|
Packit Service |
8a8a03 |
/* 17 + 2 == current count of known flags */
|
|
Packit Service |
8a8a03 |
/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob_plain;f=kernel/panic.c;hb=HEAD */
|
|
Packit Service |
8a8a03 |
/* 26 the maximal sane count of flags because of alphabet limits */
|
|
Packit Service |
8a8a03 |
unsigned sz = 26 + 1;
|
|
Packit Service |
8a8a03 |
unsigned cnt = 0;
|
|
Packit Service |
8a8a03 |
char *tnt = xmalloc(sz);
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
for (;;)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (tainted[0] >= 'A' && tainted[0] <= 'Z')
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
if (cnt == sz - 1)
|
|
Packit Service |
8a8a03 |
{ /* this should not happen but */
|
|
Packit Service |
8a8a03 |
/* I guess, it's a bit better approach than simple failure */
|
|
Packit Service |
8a8a03 |
sz <<= 1;
|
|
Packit Service |
8a8a03 |
tnt = xrealloc(tnt, sizeof(char) * sz);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
tnt[cnt] = tainted[0];
|
|
Packit Service |
8a8a03 |
++cnt;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
else if (tainted[0] != ' ')
|
|
Packit Service |
8a8a03 |
break;
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
++tainted;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
if (cnt == 0)
|
|
Packit Service |
8a8a03 |
{ /* this should not happen
|
|
Packit Service |
8a8a03 |
* cnt eq 0 means that a tainted string contains only spaces */
|
|
Packit Service |
8a8a03 |
free(tnt);
|
|
Packit Service |
8a8a03 |
return NULL;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
tnt[cnt] = '\0';
|
|
Packit Service |
8a8a03 |
return tnt;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
static const char *const tnts_long[] = {
|
|
Packit Service |
8a8a03 |
/* A */ "ACPI table overridden.",
|
|
Packit Service |
8a8a03 |
/* B */ "System has hit bad_page.",
|
|
Packit Service |
8a8a03 |
/* C */ "Modules from drivers/staging are loaded.",
|
|
Packit Service |
8a8a03 |
/* D */ "Kernel has oopsed before",
|
|
Packit Service |
8a8a03 |
/* E */ "Unsigned module has been loaded.",
|
|
Packit Service |
8a8a03 |
/* F */ "Module has been forcibly loaded.",
|
|
Packit Service |
8a8a03 |
/* We don't want to be more descriptive about G flag */
|
|
Packit Service |
8a8a03 |
/* G */ NULL, /* "Proprietary module has not been loaded." */
|
|
Packit Service |
8a8a03 |
/* H */ NULL,
|
|
Packit Service |
8a8a03 |
/* I */ "Working around severe firmware bug.",
|
|
Packit Service |
8a8a03 |
/* J */ NULL,
|
|
Packit Service |
8a8a03 |
/* K */ "Kernel has been live patched.",
|
|
Packit Service |
8a8a03 |
/* L */ "A soft lockup has previously occurred.",
|
|
Packit Service |
8a8a03 |
/* M */ "System experienced a machine check exception.",
|
|
Packit Service |
8a8a03 |
/* N */ NULL,
|
|
Packit Service |
8a8a03 |
/* O */ "Out-of-tree module has been loaded.",
|
|
Packit Service |
8a8a03 |
/* P */ "Proprietary module has been loaded.",
|
|
Packit Service |
8a8a03 |
/* Q */ NULL,
|
|
Packit Service |
8a8a03 |
/* R */ "User forced a module unload.",
|
|
Packit Service |
8a8a03 |
/* S */ "SMP with CPUs not designed for SMP.",
|
|
Packit Service |
8a8a03 |
/* T */ NULL,
|
|
Packit Service |
8a8a03 |
/* U */ "Userspace-defined naughtiness.",
|
|
Packit Service |
8a8a03 |
/* V */ NULL,
|
|
Packit Service |
8a8a03 |
/* W */ "Taint on warning.",
|
|
Packit Service |
8a8a03 |
/* X */ NULL,
|
|
Packit Service |
8a8a03 |
/* Y */ NULL,
|
|
Packit Service |
8a8a03 |
/* Z */ NULL,
|
|
Packit Service |
8a8a03 |
};
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
char *kernel_tainted_long(const char *tainted_short)
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
struct strbuf *tnt_long = strbuf_new();
|
|
Packit Service |
8a8a03 |
while (tainted_short[0] != '\0')
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
const int tnt_index = tainted_short[0] - 'A';
|
|
Packit Service |
8a8a03 |
if (tnt_index >= 0 && tnt_index <= 'Z' - 'A')
|
|
Packit Service |
8a8a03 |
{
|
|
Packit Service |
8a8a03 |
const char *const txt = tnts_long[tnt_index];
|
|
Packit Service |
8a8a03 |
if (txt)
|
|
Packit Service |
8a8a03 |
strbuf_append_strf(tnt_long, "%c - %s\n", tainted_short[0], txt);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
++tainted_short;
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|
|
Packit Service |
8a8a03 |
return strbuf_free_nobuf(tnt_long);
|
|
Packit Service |
8a8a03 |
}
|
|
Packit Service |
8a8a03 |
|