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 <[email protected]>
---
 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


--
Crash-utility mailing list
[email protected]
https://listman.redhat.com/mailman/listinfo/crash-utility

Reply via email to