Introduce a new option -s for log command which outputs
unflushed logs of the printk safe buffers
(safe_print_seq/nmi_print_seq) as follows:
PRINTK_SAFE_SEQ_BUF: nmi_print_seq
CPU: 0 ADDR: ffff8ca4fbc19ce0 LEN: 150 MESSAGE_LOST: 0
Uhhuh. NMI received for unknown reason 20 on CPU 0.
Do you have a strange power saving mode enabled?
Dazed and confused, but trying to continue
The buffers are displayed for each CPU. For an empty
buffer, '(empty)' will be printed.
Signed-off-by: Shogo Matsumoto <shogo.matsumoto(a)fujitsu.com>
---
defs.h | 5 +++
kernel.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 111 insertions(+), 1 deletion(-)
diff --git a/defs.h b/defs.h
index b63741c..c26e604 100644
--- a/defs.h
+++ b/defs.h
@@ -2146,6 +2146,9 @@ struct offset_table { /* stash of commonly-used
offsets */
long wait_queue_entry_private;
long wait_queue_head_head;
long wait_queue_entry_entry;
+ long printk_safe_seq_buf_len;
+ long printk_safe_seq_buf_message_lost;
+ long printk_safe_seq_buf_buffer;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2310,6 +2313,7 @@ struct size_table { /* stash of commonly-used sizes */
long prb_desc;
long wait_queue_entry;
long task_struct_state;
+ long printk_safe_seq_buf_buffer;
};
struct array_table {
@@ -5699,6 +5703,7 @@ void dump_log(int);
#define SHOW_LOG_TEXT (0x4)
#define SHOW_LOG_AUDIT (0x8)
#define SHOW_LOG_CTIME (0x10)
+#define SHOW_LOG_SAFE (0x20)
void set_cpu(int);
void clear_machdep_cache(void);
struct stack_hook *gather_text_list(struct bt_info *);
diff --git a/kernel.c b/kernel.c
index 37b7af7..461a5f2 100644
--- a/kernel.c
+++ b/kernel.c
@@ -93,6 +93,7 @@ static void source_tree_init(void);
static ulong dump_audit_skb_queue(ulong);
static ulong __dump_audit(char *);
static void dump_audit(void);
+static void dump_printk_safe_seq_buf(int);
static char *vmcoreinfo_read_string(const char *);
static void check_vmcoreinfo(void);
static int is_pvops_xen(void);
@@ -4998,7 +4999,7 @@ cmd_log(void)
msg_flags = 0;
- while ((c = getopt(argcnt, args, "Ttdma")) != EOF) {
+ while ((c = getopt(argcnt, args, "Ttdmas")) != EOF) {
switch(c)
{
case 'T':
@@ -5016,6 +5017,9 @@ cmd_log(void)
case 'a':
msg_flags |= SHOW_LOG_AUDIT;
break;
+ case 's':
+ msg_flags |= SHOW_LOG_SAFE;
+ break;
default:
argerrs++;
break;
@@ -5047,6 +5051,11 @@ cmd_log(void)
return;
}
+ if (msg_flags & SHOW_LOG_SAFE) {
+ dump_printk_safe_seq_buf(msg_flags);
+ return;
+ }
+
dump_log(msg_flags);
}
@@ -11544,6 +11553,102 @@ dump_audit(void)
error(INFO, "kernel audit log is empty\n");
}
+static void
+__dump_printk_safe_seq_buf(char *buf_name, int msg_flags)
+{
+ int cpu, buffer_size;
+ char *buffer;
+ ulong base_addr, len_addr, message_lost_addr, buffer_addr;
+
+ if (!symbol_exists(buf_name)) {
+ return;
+ }
+
+ base_addr = symbol_value(buf_name);
+ len_addr = base_addr + OFFSET(printk_safe_seq_buf_len)
+ + OFFSET(atomic_t_counter);
+ message_lost_addr = base_addr
+ + OFFSET(printk_safe_seq_buf_message_lost)
+ + OFFSET(atomic_t_counter);
+ buffer_addr = base_addr + OFFSET(printk_safe_seq_buf_buffer);
+ buffer_size = SIZE(printk_safe_seq_buf_buffer);
+ buffer = GETBUF(buffer_size);
+
+ fprintf(fp, "PRINTK_SAFE_SEQ_BUF: %s\n", buf_name);
+ for (cpu = 0; cpu < kt->cpus; cpu++) {
+ int len, message_lost;
+ ulong per_cpu_offset;
+ per_cpu_offset = kt->__per_cpu_offset[cpu];
+
+ readmem(len_addr + per_cpu_offset, KVADDR, &len, sizeof(int),
+ "printk_safe_seq_buf len", FAULT_ON_ERROR);
+ readmem(message_lost_addr + per_cpu_offset, KVADDR,
+ &message_lost, sizeof(int),
+ "printk_safe_seq_buf message_lost", FAULT_ON_ERROR);
+ fprintf(fp, "CPU: %d ADDR: %lx LEN: %d MESSAGE_LOST: %d\n",
+ cpu, base_addr + per_cpu_offset, len, message_lost);
+
+ if (len > 0) {
+ int i, n;
+ char *p;
+
+ readmem(buffer_addr + per_cpu_offset, KVADDR,
+ buffer, buffer_size,
+ "printk_safe_seq_buf buffer", FAULT_ON_ERROR);
+
+ n = (len <= buffer_size) ? len : buffer_size;
+ for (i = 0, p = buffer; i < n; i++, p++) {
+ if (*p == 0x1) { //SOH
+ i++; p++;
+ continue;
+ } else {
+ if (isprint(*p) || isspace(*p)) {
+ fputc(*p, fp);
+ } else {
+ fputc('.', fp);
+ }
+ }
+ }
+ fputc('\n', fp);
+ } else {
+ fprintf(fp, "(empty)\n\n");
+ }
+ }
+ FREEBUF(buffer);
+}
+
+static void
+dump_printk_safe_seq_buf(int msg_flags)
+{
+ if (!STRUCT_EXISTS("printk_safe_seq_buf"))
+ return;
+
+ if (INVALID_SIZE(printk_safe_seq_buf_buffer)) {
+ MEMBER_OFFSET_INIT(printk_safe_seq_buf_len,
+ "printk_safe_seq_buf", "len");
+ MEMBER_OFFSET_INIT(printk_safe_seq_buf_message_lost,
+ "printk_safe_seq_buf", "message_lost");
+ MEMBER_OFFSET_INIT(printk_safe_seq_buf_buffer,
+ "printk_safe_seq_buf", "buffer");
+
+ if (!INVALID_MEMBER(printk_safe_seq_buf_buffer)) {
+ MEMBER_SIZE_INIT(printk_safe_seq_buf_buffer,
+ "printk_safe_seq_buf", "buffer");
+ }
+ }
+
+ if (INVALID_MEMBER(printk_safe_seq_buf_len) ||
+ INVALID_MEMBER(printk_safe_seq_buf_message_lost) ||
+ INVALID_MEMBER(printk_safe_seq_buf_buffer) ||
+ INVALID_SIZE(printk_safe_seq_buf_buffer)) {
+ error(INFO, "-s not supported with this kernel version\n");
+ return;
+ }
+
+ __dump_printk_safe_seq_buf("nmi_print_seq", msg_flags);
+ __dump_printk_safe_seq_buf("safe_print_seq", msg_flags);
+}
+
/*
* Reads a string value from the VMCOREINFO data stored in (live) memory.
*
--
2.29.2