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@xxxxxxxxxxx> --- 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 Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility