On 10/10/2011 04:06 PM, Nikola Pajkovsky wrote:
Signed-off-by: Nikola Pajkovsky<npajkovs(a)redhat.com>
---
.gitignore | 9 +-
Makefile.am | 2 +-
configure.ac | 7 +
examples/oops-kernel-3.x.x | 43 +++++
src/include/libabrt.h | 6 +
src/lib/kernel.c | 366 +++++++++++++++++++++++++++++++++++++++++
src/plugins/abrt-dump-oops.c | 369 +-----------------------------------------
tests/Makefile.am | 54 ++++++
tests/atlocal.in | 15 ++
tests/koops-parser.at | 46 ++++++
tests/local.at | 27 +++
tests/testsuite.at | 4 +
12 files changed, 577 insertions(+), 371 deletions(-)
create mode 100644 examples/oops-kernel-3.x.x
create mode 100644 tests/Makefile.am
create mode 100644 tests/atlocal.in
create mode 100644 tests/koops-parser.at
create mode 100644 tests/local.at
create mode 100644 tests/testsuite.at
diff --git a/.gitignore b/.gitignore
index d0df191..8ae0534 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,9 +64,6 @@ libtool
ltmain.sh
py-compile
stamp-h1
-tests/atconfig
-tests/atlocal
-tests/package.m4
# pc files
src/btparser/btparser.pc
@@ -114,6 +111,12 @@ src/gui-wizard-gtk/wizard_glade.c
# generated man pages
*.[1,5,8]
+# generated files form testsuite
+testsuite*
+tests/atconfig
+tests/atlocal
+tests/package.m4
+
# if you want to enable them, be aware of that 'git clean -df' won't clean
them
# and you have to do it *manually*
# x86_64/
diff --git a/Makefile.am b/Makefile.am
index 87b6fcb..95c748e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = src po icons
+SUBDIRS = src po icons tests
DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
diff --git a/configure.ac b/configure.ac
index 8debc2d..9eb44b6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -96,6 +96,13 @@ AC_SUBST(PLUGINS_CONF_DIR)
AC_SUBST(EVENTS_CONF_DIR)
AC_SUBST(EVENTS_DIR)
+# Initialize the test suite.
+AC_CONFIG_TESTDIR(tests)
+AC_CONFIG_FILES([tests/Makefile tests/atlocal])
+AM_MISSING_PROG([AUTOM4TE], [autom4te])
+# Needed by tests/atlocal.in.
+AC_SUBST([O0CFLAGS], [`echo $CFLAGS | sed 's/-O[[0-9]] *//'`])
+
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
diff --git a/examples/oops-kernel-3.x.x b/examples/oops-kernel-3.x.x
new file mode 100644
index 0000000..1b37c5b
--- /dev/null
+++ b/examples/oops-kernel-3.x.x
@@ -0,0 +1,43 @@
+[ 3.908169] ------------[ cut here ]------------
+[ 3.910024] WARNING: at lib/dma-debug.c:800 check_unmap+0x9c/0x67f()
+[ 3.911885] firewire_ohci 0000:05:00.0: DMA-API: device driver tries to free an
invalid DMA memory address
+[ 3.913793] Modules linked in: firewire_ohci(+) firewire_core crc_itu_t radeon ttm
drm_kms_helper drm i2c_algo_bit i2c_core
+[ 3.915780] Pid: 202, comm: modprobe Not tainted 3.0.0-3.fc16.i686.PAE #1
+[ 3.917715] Call Trace:
+[ 3.919632] [<c04463d4>] warn_slowpath_common+0x7c/0x91
+[ 3.921557] [<c05fcc7a>] ? check_unmap+0x9c/0x67f
+[ 3.923467] [<c05fcc7a>] ? check_unmap+0x9c/0x67f
+[ 3.925335] [<c0446474>] warn_slowpath_fmt+0x33/0x35
+[ 3.927176] [<c05fcc7a>] check_unmap+0x9c/0x67f
+[ 3.929010] [<c05eeba4>] ? trace_hardirqs_on_thunk+0xc/0x10
+[ 3.930844] [<c05eebb4>] ? trace_hardirqs_off_thunk+0xc/0x10
+[ 3.932659] [<c084f3bd>] ? restore_all+0xf/0xf
+[ 3.934464] [<c04400d8>] ? rt_mutex_setprio+0xb2/0xf6
+[ 3.936274] [<c04464a1>] ? arch_local_irq_restore+0x5/0xb
+[ 3.938083] [<c05fd2b9>] debug_dma_free_coherent+0x5c/0x64
+[ 3.939895] [<f7a755ee>] dma_free_coherent+0x6a/0x8f [firewire_ohci]
+[ 3.941714] [<f7a77c9e>] ohci_enable+0x3c2/0x439 [firewire_ohci]
+[ 3.943524] [<f7a4d7c4>] fw_card_add+0x45/0x71 [firewire_core]
+[ 3.945331] [<f7a78e8d>] pci_probe+0x377/0x4a1 [firewire_ohci]
+[ 3.947126] [<c084f0f5>] ? _raw_spin_unlock_irqrestore+0x44/0x48
+[ 3.948933] [<c0605db8>] pci_device_probe+0x62/0xab
+[ 3.950733] [<c06a838e>] driver_probe_device+0x129/0x208
+[ 3.952528] [<c084dc54>] ? mutex_lock_nested+0x43/0x49
+[ 3.954328] [<c06a84bc>] __driver_attach+0x4f/0x6b
+[ 3.956104] [<c06a757f>] bus_for_each_dev+0x42/0x6b
+[ 3.957862] [<c06a7fc1>] driver_attach+0x1f/0x23
+[ 3.959613] [<c06a846d>] ? driver_probe_device+0x208/0x208
+[ 3.961355] [<c06a7c47>] bus_add_driver+0xcd/0x214
+[ 3.963071] [<c06a8902>] driver_register+0x84/0xe3
+[ 3.964779] [<c05f2e2b>] ? __raw_spin_lock_init+0x2d/0x4e
+[ 3.966479] [<c0606530>] __pci_register_driver+0x4f/0xab
+[ 3.968145] [<f7a39000>] ? 0xf7a38fff
+[ 3.969805] [<f7a39000>] ? 0xf7a38fff
+[ 3.971436] [<f7a39017>] fw_ohci_init+0x17/0x1000 [firewire_ohci]
+[ 3.973060] [<c04030a2>] do_one_initcall+0x8c/0x146
+[ 3.974685] [<c04296cf>] ? set_memory_nx+0x38/0x3a
+[ 3.976312] [<f7a39000>] ? 0xf7a38fff
+[ 3.977936] [<f7a39000>] ? 0xf7a38fff
+[ 3.979535] [<c047cea1>] sys_init_module+0x14b9/0x16dd
+[ 3.981135] [<c085525f>] sysenter_do_call+0x12/0x38
+[ 3.982726] ---[ end trace 50b7d6497bc6b1f4 ]---
diff --git a/src/include/libabrt.h b/src/include/libabrt.h
index 197e903..c902660 100644
--- a/src/include/libabrt.h
+++ b/src/include/libabrt.h
@@ -64,6 +64,12 @@ int daemon_is_ok();
#define kernel_tainted_short abrt_kernel_tainted_short
char *kernel_tainted_short(const char *kernel_bt);
+#define koops_extract_version abrt_koops_extract_version
+char *koops_extract_version(const char *linepointer);
+
+#define koops_extract_oopses abrt_koops_extract_oopses
+void koops_extract_oopses(GList **oops_list, char *buffer, size_t buflen);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/lib/kernel.c b/src/lib/kernel.c
index 0e96b05..7c77202 100644
--- a/src/lib/kernel.c
+++ b/src/lib/kernel.c
@@ -144,3 +144,369 @@ GList *kernel_tainted_long(unsigned tainted)
return tnt;
}
#endif
+
+/*
+ * extract_version tries to find the kernel version in given data
+ */
+char *koops_extract_version(const char *linepointer)
+{
+ if (strstr(linepointer, "Pid")
+ || strstr(linepointer, "comm")
+ || strstr(linepointer, "CPU")
+ || strstr(linepointer, "REGS")
+ || strstr(linepointer, "EFLAGS")
+ ) {
+ char* start;
+ char* end;
+
+ start = strstr((char*)linepointer, "2.6.");
+ if (start)
+ {
+ end = strchr(start, ')');
+ if (!end)
+ end = strchrnul(start, ' ');
+ return xstrndup(start, end-start);
+ }
+ }
+
+ return NULL;
+}
+
+/* npajkovs: remove 2 lines func; it's used only once!*/
+static void queue_oops(GList **vec, const char *data, const char *version)
+{
+ char *ver_data = xasprintf("%s\n%s", version, data);
+ *vec = g_list_append(*vec, ver_data);
+}
+
+/*
+ * extract_oops tries to find oops signatures in a log
+ */
+struct line_info {
+ char *ptr;
+ char level;
+};
+
+static void record_oops(GList **oops_list, struct line_info* lines_info, int oopsstart,
int oopsend)
+{
+ int q;
+ int len;
+ int rv = 1;
+
+ len = 2;
+ for (q = oopsstart; q<= oopsend; q++)
+ len += strlen(lines_info[q].ptr) + 1;
+
+ /* too short oopses are invalid */
+ if (len> 100)
+ {
+ char *oops = (char*)xzalloc(len);
+ char *dst = oops;
+ char *version = NULL;
+ for (q = oopsstart; q<= oopsend; q++)
+ {
+ if (!version)
+ version = koops_extract_version(lines_info[q].ptr);
+ if (lines_info[q].ptr[0])
+ {
+ dst = stpcpy(dst, lines_info[q].ptr);
+ dst = stpcpy(dst, "\n");
+ }
+ }
+ if ((dst - oops)> 100)
+ queue_oops(oops_list, oops, version ? version : "undefined");
+ else
+ /* too short oopses are invalid */
+ rv = 0;
+ free(oops);
+ free(version);
+ }
+
+ VERB3 if (rv == 0) log("Dropped oops: too short");
+}
+
+void koops_extract_oopses(GList **oops_list, char *buffer, size_t buflen)
+{
+ char *c;
+ int linecount = 0;
+ int lines_info_size = 0;
+ struct line_info *lines_info = NULL;
+
+ /* Split buffer into lines */
+
+ if (buflen != 0)
+ buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but
let's make sure */
+ c = buffer;
+ while (c< buffer + buflen)
+ {
+ char linelevel;
+ char *c9;
+ char *colon;
+
+ linecount++;
+ c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be
found */
+ assert(c9);
+ *c9 = '\0'; /* turn the \n into a string termination */
+ if (c9 == c)
+ goto next_line;
+
+ /* Is it a syslog file (/var/log/messages or similar)?
+ * Even though _usually_ it looks like "Nov 19 12:34:38 localhost kernel:
xxx",
+ * some users run syslog in non-C locale:
+ * "2010-02-22T09:24:08.156534-08:00 gnu-4 gnome-session[2048]: blah
blah"
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !!!
+ * We detect it by checking for N:NN:NN pattern in first 15 chars
+ * (and this still is not good enough... false positive: "pci 0000:15:00.0:
PME# disabled")
+ */
+ colon = strchr(c, ':');
+ if (colon&& colon> c&& colon< c + 15
+&& isdigit(colon[-1]) /* N:... */
+&& isdigit(colon[1]) /* ...N:NN:... */
+&& isdigit(colon[2])
+&& colon[3] == ':'
+&& isdigit(colon[4]) /* ...N:NN:NN... */
+&& isdigit(colon[5])
+ ) {
+ /* It's syslog file, not a bare dmesg */
+
+ /* Skip non-kernel lines */
+ char *kernel_str = strstr(c, "kernel: ");
+ if (!kernel_str)
+ {
+ /* if we see our own marker:
+ * "hostname abrt: Kerneloops: Reported 1 kernel oopses to
Abrt"
+ * we know we submitted everything upto here already */
+ if (strstr(c, "kernel oopses to Abrt"))
+ {
+ VERB3 log("Found our marker at line %d", linecount);
+ free(lines_info);
+ lines_info = NULL;
+ lines_info_size = 0;
+ list_free_with_free(*oops_list);
+ *oops_list = NULL;
+ }
+ goto next_line;
+ }
+ c = kernel_str + sizeof("kernel: ")-1;
+ }
+
+ linelevel = 0;
+ /* store and remove kernel log level */
+ if (*c == '<'&& c[1]&& c[2] == '>')
+ {
+ linelevel = c[1];
+ c += 3;
+ }
+ /* remove jiffies time stamp counter if present */
+ if (*c == '[')
+ {
+ char *c2 = strchr(c, '.');
+ char *c3 = strchr(c, ']');
+ if (c2&& c3&& (c2< c3)&& (c3-c)<
14&& (c2-c)< 8)
+ {
+ c = c3 + 1;
+ if (*c == ' ')
+ c++;
+ }
+ }
+ if ((lines_info_size& 0xfff) == 0)
+ {
+ lines_info = xrealloc(lines_info, (lines_info_size + 0x1000) *
sizeof(lines_info[0]));
+ }
+ lines_info[lines_info_size].ptr = c;
+ lines_info[lines_info_size].level = linelevel;
+ lines_info_size++;
+next_line:
+ c = c9 + 1;
+ }
+
+ /* Analyze lines */
+
+ int i;
+ char prevlevel = 0;
+ int oopsstart = -1;
+ int inbacktrace = 0;
+
+ i = 0;
+ while (i< lines_info_size)
+ {
+ char *curline = lines_info[i].ptr;
+
+ if (curline == NULL)
+ {
+ i++;
+ continue;
+ }
+ while (*curline == ' ')
+ curline++;
+
+ if (oopsstart< 0)
+ {
+ /* Find start-of-oops markers */
+ /* In some comparisons, we skip 1st letter, to avoid dealing with
+ * changes in capitalization in kernel. For example, I see that
+ * current kernel git (at 2011-01-01) has both "kernel BUG at
..."
+ * and "Kernel BUG at ..." messages, and I don't want to
change
+ * the code below whenever kernel is changed to use "K" (or
"k")
+ * uniformly.
+ */
+ if (strstr(curline, /*g*/ "eneral protection fault:"))
+ oopsstart = i;
+ else if (strstr(curline, "BUG:"))
+ oopsstart = i;
+ else if (strstr(curline, /*k*/ "ernel BUG at"))
+ oopsstart = i;
+ else if (strstr(curline, "do_IRQ: stack overflow:"))
+ oopsstart = i;
+ else if (strstr(curline, "RTNL: assertion failed"))
+ oopsstart = i;
+ else if (strstr(curline, /*e*/ "eek! page_mapcount(page) went
negative!"))
+ oopsstart = i;
+ else if (strstr(curline, /*n*/ "ear stack overflow (cur:"))
+ oopsstart = i;
+ else if (strstr(curline, /*d*/ "ouble fault:"))
+ oopsstart = i;
+ else if (strstr(curline, /*b*/ "adness at"))
+ oopsstart = i;
+ else if (strstr(curline, "NETDEV WATCHDOG"))
+ oopsstart = i;
+ else if (strstr(curline, "WARNING: at ")) /* WARN_ON() generated
message */
+ oopsstart = i;
+ else if (strstr(curline, /*u*/ "nable to handle kernel"))
+ oopsstart = i;
+ else if (strstr(curline, /*s*/ "ysctl table check failed"))
+ oopsstart = i;
+ else if (strstr(curline, "INFO: possible recursive locking
detected"))
+ oopsstart = i;
+ // Not needed: "--[ cut here ]--" is always followed
+ // by "Badness at", "kernel BUG at", or "WARNING:
at" string
+ //else if (strstr(curline, "------------[ cut here
]------------"))
+ // oopsstart = i;
+ else if (strstr(curline, "list_del corruption"))
+ oopsstart = i;
+ else if (strstr(curline, "list_add corruption"))
+ oopsstart = i;
+
+ if (i>= 3&& strstr(curline, "Oops:"))
+ oopsstart = i-3;
+
+ if (oopsstart>= 0)
+ {
+ /* debug information */
+ VERB3 {
+ log("Found oops at line %d: '%s'", oopsstart,
lines_info[oopsstart].ptr);
+ if (oopsstart != i)
+ log("Trigger line is %d: '%s'", i, c);
+ }
+ /* try to find the end marker */
+ int i2 = i + 1;
+ while (i2< lines_info_size&& i2< (i+50))
+ {
+ if (strstr(lines_info[i2].ptr, "---[ end trace"))
+ {
+ inbacktrace = 1;
+ i = i2;
+ break;
+ }
+ i2++;
+ }
+ }
+ }
+
+ /* Are we entering a call trace part? */
+ /* a call trace starts with "Call Trace:" or with the "
[<.......>] function+0xFF/0xAA" pattern */
+ if (oopsstart>= 0&& !inbacktrace)
+ {
+ if (strstr(curline, "Call Trace:"))
+ inbacktrace = 1;
+ else
+ if (strnlen(curline, 9)> 8
+&& curline[0] == '['&& curline[1] == '<'
+&& strstr(curline, ">]")
+&& strstr(curline, "+0x")
+&& strstr(curline, "/0x")
+ ) {
+ inbacktrace = 1;
+ }
+ }
+
+ /* Are we at the end of an oops? */
+ else if (oopsstart>= 0&& inbacktrace)
+ {
+ int oopsend = INT_MAX;
+
+ /* line needs to start with " [" or have "] [" if it is
still a call trace */
+ /* example: "[<ffffffffa006c156>] radeon_get_ring_head+0x16/0x41
[radeon]" */
+ if (curline[0] != '['
+&& !strstr(curline, "] [")
+&& !strstr(curline, "--- Exception")
+&& !strstr(curline, "LR =")
+&& !strstr(curline, "<#DF>")
+&& !strstr(curline, "<IRQ>")
+&& !strstr(curline, "<EOI>")
+&& !strstr(curline, "<<EOE>>")
+&& strncmp(curline, "Code: ", 6) != 0
+&& strncmp(curline, "RIP ", 4) != 0
+&& strncmp(curline, "RSP ", 4) != 0
+ ) {
+ oopsend = i-1; /* not a call trace line */
+ }
+ /* oops lines are always more than 8 chars long */
+ else if (strnlen(curline, 8)< 8)
+ oopsend = i-1;
+ /* single oopses are of the same loglevel */
+ else if (lines_info[i].level != prevlevel)
+ oopsend = i-1;
+ else if (strstr(curline, "Instruction dump:"))
+ oopsend = i;
+ /* if a new oops starts, this one has ended */
+ else if (strstr(curline, "WARNING: at ")&& oopsstart !=
i) /* WARN_ON() generated message */
+ oopsend = i-1;
+ else if (strstr(curline, "Unable to handle")&& oopsstart
!= i)
+ oopsend = i-1;
+ /* kernel end-of-oops marker (not including marker itself) */
+ else if (strstr(curline, "---[ end trace"))
+ oopsend = i-1;
+
+ if (oopsend<= i)
+ {
+ VERB3 log("End of oops at line %d (%d): '%s'",
oopsend, i, lines_info[oopsend].ptr);
+ record_oops(oops_list, lines_info, oopsstart, oopsend);
+ oopsstart = -1;
+ inbacktrace = 0;
+ }
+ }
+
+ prevlevel = lines_info[i].level;
+ i++;
+
+ if (oopsstart>= 0)
+ {
+ /* Do we have a suspiciously long oops? Cancel it */
+ if (i-oopsstart> 60)
+ {
+ inbacktrace = 0;
+ oopsstart = -1;
+ VERB3 log("Dropped oops, too long");
+ continue;
+ }
+ if (!inbacktrace&& i-oopsstart> 40)
+ {
+ /*inbacktrace = 0; - already is */
+ oopsstart = -1;
+ VERB3 log("Dropped oops, too long");
+ continue;
+ }
+ }
+ } /* while (i< lines_info_size) */
+
+ /* process last oops if we have one */
+ if (oopsstart>= 0&& inbacktrace)
+ {
+ int oopsend = i-1;
+ VERB3 log("End of oops at line %d (end of file): '%s'",
oopsend, lines_info[oopsend].ptr);
+ record_oops(oops_list, lines_info, oopsstart, oopsend);
+ }
+
+ free(lines_info);
+}
diff --git a/src/plugins/abrt-dump-oops.c b/src/plugins/abrt-dump-oops.c
index 81c41a1..17b7d05 100644
--- a/src/plugins/abrt-dump-oops.c
+++ b/src/plugins/abrt-dump-oops.c
@@ -25,371 +25,6 @@
static bool world_readable_dump = false;
static const char *debug_dumps_dir = ".";
-static void queue_oops(GList **vec, const char *data, const char *version)
-{
- char *ver_data = xasprintf("%s\n%s", version, data);
- *vec = g_list_append(*vec, ver_data);
-}
-
-/*
- * extract_version tries to find the kernel version in given data
- */
-static char *extract_version(const char *linepointer)
-{
- if (strstr(linepointer, "Pid")
- || strstr(linepointer, "comm")
- || strstr(linepointer, "CPU")
- || strstr(linepointer, "REGS")
- || strstr(linepointer, "EFLAGS")
- ) {
- char* start;
- char* end;
-
- start = strstr((char*)linepointer, "2.6.");
- if (start)
- {
- end = strchr(start, ')');
- if (!end)
- end = strchrnul(start, ' ');
- return xstrndup(start, end-start);
- }
- }
-
- return NULL;
-}
-
-/*
- * extract_oops tries to find oops signatures in a log
- */
-struct line_info {
- char *ptr;
- char level;
-};
-
-static void record_oops(GList **oops_list, struct line_info* lines_info, int oopsstart,
int oopsend)
-{
- int q;
- int len;
- int rv = 1;
-
- len = 2;
- for (q = oopsstart; q<= oopsend; q++)
- len += strlen(lines_info[q].ptr) + 1;
-
- /* too short oopses are invalid */
- if (len> 100)
- {
- char *oops = (char*)xzalloc(len);
- char *dst = oops;
- char *version = NULL;
- for (q = oopsstart; q<= oopsend; q++)
- {
- if (!version)
- version = extract_version(lines_info[q].ptr);
- if (lines_info[q].ptr[0])
- {
- dst = stpcpy(dst, lines_info[q].ptr);
- dst = stpcpy(dst, "\n");
- }
- }
- if ((dst - oops)> 100)
- queue_oops(oops_list, oops, version ? version : "undefined");
- else
- /* too short oopses are invalid */
- rv = 0;
- free(oops);
- free(version);
- }
-
- VERB3 if (rv == 0) log("Dropped oops: too short");
-}
-
-static void extract_oopses(GList **oops_list, char *buffer, size_t buflen)
-{
- char *c;
- int linecount = 0;
- int lines_info_size = 0;
- struct line_info *lines_info = NULL;
-
- /* Split buffer into lines */
-
- if (buflen != 0)
- buffer[buflen - 1] = '\n'; /* the buffer usually ends with \n, but
let's make sure */
- c = buffer;
- while (c< buffer + buflen)
- {
- char linelevel;
- char *c9;
- char *colon;
-
- linecount++;
- c9 = (char*)memchr(c, '\n', buffer + buflen - c); /* a \n will always be
found */
- assert(c9);
- *c9 = '\0'; /* turn the \n into a string termination */
- if (c9 == c)
- goto next_line;
-
- /* Is it a syslog file (/var/log/messages or similar)?
- * Even though _usually_ it looks like "Nov 19 12:34:38 localhost kernel:
xxx",
- * some users run syslog in non-C locale:
- * "2010-02-22T09:24:08.156534-08:00 gnu-4 gnome-session[2048]: blah
blah"
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ !!!
- * We detect it by checking for N:NN:NN pattern in first 15 chars
- * (and this still is not good enough... false positive: "pci 0000:15:00.0:
PME# disabled")
- */
- colon = strchr(c, ':');
- if (colon&& colon> c&& colon< c + 15
-&& isdigit(colon[-1]) /* N:... */
-&& isdigit(colon[1]) /* ...N:NN:... */
-&& isdigit(colon[2])
-&& colon[3] == ':'
-&& isdigit(colon[4]) /* ...N:NN:NN... */
-&& isdigit(colon[5])
- ) {
- /* It's syslog file, not a bare dmesg */
-
- /* Skip non-kernel lines */
- char *kernel_str = strstr(c, "kernel: ");
- if (!kernel_str)
- {
- /* if we see our own marker:
- * "hostname abrt: Kerneloops: Reported 1 kernel oopses to
Abrt"
- * we know we submitted everything upto here already */
- if (strstr(c, "kernel oopses to Abrt"))
- {
- VERB3 log("Found our marker at line %d", linecount);
- free(lines_info);
- lines_info = NULL;
- lines_info_size = 0;
- list_free_with_free(*oops_list);
- *oops_list = NULL;
- }
- goto next_line;
- }
- c = kernel_str + sizeof("kernel: ")-1;
- }
-
- linelevel = 0;
- /* store and remove kernel log level */
- if (*c == '<'&& c[1]&& c[2] == '>')
- {
- linelevel = c[1];
- c += 3;
- }
- /* remove jiffies time stamp counter if present */
- if (*c == '[')
- {
- char *c2 = strchr(c, '.');
- char *c3 = strchr(c, ']');
- if (c2&& c3&& (c2< c3)&& (c3-c)<
14&& (c2-c)< 8)
- {
- c = c3 + 1;
- if (*c == ' ')
- c++;
- }
- }
- if ((lines_info_size& 0xfff) == 0)
- {
- lines_info = xrealloc(lines_info, (lines_info_size + 0x1000) *
sizeof(lines_info[0]));
- }
- lines_info[lines_info_size].ptr = c;
- lines_info[lines_info_size].level = linelevel;
- lines_info_size++;
-next_line:
- c = c9 + 1;
- }
-
- /* Analyze lines */
-
- int i;
- char prevlevel = 0;
- int oopsstart = -1;
- int inbacktrace = 0;
-
- i = 0;
- while (i< lines_info_size)
- {
- char *curline = lines_info[i].ptr;
-
- if (curline == NULL)
- {
- i++;
- continue;
- }
- while (*curline == ' ')
- curline++;
-
- if (oopsstart< 0)
- {
- /* Find start-of-oops markers */
- /* In some comparisons, we skip 1st letter, to avoid dealing with
- * changes in capitalization in kernel. For example, I see that
- * current kernel git (at 2011-01-01) has both "kernel BUG at
..."
- * and "Kernel BUG at ..." messages, and I don't want to
change
- * the code below whenever kernel is changed to use "K" (or
"k")
- * uniformly.
- */
- if (strstr(curline, /*g*/ "eneral protection fault:"))
- oopsstart = i;
- else if (strstr(curline, "BUG:"))
- oopsstart = i;
- else if (strstr(curline, /*k*/ "ernel BUG at"))
- oopsstart = i;
- else if (strstr(curline, "do_IRQ: stack overflow:"))
- oopsstart = i;
- else if (strstr(curline, "RTNL: assertion failed"))
- oopsstart = i;
- else if (strstr(curline, /*e*/ "eek! page_mapcount(page) went
negative!"))
- oopsstart = i;
- else if (strstr(curline, /*n*/ "ear stack overflow (cur:"))
- oopsstart = i;
- else if (strstr(curline, /*d*/ "ouble fault:"))
- oopsstart = i;
- else if (strstr(curline, /*b*/ "adness at"))
- oopsstart = i;
- else if (strstr(curline, "NETDEV WATCHDOG"))
- oopsstart = i;
- else if (strstr(curline, "WARNING: at ")) /* WARN_ON() generated
message */
- oopsstart = i;
- else if (strstr(curline, /*u*/ "nable to handle kernel"))
- oopsstart = i;
- else if (strstr(curline, /*s*/ "ysctl table check failed"))
- oopsstart = i;
- else if (strstr(curline, "INFO: possible recursive locking
detected"))
- oopsstart = i;
- // Not needed: "--[ cut here ]--" is always followed
- // by "Badness at", "kernel BUG at", or "WARNING:
at" string
- //else if (strstr(curline, "------------[ cut here
]------------"))
- // oopsstart = i;
- else if (strstr(curline, "list_del corruption"))
- oopsstart = i;
- else if (strstr(curline, "list_add corruption"))
- oopsstart = i;
-
- if (i>= 3&& strstr(curline, "Oops:"))
- oopsstart = i-3;
-
- if (oopsstart>= 0)
- {
- /* debug information */
- VERB3 {
- log("Found oops at line %d: '%s'", oopsstart,
lines_info[oopsstart].ptr);
- if (oopsstart != i)
- log("Trigger line is %d: '%s'", i, c);
- }
- /* try to find the end marker */
- int i2 = i + 1;
- while (i2< lines_info_size&& i2< (i+50))
- {
- if (strstr(lines_info[i2].ptr, "---[ end trace"))
- {
- inbacktrace = 1;
- i = i2;
- break;
- }
- i2++;
- }
- }
- }
-
- /* Are we entering a call trace part? */
- /* a call trace starts with "Call Trace:" or with the "
[<.......>] function+0xFF/0xAA" pattern */
- if (oopsstart>= 0&& !inbacktrace)
- {
- if (strstr(curline, "Call Trace:"))
- inbacktrace = 1;
- else
- if (strnlen(curline, 9)> 8
-&& curline[0] == '['&& curline[1] == '<'
-&& strstr(curline, ">]")
-&& strstr(curline, "+0x")
-&& strstr(curline, "/0x")
- ) {
- inbacktrace = 1;
- }
- }
-
- /* Are we at the end of an oops? */
- else if (oopsstart>= 0&& inbacktrace)
- {
- int oopsend = INT_MAX;
-
- /* line needs to start with " [" or have "] [" if it is
still a call trace */
- /* example: "[<ffffffffa006c156>] radeon_get_ring_head+0x16/0x41
[radeon]" */
- if (curline[0] != '['
-&& !strstr(curline, "] [")
-&& !strstr(curline, "--- Exception")
-&& !strstr(curline, "LR =")
-&& !strstr(curline, "<#DF>")
-&& !strstr(curline, "<IRQ>")
-&& !strstr(curline, "<EOI>")
-&& !strstr(curline, "<<EOE>>")
-&& strncmp(curline, "Code: ", 6) != 0
-&& strncmp(curline, "RIP ", 4) != 0
-&& strncmp(curline, "RSP ", 4) != 0
- ) {
- oopsend = i-1; /* not a call trace line */
- }
- /* oops lines are always more than 8 chars long */
- else if (strnlen(curline, 8)< 8)
- oopsend = i-1;
- /* single oopses are of the same loglevel */
- else if (lines_info[i].level != prevlevel)
- oopsend = i-1;
- else if (strstr(curline, "Instruction dump:"))
- oopsend = i;
- /* if a new oops starts, this one has ended */
- else if (strstr(curline, "WARNING: at ")&& oopsstart !=
i) /* WARN_ON() generated message */
- oopsend = i-1;
- else if (strstr(curline, "Unable to handle")&& oopsstart
!= i)
- oopsend = i-1;
- /* kernel end-of-oops marker (not including marker itself) */
- else if (strstr(curline, "---[ end trace"))
- oopsend = i-1;
-
- if (oopsend<= i)
- {
- VERB3 log("End of oops at line %d (%d): '%s'",
oopsend, i, lines_info[oopsend].ptr);
- record_oops(oops_list, lines_info, oopsstart, oopsend);
- oopsstart = -1;
- inbacktrace = 0;
- }
- }
-
- prevlevel = lines_info[i].level;
- i++;
-
- if (oopsstart>= 0)
- {
- /* Do we have a suspiciously long oops? Cancel it */
- if (i-oopsstart> 60)
- {
- inbacktrace = 0;
- oopsstart = -1;
- VERB3 log("Dropped oops, too long");
- continue;
- }
- if (!inbacktrace&& i-oopsstart> 40)
- {
- /*inbacktrace = 0; - already is */
- oopsstart = -1;
- VERB3 log("Dropped oops, too long");
- continue;
- }
- }
- } /* while (i< lines_info_size) */
-
- /* process last oops if we have one */
- if (oopsstart>= 0&& inbacktrace)
- {
- int oopsend = i-1;
- VERB3 log("End of oops at line %d (end of file): '%s'",
oopsend, lines_info[oopsend].ptr);
- record_oops(oops_list, lines_info, oopsstart, oopsend);
- }
-
- free(lines_info);
-}
-
#define MAX_SCAN_BLOCK (4*1024*1024)
#define READ_AHEAD (10*1024)
@@ -404,7 +39,7 @@ static void scan_dmesg(GList **oops_list)
*/
char *buffer = xzalloc(16*1024);
syscall(__NR_syslog, 3, buffer, 16*1024 - 1); /* always NUL terminated */
- extract_oopses(oops_list, buffer, strlen(buffer));
+ koops_extract_oopses(oops_list, buffer, strlen(buffer));
free(buffer);
}
@@ -463,7 +98,7 @@ static int scan_syslog_file(GList **oops_list, int fd, struct stat
*statbuf, int
if (partial_line_len> 500) /* cap it */
partial_line_len = 500;
- extract_oopses(oops_list, buffer, r);
+ koops_extract_oopses(oops_list, buffer, r);
cur_pos += r;
} while (cur_pos< statbuf->st_size);
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..5dcea73
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,54 @@
+## ------------ ##
+## package.m4. ##
+## ------------ ##
+
+package.m4: Makefile.in
+ { \
+ echo '# Signature of the current package.'&& \
+ echo 'm4_define([AT_PACKAGE_NAME],'&& \
+ echo ' [@PACKAGE_NAME@])'&& \
+ echo 'm4_define([AT_PACKAGE_TARNAME],'&& \
+ echo ' [@PACKAGE_TARNAME@])'&& \
+ echo 'm4_define([AT_PACKAGE_VERSION],'&& \
+ echo ' [@PACKAGE_VERSION@])'&& \
+ echo 'm4_define([AT_PACKAGE_STRING],'&& \
+ echo ' [@PACKAGE_STRING@])'&& \
+ echo 'm4_define([AT_PACKAGE_BUGREPORT],'&& \
+ echo ' [@PACKAGE_BUGREPORT@])'; \
+ echo 'm4_define([AT_PACKAGE_URL],'&& \
+ echo ' [@PACKAGE_URL@])'; \
+ }>'package.m4'
+EXTRA_DIST = package.m4
+
+## ------------ ##
+## Test suite. ##
+## ------------ ##
+
+TESTSUITE_AT = \
+ local.at \
+ testsuite.at \
+ koops-parser.at
+
+EXTRA_DIST += $(TESTSUITE_AT)
+TESTSUITE = $(srcdir)/testsuite
+MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE)
+check_DATA = atconfig atlocal $(TESTSUITE)
+DISTCLEANFILES = atconfig
+EXTRA_DIST += atlocal.in
+
+atconfig: $(top_builddir)/config.status
+ (cd ${top_builddir}&& ./config.status ${subdir}/atconfig)
+
+check-local: $(check_DATA)
+ $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) ||:
+
+installcheck-local: $(check_DATA)
+ $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' $(TESTSUITEFLAGS)
||:
+
+clean-local:
+ test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' --clean
+
+AUTOTEST = $(AUTOM4TE) --language=autotest
+$(TESTSUITE): $(TESTSUITE_AT) $(srcdir)/package.m4
+ $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
+ mv $@.tmp $@
diff --git a/tests/atlocal.in b/tests/atlocal.in
new file mode 100644
index 0000000..00c6885
--- /dev/null
+++ b/tests/atlocal.in
@@ -0,0 +1,15 @@
+# @configure_input@ -*- shell-script -*-
+# Configurable variable values for btparser test suite.
+
+# We need a C compiler.
+CC='@CC@'
+LIBTOOL="$abs_top_builddir/libtool"
+
+# We want no optimization.
+CFLAGS="@O0CFLAGS@ -I$abs_top_builddir/src/include -D_GNU_SOURCE @GLIB_CFLAGS@
@LIBREPORT_CFLAGS@"
+
+# Are special link options needed?
+LDFLAGS="@LDFLAGS@ $abs_top_builddir/src/lib/libabrt.la"
+
+# Are special libraries needed?
+LIBS="@LIBS@ @LIBREPORT_LIBS@"
diff --git a/tests/koops-parser.at b/tests/koops-parser.at
new file mode 100644
index 0000000..620903b
--- /dev/null
+++ b/tests/koops-parser.at
@@ -0,0 +1,46 @@
+# -*- Autotest -*-
+
+AT_BANNER([kernel_oops_parser])
+
+AT_TESTFUN([koops_extract_version],
+[[
+#include "libabrt.h"
+
+int run_test(const char *filename)
+{
+ FILE *fp = fopen(filename, "r");
+ if (!fp)
+ perror_msg_and_die("Can't open '%s'", filename);
+
+ char *line;
+ while ((line = xmalloc_fgetline(fp)) != NULL)
+ {
+ char *version = koops_extract_version(line);
+ if (version)
+ {
+ log("version %s", version);
+ return 0;
+ }
+
+ free(line);
+ }
+ fclose(fp);
+ return 1;
+}
- the test, just tests if it extracted *some version* it should test if
it extracted the *correct version*
+
+int main(void)
+{
+ /* tests run in abrt/tests/testsuite.dir/X, where X is test number */
+ char *filenames[] = {
+ "../../../examples/cut_here.right",
+ "../../../examples/oops-kernel-3.x.x",
+ NULL
+ };
+ int ret = 0;
+ char **tmp = filenames;
+ for ( ; *tmp; tmp++)
+ ret |= run_test(*tmp);
+
+ return ret;
- it's hard to guess which test fails from this output
- how about:
for ( ; *tmp; tmp++)
{
int retval = run_test(*tmp)
if (retval)
log("Koops test failed for %s", *tmp);
ret |= retval;
+}
+]])
diff --git a/tests/local.at b/tests/local.at
new file mode 100644
index 0000000..758906d
--- /dev/null
+++ b/tests/local.at
@@ -0,0 +1,27 @@
+# Source: bison local.at
+
+# ----------------------------------------
+# AT_COMPILE(OUTPUT, [SOURCES = OUTPUT.c])
+# ----------------------------------------
+# Compile SOURCES into OUTPUT. If OUTPUT does not contain '.',
+# assume that we are linking too; this is a hack.
+m4_define([AT_COMPILE],
+[AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS m4_bmatch([$1], [[.]], [], [$LDFLAGS ])-o $1
m4_default([$2], [$1.c])[]m4_bmatch([$1], [[.]], [], [ $LIBS])],
+ 0, [ignore], [ignore])])
+
+# ------------------------
+# AT_TESTFUN(NAME, SOURCE)
+# ------------------------
+
+# Create a test named NAME by compiling and running C file with
+# contents SOURCE. The stdout and stderr output of the C program is
+# ignored by Autotest.
+
+m4_define([AT_TESTFUN],
+[AT_SETUP([$1])
+AT_DATA([$1.c], [$2])
+AT_COMPILE([$1])
+AT_CHECK([./$1], 0, [ignore], [ignore])
+AT_CLEANUP])
+
+AT_INIT
diff --git a/tests/testsuite.at b/tests/testsuite.at
new file mode 100644
index 0000000..807da66
--- /dev/null
+++ b/tests/testsuite.at
@@ -0,0 +1,4 @@
+# Test suite for abrt.
+# See
http://www.gnu.org/software/hello/manual/autoconf/Writing-Testsuites.html
+
+m4_include([koops-parser.at])