[PATCH v2] log: output logs of printk safe buffers
by shogo.matsumoto@fujitsu.com
We sometimes overlook logs written to printk safe buffers
(safe_print_seq/nmi_print_seq) which have not been flushed yet.
This patch will output unflushed logs of the safe buffers
at the bottom of log command output as follows:
[nmi_print_seq] CPU: 0 LEN: 188 MESSAGE_LOST: 0 WORK: ffff8c31fbc19ce8 BUFFER: ffff8c31fbc19d00
message2 message2 message2 message2
Uhhuh. NMI received for unknown reason 30 on CPU 0.
Do you have a strange power saving mode enabled?
Dazed and confused, but trying to continue
[safe_print_seq] CPU: 1 LEN: 38 MESSAGE_LOST: 0 WORK: ffff8c31fbc9ad08 BUFFER: ffff8c31fbc9ad20
message1 message1 message1 message1
Note that the safe buffer (struct printk_safe_seq_buf) was introduced
in kernel-4.11 (f92bac3b141b8233e34ddf32d227e12bfba07b48,
099f1c84c0052ec1b27f1c3942eed5830d86bdbb, ddb9baa822265b55afffd9815a2758a4b70006c1)
and removed in kernel-5.15 (93d102f094be9beab28e5afb656c188b16a3793b).
v2 Changes:
- add all members of struct printk_safe_seq_buf
- support help -o
- consider OFFSET(atomic_t_counter) for atomic_t member
- some code refactoring
Signed-off-by: Shogo Matsumoto <shogo.matsumoto(a)fujitsu.com>
---
defs.h | 5 ++++
kernel.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
symbols.c | 6 ++++
3 files changed, 98 insertions(+)
diff --git a/defs.h b/defs.h
index b63741c..f590910 100644
--- a/defs.h
+++ b/defs.h
@@ -2146,6 +2146,10 @@ 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_work;
+ long printk_safe_seq_buf_buffer;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2310,6 +2314,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 {
diff --git a/kernel.c b/kernel.c
index 37b7af7..b2a597c 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(void);
static char *vmcoreinfo_read_string(const char *);
static void check_vmcoreinfo(void);
static int is_pvops_xen(void);
@@ -5048,6 +5049,7 @@ cmd_log(void)
}
dump_log(msg_flags);
+ dump_printk_safe_seq_buf();
}
@@ -11544,6 +11546,91 @@ dump_audit(void)
error(INFO, "kernel audit log is empty\n");
}
+static void
+__dump_printk_safe_seq_buf(char *buf_name)
+{
+ int cpu, buffer_size;
+ char *buffer;
+ ulong len_addr, message_lost_addr, work_addr, buffer_addr;
+
+ if (!symbol_exists(buf_name)) {
+ return;
+ }
+
+ len_addr = symbol_value(buf_name) + OFFSET(printk_safe_seq_buf_len)
+ + OFFSET(atomic_t_counter);
+ message_lost_addr = symbol_value(buf_name)
+ + OFFSET(printk_safe_seq_buf_message_lost)
+ + OFFSET(atomic_t_counter);
+ work_addr = symbol_value(buf_name) + OFFSET(printk_safe_seq_buf_work);
+ buffer_addr = symbol_value(buf_name) + OFFSET(printk_safe_seq_buf_buffer);
+
+ buffer_size = SIZE(printk_safe_seq_buf_buffer);
+ buffer = GETBUF(buffer_size);
+ for (cpu = 0; cpu < kt->cpus; cpu++) {
+ int len;
+ 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);
+
+ if (len > 0) {
+ int message_lost;
+ int i, n;
+ char *p;
+
+ readmem(message_lost_addr + per_cpu_offset, KVADDR,
+ &message_lost, sizeof(int),
+ "printk_safe_seq_buf message_lost", FAULT_ON_ERROR);
+ readmem(buffer_addr + per_cpu_offset, KVADDR,
+ buffer, buffer_size,
+ "printk_safe_seq_buf buffer", FAULT_ON_ERROR);
+
+ fprintf(fp, "[%s] CPU: %d LEN: %d MESSAGE_LOST: %d"
+ " WORK: %lx BUFFER: %lx\n",
+ buf_name, cpu, len, message_lost,
+ work_addr + per_cpu_offset,
+ buffer_addr + per_cpu_offset);
+
+ n = (len <= buffer_size) ? len : buffer_size;
+ for (i = 0, p = buffer; i < n; i++, p++) {
+ if (*p == 0x1) { //SOH
+ i++; p++;
+ continue;
+ } else {
+ fputc(ascii(*p) ? *p : '.', fp);
+ }
+ }
+ fputc('\n', fp);
+ }
+ }
+ FREEBUF(buffer);
+}
+
+static void
+dump_printk_safe_seq_buf(void)
+{
+ 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_work,
+ "printk_safe_seq_buf", "work");
+ MEMBER_OFFSET_INIT(printk_safe_seq_buf_buffer,
+ "printk_safe_seq_buf", "buffer");
+ MEMBER_SIZE_INIT(printk_safe_seq_buf_buffer,
+ "printk_safe_seq_buf", "buffer");
+ }
+
+ __dump_printk_safe_seq_buf("nmi_print_seq");
+ __dump_printk_safe_seq_buf("safe_print_seq");
+}
+
/*
* Reads a string value from the VMCOREINFO data stored in (live) memory.
*
diff --git a/symbols.c b/symbols.c
index 73baa95..5c575a9 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10523,6 +10523,11 @@ dump_offset_table(char *spec, ulong makestruct)
fprintf(fp, " prb_data_ring_size_bits: %ld\n", OFFSET(prb_data_ring_size_bits));
fprintf(fp, " prb_data_ring_data: %ld\n", OFFSET(prb_data_ring_data));
fprintf(fp, " atomit_long_t_counter: %ld\n", OFFSET(atomic_long_t_counter));
+ fprintf(fp, " printk_safe_seq_buf_len: %ld\n", OFFSET(printk_safe_seq_buf_len));
+ fprintf(fp, "printk_safe_seq_buf_message_lost: %ld\n",
+ OFFSET(printk_safe_seq_buf_message_lost));
+ fprintf(fp, " printk_safe_seq_buf_work: %ld\n", OFFSET(printk_safe_seq_buf_work));
+ fprintf(fp, " printk_safe_seq_buf_buffer: %ld\n", OFFSET(printk_safe_seq_buf_buffer));
fprintf(fp, " sched_rt_entity_my_q: %ld\n",
OFFSET(sched_rt_entity_my_q));
@@ -10954,6 +10959,7 @@ dump_offset_table(char *spec, ulong makestruct)
fprintf(fp, " printk_info: %ld\n", SIZE(printk_info));
fprintf(fp, " printk_ringbuffer: %ld\n", SIZE(printk_ringbuffer));
fprintf(fp, " prb_desc: %ld\n", SIZE(prb_desc));
+ fprintf(fp, " printk_safe_seq_buf_buffer: %ld\n", SIZE(printk_safe_seq_buf_buffer));
fprintf(fp, "\n array_table:\n");
--
2.26.2
I also attach a test module printk_safe_buf_test.c
which I used to test this patch.
How to use:
1. Load the test module
2. Generate a NMI interrupt
3. Start crash on a live system and execute log command
I tested with the module in Fedora 32 (5.6.8-300.fc32.x86_64) and
CentOS 8 (4.18.0-348.el8.x86_64).
kallsyms_lookup_name should be replaced with the specific address
if kernel >= 5.7 is used.
printk_safe_buf_test.c:
=====
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/irq_work.h>
#include <linux/nmi.h>
static int msg1_line = 0;
static int output_msg1(struct kprobe *p, struct pt_regs *regs) {
if (msg1_line++ < 1)
printk(KERN_INFO "message1 message1 message1 message1\n");
return 0;
}
static int output_msg2(unsigned int cmd, struct pt_regs *regs) {
int i;
for (i = 0; i < 1; i++)
printk(KERN_INFO "message2 message2 message2 message2\n");
return 0;
}
static void empty_work(struct irq_work *work) {
}
static struct kprobe kp = {
.symbol_name = "__printk_safe_exit",
.pre_handler = output_msg1,
};
static int __init printk_safe_buf_test_init(void) {
int i, ret = 0;
ulong safe_print_seq, nmi_print_seq, per_cpu_offset;
struct dummy_printk_safe_seq_buf {
atomic_t len;
atomic_t message_lost;
struct irq_work work;
};
safe_print_seq = kallsyms_lookup_name("safe_print_seq");
nmi_print_seq = kallsyms_lookup_name("nmi_print_seq");
per_cpu_offset = kallsyms_lookup_name("__per_cpu_offset");
if (!(safe_print_seq && nmi_print_seq && per_cpu_offset))
return -1;
for (i = 0; i < num_possible_cpus(); i++) {
ulong offset = ((ulong*)per_cpu_offset)[i];
init_irq_work(&((struct dummy_printk_safe_seq_buf*)(offset + safe_print_seq))->work, empty_work);
init_irq_work(&((struct dummy_printk_safe_seq_buf*)(offset + nmi_print_seq))->work, empty_work);
}
ret = register_kprobe(&kp);
if (ret < 0) {
pr_err("register kp failed%d\n", ret);
return ret;
}
register_nmi_handler(NMI_LOCAL, output_msg2, 0, "output_msg2");
return 0;
}
static void __exit printk_safe_buf_test_exit(void) {
unregister_nmi_handler(NMI_LOCAL, "output_msg2");
unregister_kprobe(&kp);
return;
}
module_init(printk_safe_buf_test_init);
module_exit(printk_safe_buf_test_exit);
MODULE_LICENSE("GPL");
=====
2 years, 10 months
[PATCH] Fix for "bt -v" option to display the stack-end address correctly
by Lianbo Jiang
The "bt -v" command prints incorrect stack-end address when the
"CONFIG_THREAD_INFO_IN_TASK=y" is enabled in kernel, the "bt -v"
command output shows that the value stored at 0xffff8dee0312c198
is 0xffffffffc076400a, however, the value stored actually at
0xffff8dee0312c198 is NULL(0x0000000000000000), the stack-end
address is incorrect.
Without the patch:
crash> bt -v
PID: 28642 TASK: ffff8dee0312c180 CPU: 0 COMMAND: "insmod"
possible stack overflow: ffff8dee0312c198: ffffffffc076400a != STACK_END_MAGIC
^^^^^^^^^^^^^^^^
crash> rd 0xffff8dee0312c198
ffff8dee0312c198: 0000000000000000 ........
^^^^^^^^^^^^^^^^
With the patch:
crash> bt -v
PID: 28642 TASK: ffff8dee0312c180 CPU: 0 COMMAND: "insmod"
possible stack overflow: ffff991340bc0000: ffffffffc076400a != STACK_END_MAGIC
crash> rd 0xffff991340bc0000
ffff991340bc0000: ffffffffc076400a .@v.....
Signed-off-by: Lianbo Jiang <lijiang(a)redhat.com>
---
task.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/task.c b/task.c
index bb6a5da8ad33..b5ddc88e0acb 100644
--- a/task.c
+++ b/task.c
@@ -11202,7 +11202,7 @@ check_stack_overflow(void)
{
int i, overflow, cpu_size, cpu, total;
char buf[BUFSIZE];
- ulong magic, task, stackbase;
+ ulong magic, task, stackbase, location;
struct task_context *tc;
if (!tt->stack_end_magic &&
@@ -11286,9 +11286,15 @@ check_stack_end_magic:
if (magic != STACK_END_MAGIC) {
if (!overflow)
print_task_header(fp, tc, 0);
+
+ if (tt->flags & THREAD_INFO_IN_TASK)
+ location = task_to_stackbase(tc->task);
+ else
+ location = tc->thread_info + SIZE(thread_info);
+
fprintf(fp,
" possible stack overflow: %lx: %lx != STACK_END_MAGIC\n",
- tc->thread_info + SIZE(thread_info), magic);
+ location, magic);
overflow++, total++;
}
--
2.20.1
2 years, 10 months
[PATCH] Fix for "timer -r -C" option to display all the per-CPU clocks
by Lianbo Jiang
Currently, the hrtimer_max_clock_bases is hard-coded to 3, which
makes that crash only prints three clocks, and the rest of clocks
are not displayed.
Without the patch:
crash> timer -r -C 11
CPU: 11 HRTIMER_CPU_BASE: ffff9a775f95ee00
CLOCK: 0 HRTIMER_CLOCK_BASE: ffff9a775f95ee80 [ktime_get]
(empty)
CLOCK: 1 HRTIMER_CLOCK_BASE: ffff9a775f95ef00 [ktime_get_real]
(empty)
CLOCK: 2 HRTIMER_CLOCK_BASE: ffff9a775f95ef80 [ktime_get_boottime]
(empty)
With the patch:
crash> timer -r -C 11
CPU: 11 HRTIMER_CPU_BASE: ffff9a775f95ee00
CLOCK: 0 HRTIMER_CLOCK_BASE: ffff9a775f95ee80 [ktime_get]
(empty)
CLOCK: 1 HRTIMER_CLOCK_BASE: ffff9a775f95ef00 [ktime_get_real]
(empty)
CLOCK: 2 HRTIMER_CLOCK_BASE: ffff9a775f95ef80 [ktime_get_boottime]
(empty)
...
CLOCK: 7 HRTIMER_CLOCK_BASE: ffff9a775f95f200 [ktime_get_clocktai]
(empty)
Signed-off-by: Lianbo Jiang <lijiang(a)redhat.com>
---
kernel.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel.c b/kernel.c
index 37b7af74ed2e..36c57ed501ad 100644
--- a/kernel.c
+++ b/kernel.c
@@ -7675,7 +7675,8 @@ dump_hrtimer_data(const ulong *cpus)
if (VALID_STRUCT(hrtimer_clock_base)) {
hrtimer_max_clock_bases = 2;
if (symbol_exists("ktime_get_boottime"))
- hrtimer_max_clock_bases = 3;
+ hrtimer_max_clock_bases = MEMBER_SIZE("hrtimer_cpu_base", "clock_base") /
+ SIZE(hrtimer_clock_base);
} else if (VALID_STRUCT(hrtimer_base)) {
max_hrtimer_bases = 2;
} else
--
2.20.1
2 years, 10 months
[PATCH] log: output logs of printk safe buffers
by shogo.matsumoto@fujitsu.com
We sometimes overlook logs written to printk safe buffers
(safe_print_seq/nmi_print_seq) which have not been flushed yet.
This patch will output unflushed logs of the safe buffers
at the bottom of log command output as follows:
[nmi_print_seq] CPU: 0 BUFFER: ffff888063c18ac0 LEN: 28
nmi print seq test message
[safe_print_seq] CPU: 1 BUFFER: ffff888063d19ae0 LEN: 30
safe print seq test message
Note that the safe buffer (struct printk_safe_seq_buf) was introduced
in kernel-4.11 and removed in kernel-5.15.
Signed-off-by: Shogo Matsumoto <shogo.matsumoto(a)fujitsu.com>
---
defs.h | 3 +++
kernel.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 61 insertions(+)
diff --git a/defs.h b/defs.h
index 7e2a16e..3ee51e0 100644
--- a/defs.h
+++ b/defs.h
@@ -2146,6 +2146,8 @@ 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_buffer;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2310,6 +2312,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 {
diff --git a/kernel.c b/kernel.c
index f4598ea..cc97176 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(void);
static char *vmcoreinfo_read_string(const char *);
static void check_vmcoreinfo(void);
static int is_pvops_xen(void);
@@ -5048,6 +5049,7 @@ cmd_log(void)
}
dump_log(msg_flags);
+ dump_printk_safe_seq_buf();
}
@@ -11534,6 +11536,62 @@ dump_audit(void)
error(INFO, "kernel audit log is empty\n");
}
+static void
+__dump_printk_safe_seq_buf(char *buf_name)
+{
+ int cpu, buffer_size;
+ char *buffer;
+
+ if (!symbol_exists(buf_name)) {
+ return;
+ }
+
+ buffer_size = SIZE(printk_safe_seq_buf_buffer);
+ buffer = GETBUF(buffer_size);
+ for (cpu = 0; cpu < kt->cpus; cpu++) {
+ ulong len_addr, buffer_addr;
+ int len;
+
+ len_addr = symbol_value(buf_name) + kt->__per_cpu_offset[cpu] + OFFSET(printk_safe_seq_buf_len);
+ buffer_addr = symbol_value(buf_name) + kt->__per_cpu_offset[cpu] + OFFSET(printk_safe_seq_buf_buffer);
+ readmem(len_addr, KVADDR, &len, STRUCT_SIZE("atomic_t"), "printk_safe_seq_buf len", FAULT_ON_ERROR);
+ readmem(buffer_addr, KVADDR, buffer, buffer_size, "printk_safe_seq_buf buffer", FAULT_ON_ERROR);
+
+ if (len > 0) {
+ int i, n;
+ char *p;
+ fprintf(fp, "[%s] CPU: %d BUFFER: %lx LEN: %d\n", buf_name, cpu, buffer_addr, len);
+ n = (len <= buffer_size) ? len : buffer_size;
+ for (i = 0, p = buffer; i < n; i++, p++) {
+ if (*p == 0x1) { //SOH
+ i++; p++;
+ continue;
+ } else {
+ fputc(ascii(*p) ? *p : '.', fp);
+ }
+ }
+ fputc('\n', fp);
+ }
+ }
+ FREEBUF(buffer);
+}
+
+static void
+dump_printk_safe_seq_buf(void)
+{
+ 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_buffer, "printk_safe_seq_buf", "buffer");
+ MEMBER_SIZE_INIT(printk_safe_seq_buf_buffer, "printk_safe_seq_buf", "buffer");
+ }
+
+ __dump_printk_safe_seq_buf("nmi_print_seq");
+ __dump_printk_safe_seq_buf("safe_print_seq");
+}
+
/*
* Reads a string value from the VMCOREINFO data stored in (live) memory.
*
--
2.29.2
2 years, 10 months
Re: [Crash-utility] [PATCH] log: output logs of printk safe buffers
by lijiang
Hi, shogo
Thank you for the patch.
On Thu, Dec 16, 2021 at 4:01 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Thu, 16 Dec 2021 07:39:42 +0000
> From: "shogo.matsumoto(a)fujitsu.com" <shogo.matsumoto(a)fujitsu.com>
> To: "'crash-utility(a)redhat.com'" <crash-utility(a)redhat.com>
> Subject: [Crash-utility] [PATCH] log: output logs of printk safe
> buffers
> Message-ID:
> <TYAPR01MB62191B03B637D36487695277E2779(a)TYAPR01MB6219.jpnprd01.prod.outlook.com>
>
> Content-Type: text/plain; charset="iso-2022-jp"
>
> We sometimes overlook logs written to printk safe buffers
> (safe_print_seq/nmi_print_seq) which have not been flushed yet.
>
> This patch will output unflushed logs of the safe buffers
> at the bottom of log command output as follows:
>
> [nmi_print_seq] CPU: 0 BUFFER: ffff888063c18ac0 LEN: 28
> nmi print seq test message
> [safe_print_seq] CPU: 1 BUFFER: ffff888063d19ae0 LEN: 30
> safe print seq test message
>
> Note that the safe buffer (struct printk_safe_seq_buf) was introduced
> in kernel-4.11 and removed in kernel-5.15.
>
Although the safe buffer has been deprecated from the latest kernel
with the printk ringbuffer feature, it seems to be still helpful for
the old kernel.
> Signed-off-by: Shogo Matsumoto <shogo.matsumoto(a)fujitsu.com>
> ---
> defs.h | 3 +++
> kernel.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 61 insertions(+)
>
> diff --git a/defs.h b/defs.h
> index 7e2a16e..3ee51e0 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -2146,6 +2146,8 @@ 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_buffer;
> };
>
> struct size_table { /* stash of commonly-used sizes */
> @@ -2310,6 +2312,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;
> };
>
Can you help to add all new variables mentioned above to the dump table?
> struct array_table {
> diff --git a/kernel.c b/kernel.c
> index f4598ea..cc97176 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(void);
> static char *vmcoreinfo_read_string(const char *);
> static void check_vmcoreinfo(void);
> static int is_pvops_xen(void);
> @@ -5048,6 +5049,7 @@ cmd_log(void)
> }
>
> dump_log(msg_flags);
> + dump_printk_safe_seq_buf();
> }
>
This does not support dumping with the crash --log command, right?
Thanks.
Lianbo
>
> @@ -11534,6 +11536,62 @@ dump_audit(void)
> error(INFO, "kernel audit log is empty\n");
> }
>
> +static void
> +__dump_printk_safe_seq_buf(char *buf_name)
> +{
> + int cpu, buffer_size;
> + char *buffer;
> +
> + if (!symbol_exists(buf_name)) {
> + return;
> + }
> +
> + buffer_size = SIZE(printk_safe_seq_buf_buffer);
> + buffer = GETBUF(buffer_size);
> + for (cpu = 0; cpu < kt->cpus; cpu++) {
> + ulong len_addr, buffer_addr;
> + int len;
> +
> + len_addr = symbol_value(buf_name) + kt->__per_cpu_offset[cpu] + OFFSET(printk_safe_seq_buf_len);
> + buffer_addr = symbol_value(buf_name) + kt->__per_cpu_offset[cpu] + OFFSET(printk_safe_seq_buf_buffer);
> + readmem(len_addr, KVADDR, &len, STRUCT_SIZE("atomic_t"), "printk_safe_seq_buf len", FAULT_ON_ERROR);
> + readmem(buffer_addr, KVADDR, buffer, buffer_size, "printk_safe_seq_buf buffer", FAULT_ON_ERROR);
> +
> + if (len > 0) {
> + int i, n;
> + char *p;
> + fprintf(fp, "[%s] CPU: %d BUFFER: %lx LEN: %d\n", buf_name, cpu, buffer_addr, len);
> + n = (len <= buffer_size) ? len : buffer_size;
> + for (i = 0, p = buffer; i < n; i++, p++) {
> + if (*p == 0x1) { //SOH
> + i++; p++;
> + continue;
> + } else {
> + fputc(ascii(*p) ? *p : '.', fp);
> + }
> + }
> + fputc('\n', fp);
> + }
> + }
> + FREEBUF(buffer);
> +}
> +
> +static void
> +dump_printk_safe_seq_buf(void)
> +{
> + 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_buffer, "printk_safe_seq_buf", "buffer");
> + MEMBER_SIZE_INIT(printk_safe_seq_buf_buffer, "printk_safe_seq_buf", "buffer");
> + }
> +
> + __dump_printk_safe_seq_buf("nmi_print_seq");
> + __dump_printk_safe_seq_buf("safe_print_seq");
> +}
> +
> /*
> * Reads a string value from the VMCOREINFO data stored in (live) memory.
> *
> --
> 2.29.2
2 years, 10 months