File crash-var_length_log_rec.patch of Package crash
diff -ur crash-6.0.7.orig/defs.h crash-6.0.7/defs.h
--- crash-6.0.7.orig/defs.h 2012-12-31 10:40:27.997859461 -0500
+++ crash-6.0.7/defs.h 2012-12-31 12:35:19.693388207 -0500
@@ -1759,6 +1759,11 @@
long msg_queue_q_qnum;
long super_block_s_fs_info;
long rq_timestamp;
+ long log_ts_nsec;
+ long log_len;
+ long log_text_len;
+ long log_dict_len;
+ long log_level;
};
struct size_table { /* stash of commonly-used sizes */
@@ -1891,6 +1896,7 @@
long shmid_kernel;
long sem_array;
long msg_queue;
+ long log;
};
struct array_table {
@@ -4328,6 +4334,9 @@
void dump_kernel_table(int);
void dump_bt_info(struct bt_info *, char *where);
void dump_log(int);
+#define SHOW_LOG_LEVEL (0x1)
+#define SHOW_LOG_DICT (0x2)
+#define SHOW_LOG_TEXT (0x4)
void set_cpu(int);
void clear_machdep_cache(void);
struct stack_hook *gather_text_list(struct bt_info *);
diff -ur crash-6.0.7.orig/help.c crash-6.0.7/help.c
--- crash-6.0.7.orig/help.c 2012-05-30 14:25:37.000000000 -0400
+++ crash-6.0.7/help.c 2012-12-31 11:00:00.022779319 -0500
@@ -2921,10 +2921,18 @@
char *help_log[] = {
"log",
"dump system message buffer",
-"[-m]",
-" This command dumps the kernel log_buf contents in chronological order.",
+"[-tdm]",
+" This command dumps the kernel log_buf contents in chronological order. The",
+" command supports the older log_buf formats, which may or may not contain a",
+" timestamp inserted prior to each message, as well as the newer variable-length",
+" record format, where the timestamp is contained in each log entry's header.",
" ",
-" -m Display the message log level preceding each message.",
+" -t Display the message text without the timestamp; only applicable to the",
+" variable-length record format.",
+" -d Display the dictionary of key/value pair properties that are optionally",
+" appended to a message by the kernel's dev_printk() function; only",
+" applicable to the variable-length record format.",
+" -m Display the message log level in brackets preceding each message.",
"\nEXAMPLES",
" Dump the kernel message buffer:\n",
" %s> log",
@@ -2973,6 +2981,49 @@
" <6>Installing knfsd (copyright (C) 1996 okir@monad.swb.de).",
" <7>nfsd_init: initialized fhcache, entries=256",
" ... ",
+" ",
+" On a system with the variable-length record format, and whose log_buf has been",
+" filled and wrapped around, display the log with timestamp data:\n",
+" %s> log",
+" [ 0.467730] pci 0000:ff:02.0: [8086:2c10] type 00 class 0x060000",
+" [ 0.467749] pci 0000:ff:02.1: [8086:2c11] type 00 class 0x060000",
+" [ 0.467769] pci 0000:ff:02.4: [8086:2c14] type 00 class 0x060000",
+" [ 0.467788] pci 0000:ff:02.5: [8086:2c15] type 00 class 0x060000",
+" [ 0.467809] pci 0000:ff:03.0: [8086:2c18] type 00 class 0x060000",
+" [ 0.467828] pci 0000:ff:03.1: [8086:2c19] type 00 class 0x060000",
+" ...",
+" ",
+" Display the same message text as above, without the timestamp data:\n",
+" %s> log -t",
+" pci 0000:ff:02.0: [8086:2c10] type 00 class 0x060000",
+" pci 0000:ff:02.1: [8086:2c11] type 00 class 0x060000",
+" pci 0000:ff:02.4: [8086:2c14] type 00 class 0x060000",
+" pci 0000:ff:02.5: [8086:2c15] type 00 class 0x060000",
+" pci 0000:ff:03.0: [8086:2c18] type 00 class 0x060000",
+" pci 0000:ff:03.1: [8086:2c19] type 00 class 0x060000",
+" ...",
+" ",
+" Display the same message text as above, with appended dictionary data:\n",
+" %s> log -td",
+" pci 0000:ff:02.0: [8086:2c10] type 00 class 0x060000",
+" SUBSYSTEM=pci",
+" DEVICE=+pci:0000:ff:02.0",
+" pci 0000:ff:02.1: [8086:2c11] type 00 class 0x060000",
+" SUBSYSTEM=pci",
+" DEVICE=+pci:0000:ff:02.1",
+" pci 0000:ff:02.4: [8086:2c14] type 00 class 0x060000",
+" SUBSYSTEM=pci",
+" DEVICE=+pci:0000:ff:02.4",
+" pci 0000:ff:02.5: [8086:2c15] type 00 class 0x060000",
+" SUBSYSTEM=pci",
+" DEVICE=+pci:0000:ff:02.5",
+" pci 0000:ff:03.0: [8086:2c18] type 00 class 0x060000",
+" SUBSYSTEM=pci",
+" DEVICE=+pci:0000:ff:03.0",
+" pci 0000:ff:03.1: [8086:2c19] type 00 class 0x060000",
+" SUBSYSTEM=pci",
+" DEVICE=+pci:0000:ff:03.1",
+" ...",
NULL
};
diff -ur crash-6.0.7.orig/kernel.c crash-6.0.7/kernel.c
--- crash-6.0.7.orig/kernel.c 2012-12-31 10:40:27.999859463 -0500
+++ crash-6.0.7/kernel.c 2012-12-31 12:18:24.621457616 -0500
@@ -19,6 +19,7 @@
#include "xen_hyper_defs.h"
#include <elf.h>
#include <libgen.h>
+#include <ctype.h>
static void do_module_cmd(ulong, char *, ulong, char *, char *);
static char *find_module_objfile(char *, char *, char *);
@@ -55,6 +56,10 @@
static int BUG_x86_64(void);
static void cpu_maps_init(void);
static void get_xtime(struct timespec *);
+static char *log_from_idx(uint32_t, char *);
+static uint32_t log_next(uint32_t, char *);
+static void dump_log_entry(char *, int);
+static void dump_variable_length_record_log(int);
/*
@@ -3888,15 +3893,21 @@
cmd_log(void)
{
int c;
- int msg_level;
+ int msg_flags;
- msg_level = FALSE;
+ msg_flags = 0;
- while ((c = getopt(argcnt, args, "m")) != EOF) {
+ while ((c = getopt(argcnt, args, "tdm")) != EOF) {
switch(c)
{
+ case 't':
+ msg_flags |= SHOW_LOG_TEXT;
+ break;
+ case 'd':
+ msg_flags |= SHOW_LOG_DICT;
+ break;
case 'm':
- msg_level = TRUE;
+ msg_flags |= SHOW_LOG_LEVEL;
break;
default:
argerrs++;
@@ -3907,14 +3918,14 @@
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
- dump_log(msg_level);
+ dump_log(msg_flags);
}
void
-dump_log(int msg_level)
+dump_log(int msg_flags)
{
- int i, len, tmp;
+ int i, len, tmp, show_level;
ulong log_buf, log_end;
char *buf;
char last;
@@ -3922,6 +3933,19 @@
struct syment *nsp;
int log_wrap, loglevel, log_buf_len;
+ if (kernel_symbol_exists("log_first_idx") &&
+ kernel_symbol_exists("log_next_idx")) {
+ dump_variable_length_record_log(msg_flags);
+ return;
+ }
+
+ if (msg_flags & SHOW_LOG_DICT)
+ option_not_supported('d');
+ if ((msg_flags & SHOW_LOG_TEXT) && STREQ(pc->curcmd, "log"))
+ option_not_supported('t');
+
+ show_level = msg_flags & SHOW_LOG_LEVEL ? TRUE : FALSE;
+
if (symbol_exists("log_buf_len")) {
get_symbol_data("log_buf_len", sizeof(int), &log_buf_len);
get_symbol_data("log_buf", sizeof(ulong), &log_buf);
@@ -3968,7 +3992,7 @@
wrap_around:
for (i = index; i < log_buf_len; i++) {
- if (loglevel && !msg_level) {
+ if (loglevel && !show_level) {
switch (buf[i])
{
case '>':
@@ -4011,6 +4035,205 @@
FREEBUF(buf);
}
+/*
+ * get log record by index; idx must point to valid message.
+ */
+static char *
+log_from_idx(uint32_t idx, char *logbuf)
+{
+ char *logptr;
+ uint16_t msglen;
+
+ logptr = logbuf + idx;
+
+ /*
+ * A length == 0 record is the end of buffer marker.
+ * Wrap around and return the message at the start of
+ * the buffer.
+ */
+
+ msglen = USHORT(logptr + OFFSET(log_len));
+ if (!msglen)
+ logptr = logbuf;
+
+ return logptr;
+}
+
+/*
+ * get next record index; idx must point to valid message.
+ */
+static uint32_t
+log_next(uint32_t idx, char *logbuf)
+{
+ char *logptr;
+ uint16_t msglen;
+
+ logptr = logbuf + idx;
+
+ /*
+ * A length == 0 record is the end of buffer marker. Wrap around and
+ * read the message at the start of the buffer as *this* one, and
+ * return the one after that.
+ */
+
+ msglen = USHORT(logptr + OFFSET(log_len));
+ if (!msglen) {
+ msglen = USHORT(logbuf + OFFSET(log_len));
+ return msglen;
+ }
+
+ return idx + msglen;
+}
+
+static void
+dump_log_entry(char *logptr, int msg_flags)
+{
+ int indent;
+ char *msg, *p;
+ uint16_t i, text_len, dict_len, level;
+ uint64_t ts_nsec;
+ ulonglong nanos;
+ ulong rem;
+ char buf[BUFSIZE];
+ int ilen;
+
+ ilen = 0;
+ text_len = USHORT(logptr + OFFSET(log_text_len));
+ dict_len = USHORT(logptr + OFFSET(log_dict_len));
+ level = USHORT(logptr + OFFSET(log_level));
+ ts_nsec = ULONGLONG(logptr + OFFSET(log_ts_nsec));
+
+ msg = logptr + SIZE(log);
+
+ if (CRASHDEBUG(1))
+ fprintf(fp,
+ "\nlog %lx -> msg: %lx ts_nsec: %lld level: %d"
+ " text_len: %d dict_len: %d\n",
+ (ulong)logptr, (ulong)msg, (ulonglong)ts_nsec,
+ level, text_len, dict_len);
+
+ if ((msg_flags & SHOW_LOG_TEXT) == 0) {
+ nanos = (ulonglong)ts_nsec / (ulonglong)1000000000;
+ rem = (ulonglong)ts_nsec % (ulonglong)1000000000;
+ sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000);
+ ilen = strlen(buf);
+ fprintf(fp, buf);
+ }
+
+ if (msg_flags & SHOW_LOG_LEVEL) {
+ fprintf(fp, "<%d>", level);
+ ilen += 3;
+ }
+
+ for (i = 0, p = msg; i < text_len; i++, p++)
+ fputc(isprint(*p) ? *p : '.', fp);
+
+ if (dict_len & (msg_flags & SHOW_LOG_DICT)) {
+ fprintf(fp, "\n");
+ indent = TRUE;
+
+ for (i = 0; i < dict_len; i++, p++) {
+ if (indent) {
+ fprintf(fp, "%s", space(ilen));
+ indent = FALSE;
+ }
+ if (isprint(*p))
+ fputc(*p, fp);
+ else if (*p == NULLCHAR) {
+ fputc('\n', fp);
+ indent = TRUE;
+ } else
+ fputc('.', fp);
+ }
+ }
+ fprintf(fp, "\n");
+}
+
+/*
+ * Handle the new variable-length-record log_buf.
+ */
+static void
+dump_variable_length_record_log(int msg_flags)
+{
+ uint32_t idx, log_first_idx, log_next_idx, log_buf_len;
+ ulong log_buf;
+ char *logptr, *logbuf;
+
+ if (INVALID_SIZE(log)) {
+ STRUCT_SIZE_INIT(log, "log");
+ MEMBER_OFFSET_INIT(log_ts_nsec, "log", "ts_nsec");
+ MEMBER_OFFSET_INIT(log_len, "log", "len");
+ MEMBER_OFFSET_INIT(log_text_len, "log", "text_len");
+ MEMBER_OFFSET_INIT(log_dict_len, "log", "dict_len");
+ MEMBER_OFFSET_INIT(log_level, "log", "level");
+ /*
+ * If things change, don't kill a dumpfile session
+ * searching for a panic message.
+ */
+ if (INVALID_SIZE(log) ||
+ INVALID_MEMBER(log_ts_nsec) ||
+ INVALID_MEMBER(log_len) ||
+ INVALID_MEMBER(log_text_len) ||
+ INVALID_MEMBER(log_dict_len) ||
+ INVALID_MEMBER(log_level) ||
+ !kernel_symbol_exists("log_buf_len") ||
+ !kernel_symbol_exists("log_buf")) {
+ error(WARNING, "\nlog buf data structure(s) have changed\n");
+ return;
+ }
+ }
+
+ get_symbol_data("log_first_idx", sizeof(uint32_t), &log_first_idx);
+ get_symbol_data("log_next_idx", sizeof(uint32_t), &log_next_idx);
+ get_symbol_data("log_buf_len", sizeof(uint32_t), &log_buf_len);
+ get_symbol_data("log_buf", sizeof(char *), &log_buf);
+
+ if (CRASHDEBUG(1)) {
+ fprintf(fp, "log_buf: %lx\n", (ulong)log_buf);
+ fprintf(fp, "log_buf_len: %d\n", log_buf_len);
+ fprintf(fp, "log_first_idx: %d\n", log_first_idx);
+ fprintf(fp, "log_next_idx: %d\n", log_next_idx);
+ }
+
+ logbuf = GETBUF(log_buf_len);
+
+ if (!readmem(log_buf, KVADDR, logbuf,
+ log_buf_len, "log_buf contents", RETURN_ON_ERROR|QUIET)) {
+ error(WARNING, "\ncannot read log_buf contents\n");
+ FREEBUF(logbuf);
+ return;
+ }
+
+ hq_open();
+
+ idx = log_first_idx;
+ while (idx != log_next_idx) {
+ logptr = log_from_idx(idx, logbuf);
+
+ dump_log_entry(logptr, msg_flags);
+
+ if (!hq_enter((ulong)logptr)) {
+ error(INFO, "\n duplicate log_buf message pointer\n");
+ break;
+ }
+
+ idx = log_next(idx, logbuf);
+
+ if (idx >= log_buf_len) {
+ error(INFO, "\ninvalid log_buf entry encountered\n");
+ break;
+ }
+
+ if (CRASHDEBUG(1) && (idx == log_next_idx))
+ fprintf(fp, "\nfound log_next_idx OK\n");
+ }
+
+ hq_close();
+
+ FREEBUF(logbuf);
+}
+
+
/*
* Display general system info.
diff -ur crash-6.0.7.orig/symbols.c crash-6.0.7/symbols.c
--- crash-6.0.7.orig/symbols.c 2012-12-31 10:40:56.623857504 -0500
+++ crash-6.0.7/symbols.c 2012-12-31 12:29:20.463412773 -0500
@@ -8770,6 +8770,16 @@
OFFSET(msg_queue_q_qnum));
fprintf(fp, " super_block_s_fs_info: %ld\n",
OFFSET(super_block_s_fs_info));
+ fprintf(fp, " log_ts_nsec: %ld\n",
+ OFFSET(log_ts_nsec));
+ fprintf(fp, " log_len: %ld\n",
+ OFFSET(log_len));
+ fprintf(fp, " log_text_len: %ld\n",
+ OFFSET(log_text_len));
+ fprintf(fp, " log_dict_len: %ld\n",
+ OFFSET(log_dict_len));
+ fprintf(fp, " log_level: %ld\n",
+ OFFSET(log_level));
fprintf(fp, "\n size_table:\n");
fprintf(fp, " page: %ld\n", SIZE(page));
@@ -8981,6 +8991,8 @@
SIZE(sem_array));
fprintf(fp, " msg_queue: %ld\n",
SIZE(msg_queue));
+ fprintf(fp, " log: %ld\n",
+ SIZE(log));
fprintf(fp, "\n array_table:\n");
/*
diff -ur crash-6.0.7.orig/task.c crash-6.0.7/task.c
--- crash-6.0.7.orig/task.c 2012-12-31 10:40:28.000859463 -0500
+++ crash-6.0.7/task.c 2012-12-31 11:01:57.532771285 -0500
@@ -5036,7 +5036,7 @@
return(buf);
open_tmpfile();
- dump_log(FALSE);
+ dump_log(SHOW_LOG_TEXT);
/*
* First check for a SYSRQ-generated crash, and set the