[PATCH v2] Fix dis -lr xxx+0x1 not showing target address instruction
by neilfsun
When using "dis -lr xxx+0x1", it is not correctly shown, for example:
crash> dis -lr rb_next+0x1
/kernel/lib/rbtree.c: 445
0xffffffff8133ff60 <rb_next>: push %rbp
However, dis -lr rb+next+0x4 is correctly shown,
crash> dis -lr rb_next+0x4
/kernel/lib/rbtree.c: 445
0xffffffff8133ff60 <rb_next>: push %rbp
/kernel/lib/rbtree.c: 448
0xffffffff8133ff61 <rb_next+0x1>: mov (%rdi),%rdx
/kernel/lib/rbtree.c: 445
0xffffffff8133ff64 <rb_next+0x4>: mov %rsp,%rbp
The reverse mode only disassembled (target - function_start) bytes, which
was insufficient to reach the target instruction.
Signed-off-by: neilfsun <neilfsun(a)tencent.com>
Signed-off-by: Feng Sun <loyou85(a)gmail.com>
---
kernel.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel.c b/kernel.c
index bb148d0..72d7559 100644
--- a/kernel.c
+++ b/kernel.c
@@ -2120,7 +2120,7 @@ cmd_dis(void)
if (reverse)
sprintf(buf5, "x/%ldi 0x%lx",
- (target - req->addr) ? target - req->addr : 1,
+ req->flags & GNU_FUNCTION_ONLY ? 1: req->addr2 - req->addr,
req->addr);
else
sprintf(buf5, "x/%ldi 0x%lx",
--
2.52.0
1 month, 3 weeks
[PATCH] memory: Handle crash failure in linux-next caused by struct kmem_cache changes
by Mikhail Zaslonko
Since kernel commit cf338283652f ("slab: remove struct kmem_cache_cpu")
in linux-next we have no more 'cpu_slab' member in struct kmem_cache.
Pick 'cpu_sheaves' as an alternative kmem_cache member for kernel-next to
identify the SLUB case.
Without the patch, crash fails to start on kernel-next with the error
message:
crash: invalid structure member offset: kmem_cache_s_num
FILE: memory.c LINE: 9988 FUNCTION: kmem_cache_init()
This fix allows the crash to start with no errors. But kmap -s is no
longer working for kernel-next since kmem_cache_cpu array is completely
missing.
Signed-off-by: Mikhail Zaslonko <zaslonko(a)linux.ibm.com>
---
memory.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/memory.c b/memory.c
index cbc8d2f..3373fdb 100644
--- a/memory.c
+++ b/memory.c
@@ -672,6 +672,7 @@ vm_init(void)
} else if (!VALID_STRUCT(kmem_slab_s) &&
!VALID_STRUCT(slab_s) &&
!MEMBER_EXISTS("kmem_cache", "cpu_slab") &&
+ !MEMBER_EXISTS("kmem_cache", "cpu_sheaves") &&
(VALID_STRUCT(slab) || (vt->flags & SLAB_OVERLOAD_PAGE))) {
vt->flags |= PERCPU_KMALLOC_V2;
@@ -816,7 +817,7 @@ vm_init(void)
if (INVALID_MEMBER(page_first_page))
ANON_MEMBER_OFFSET_INIT(page_first_page, "page", "first_page");
- } else if (MEMBER_EXISTS("kmem_cache", "cpu_slab") &&
+ } else if ((MEMBER_EXISTS("kmem_cache", "cpu_slab") || MEMBER_EXISTS("kmem_cache", "cpu_sheaves")) &&
STRUCT_EXISTS("kmem_cache_node")) {
vt->flags |= KMALLOC_SLUB;
--
2.52.0
1 month, 3 weeks
[PATCH] Fix dis -lr xxx+0x1 not showing target address instruction
by neilfsun
When using "dis -lr xxx+0x1", it is not correctly shown, for example:
crash> dis -lr rb_next+0x1
/kernel/lib/rbtree.c: 445
0xffffffff8133ff60 <rb_next>: push %rbp
However, dis -lr rb+next+0x4 is correctly shown,
crash> dis -lr rb_next+0x4
/kernel/lib/rbtree.c: 445
0xffffffff8133ff60 <rb_next>: push %rbp
/kernel/lib/rbtree.c: 448
0xffffffff8133ff61 <rb_next+0x1>: mov (%rdi),%rdx
/kernel/lib/rbtree.c: 445
0xffffffff8133ff64 <rb_next+0x4>: mov %rsp,%rbp
The reverse mode only disassembled (target - function_start) bytes, which
was insufficient to reach the target instruction.
Signed-off-by: neilfsun <neilfsun(a)tencent.com>
Signed-off-by: Feng Sun <loyou85(a)gmail.com>
---
kernel.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel.c b/kernel.c
index bb148d0..93ea7a6 100644
--- a/kernel.c
+++ b/kernel.c
@@ -2120,7 +2120,7 @@ cmd_dis(void)
if (reverse)
sprintf(buf5, "x/%ldi 0x%lx",
- (target - req->addr) ? target - req->addr : 1,
+ req->addr2 - req->addr,
req->addr);
else
sprintf(buf5, "x/%ldi 0x%lx",
--
2.50.1
1 month, 3 weeks
[PATCH v2 0/4] xarray: add large folio support
by Huang Shijie
The linux kernel supports the large folio for page cache by default.
But the current CRASH does not support the large folio.
So we may meet the errors when we detected the large folio sometimes,
such as in the email:
https://www.spinics.net/linux/fedora/redhat-crash-utility/msg11238.html
------------------------------
files: page_to_nid: invalid page: 0
files: page_to_nid: invalid page: 0
files: page_to_nid: invalid page: 0
files: page_to_nid: invalid page: 10
files: page_to_nid: invalid page: 10
files: page_to_nid: invalid page: 10
files: page_to_nid: invalid page: 20
files: page_to_nid: invalid page: 20
files: page_to_nid: invalid page: 20
files: page_to_nid: invalid page: 30
files: page_to_nid: invalid page: 30
files: page_to_nid: invalid page: 30
files: page_to_nid: invalid page: 40
files: page_to_nid: invalid page: 40
files: page_to_nid: invalid page: 40
files: page_to_nid: invalid page: 50
files: page_to_nid: invalid page: 50
files: page_to_nid: invalid page: 50
files: page_to_nid: invalid page: 60
files: page_to_nid: invalid page: 60
------------------------------
The first 3 patches are used to add large folio support for CRASH.
The last patch is newly version of an old patch:
it add "files -n" command.
v1-->v2:
1.) Rebase the kernel to later 7.0-rc1(merge window)
2.) Fixed a bug in the patch 3, the latest kernel supports folios
whose page order is bigger then 5:
"xarray: add large folio support"
Huang Shijie (4):
xarray: add a new parameter for do_xarray
add folio_order function
xarray: add large folio support
add "files -n" command for an inode
bpf.c | 8 +++---
defs.h | 10 ++++++-
dev.c | 4 +--
diskdump.c | 10 +++++--
filesys.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++--------
help.c | 24 ++++++++++++++++-
ipcs.c | 4 +--
kernel.c | 4 +--
memory.c | 26 ++++++++++++++++--
symbols.c | 2 ++
task.c | 4 +--
tools.c | 16 +++++++++---
12 files changed, 157 insertions(+), 32 deletions(-)
--
2.43.0
1 month, 3 weeks
Re: [PATCH v2] sys: Display livepatch transition status in KERNEL line
by Tao Liu
Hi Fuli,
On Fri, Feb 13, 2026 at 1:15 AM Fuli Qi (Fujitsu) <qi.fuli(a)fujitsu.com> wrote:
>
> Hello Tao Liu,
>
> Thank you very much.
> I appreciate your help.
^_^
Thanks,
Tao Liu
>
> Best,
> Fuli
>
> > -----Original Message-----
> > From: Tao Liu <ltao(a)redhat.com>
> > Sent: Thursday, February 12, 2026 9:01 PM
> > To: Qi, Fuli/斉 福利 <qi.fuli(a)fujitsu.com>
> > Cc: Motomasa Suzuki <moto0123moto(a)gmail.com>;
> > devel(a)lists.crash-utility.osci.io
> > Subject: Re: [PATCH v2] sys: Display livepatch transition status in KERNEL
> > line
> >
> > [You don't often get email from ltao(a)redhat.com. Learn why this is important
> > at https://aka.ms/LearnAboutSenderIdentification ]
> >
> > applied:
> > https://github.com/crash-utility/crash/commit/24b5405eb6f67a96e8b5bbd5c
> > 8de8f22dfefd092
> >
> > On Thu, Feb 12, 2026 at 7:40 PM Tao Liu <ltao(a)redhat.com> wrote:
> > >
> > > Hi Fuli,
> > >
> > > On Thu, Feb 12, 2026 at 6:57 PM Fuli Qi (Fujitsu) <qi.fuli(a)fujitsu.com>
> > wrote:
> > > >
> > > > Hello Tao Liu,
> > > >
> > > > Thank you for the review.
> > > > Could you please kindly proceed with merging this patch?
> > >
> > > Sure, I will merge it today, sorry for the delay.
> > >
> > > Thanks,
> > > Tao Liu
> > > >
> > > > Best,
> > > > Fuli
> > > >
> > > > > -----Original Message-----
> > > > > From: Tao Liu <ltao(a)redhat.com>
> > > > > Sent: Tuesday, December 30, 2025 1:32 PM
> > > > > To: Motomasa Suzuki <moto0123moto(a)gmail.com>
> > > > > Cc: devel(a)lists.crash-utility.osci.io; Qi, Fuli/斉 福利
> > > > > <qi.fuli(a)fujitsu.com>
> > > > > Subject: Re: [PATCH v2] sys: Display livepatch transition status
> > > > > in KERNEL line
> > > > >
> > > > > [You don't often get email from ltao(a)redhat.com. Learn why this is
> > > > > important at https://aka.ms/LearnAboutSenderIdentification ]
> > > > >
> > > > > On Tue, Dec 23, 2025 at 6:51 PM Motomasa Suzuki
> > > > > <moto0123moto(a)gmail.com> wrote:
> > > > > >
> > > > > > This commit enhances the 'sys' command to show if a kernel
> > > > > > livepatch is currently in a transition phase, directly within the KERNEL
> > output line.
> > > > > >
> > > > > > Currently, diagnosing system state during or immediately after
> > > > > > livepatch operations can be ambiguous. While 'livepatch' is
> > > > > > indicated by '[LIVEPATCH]', there's no direct indicator within
> > > > > > 'crash' itself to show if a livepatch is actively applying,
> > > > > > reverting, or in some other transient state. This lack of
> > > > > > immediate visibility can complicate crash analysis, as the
> > > > > > system might be in an inconsistent state due to an ongoing patch
> > application/reversion.
> > > > > >
> > > > > > This change introduces a new '[TRANSITION]' flag which appears
> > > > > > next to '[LIVEPATCH]' and '[TAINTED]' in the 'sys' command
> > > > > > output. This flag is set if the livepatch subsystem indicates an
> > > > > > in-progress transition (e.g., as exposed via
> > '/sys/kernel/livepatch/<patch_name>/transition').
> > > > > >
> > > > > > Example 'sys' output with this change:
> > > > > > KERNEL: /usr/lib/debug/lib/modules/<version_name>/vmlinux
> > > > > > [LIVEPATCH] [TRANSITION] [TAINTED]
> > > > > >
> > > > > > This enhancement provides critical, at-a-glance information for
> > > > > > developers and administrators, allowing them to quickly
> > > > > > ascertain if ongoing livepatch activity might be influencing a
> > > > > > system's behavior during crash investigations. It directly
> > > > > > leverages existing kernel livepatch status infrastructure to
> > > > > > enrich the crash utility's diagnostic capabilities.
> > > > > >
> > > > > >
> > > > > > Changes v1 -> v2:
> > > > > > - Reworked klp_patches list traversal to use the crash utility’s
> > > > > > do_list() helper instead of manual list handling.
> > > > >
> > > > > The v2 LGTM, so ack.
> > > > >
> > > > > Thanks,
> > > > > Tao Liu
> > > > > >
> > > > > > Signed-off-by: Motomasa Suzuki <moto0123moto(a)gmail.com>
> > > > > > ---
> > > > > > defs.h | 1 +
> > > > > > kernel.c | 75
> > > > > >
> > > > >
> > ++++++++++++++++++++++++++++++++++++++++++++++++
> > +++
> > > > > +++--
> > > > > > 2 files changed, 74 insertions(+), 2 deletions(-)
> > > > > >
> > > > > > diff --git a/defs.h b/defs.h
> > > > > > index ceed3a9..cfdfa08 100644
> > > > > > --- a/defs.h
> > > > > > +++ b/defs.h
> > > > > > @@ -2289,6 +2289,7 @@ struct offset_table { /*
> > stash of
> > > > > commonly-used offsets */
> > > > > > long bpf_ringbuf_consumer_pos;
> > > > > > long bpf_ringbuf_nr_pages;
> > > > > > long hrtimer_clock_base_index;
> > > > > > + long klp_patch_list;
> > > > > > };
> > > > > >
> > > > > > struct size_table { /* stash of commonly-used sizes */
> > > > > > diff --git a/kernel.c b/kernel.c index bb148d0..ccc4b3d 100644
> > > > > > --- a/kernel.c
> > > > > > +++ b/kernel.c
> > > > > > @@ -464,6 +464,11 @@ kernel_init()
> > > > > > "list_head.next offset: %ld: list command may
> > fail\n",
> > > > > > OFFSET(list_head_next));
> > > > > >
> > > > > > + if (STRUCT_EXISTS("klp_patch")) {
> > > > > > + if (MEMBER_EXISTS("klp_patch", "list"))
> > > > > > + MEMBER_OFFSET_INIT(klp_patch_list,
> > > > > > + "klp_patch",
> > > > > "list");
> > > > > > + }
> > > > > > +
> > > > > > MEMBER_OFFSET_INIT(hlist_node_next, "hlist_node",
> > "next");
> > > > > > MEMBER_OFFSET_INIT(hlist_node_pprev, "hlist_node",
> > "pprev");
> > > > > > STRUCT_SIZE_INIT(hlist_head, "hlist_head"); @@ -5689,6
> > > > > > +5694,70 @@ is_livepatch(void)
> > > > > > return FALSE;
> > > > > > }
> > > > > >
> > > > > > +struct klp_transition_ctx {
> > > > > > + ulong transition_patch;
> > > > > > + int found;
> > > > > > +};
> > > > > > +
> > > > > > +static int
> > > > > > +klp_transition_match(void *entry, void *data) {
> > > > > > + struct klp_transition_ctx *ctx = data;
> > > > > > +
> > > > > > + if ((ulong)entry == ctx->transition_patch) {
> > > > > > + ctx->found = TRUE;
> > > > > > + return TRUE;
> > > > > > + }
> > > > > > +
> > > > > > + return FALSE;
> > > > > > +}
> > > > > > +
> > > > > > +static int
> > > > > > +is_livepatch_transition(void)
> > > > > > +{
> > > > > > + struct kernel_list_head head;
> > > > > > + struct list_data ld;
> > > > > > + struct klp_transition_ctx ctx;
> > > > > > + ulong transition_patch;
> > > > > > + ulong list_addr;
> > > > > > + int ret;
> > > > > > +
> > > > > > + if (!try_get_symbol_data("klp_transition_patch",
> > > > > > + sizeof(ulong), &transition_patch) || !transition_patch)
> > > > > > + return FALSE;
> > > > > > +
> > > > > > + if (!STRUCT_EXISTS("klp_patch")
> > > > > || !VALID_MEMBER(klp_patch_list) ||
> > > > > > + !kernel_symbol_exists("klp_patches"))
> > > > > > + return TRUE;
> > > > > > +
> > > > > > + list_addr = symbol_value("klp_patches");
> > > > > > + if (!readmem(list_addr, KVADDR, &head, sizeof(head),
> > "klp_patches",
> > > > > > + RETURN_ON_ERROR | QUIET))
> > > > > > + return TRUE;
> > > > > > +
> > > > > > + if (!head.next || head.next == (void *)list_addr)
> > > > > > + return TRUE;
> > > > > > +
> > > > > > + BZERO(&ctx, sizeof(ctx));
> > > > > > + ctx.transition_patch = transition_patch;
> > > > > > +
> > > > > > + BZERO(&ld, sizeof(ld));
> > > > > > + ld.flags =
> > > > > LIST_CALLBACK|CALLBACK_RETURN|RETURN_ON_LIST_ERROR|
> > > > > > + RETURN_ON_DUPLICATE|LIST_ALLOCATE;
> > > > > > + ld.start = (ulong)head.next;
> > > > > > + ld.end = list_addr;
> > > > > > + ld.member_offset = OFFSET(list_head_next);
> > > > > > + ld.list_head_offset = OFFSET(klp_patch_list);
> > > > > > + ld.callback_func = klp_transition_match;
> > > > > > + ld.callback_data = &ctx;
> > > > > > +
> > > > > > + ret = do_list(&ld);
> > > > > > + if (ret < 0)
> > > > > > + return FALSE;
> > > > > > +
> > > > > > + return ctx.found;
> > > > > > +}
> > > > > > +
> > > > > > /*
> > > > > > * Display system stats at init-time or for the sys command.
> > > > > > */
> > > > > > @@ -5732,17 +5801,19 @@ display_sys_stats(void)
> > > > > > }
> > > > > > } else {
> > > > > > if (pc->system_map) {
> > > > > > - fprintf(fp, " SYSTEM MAP: %s%s%s\n",
> > > > > pc->system_map,
> > > > > > + fprintf(fp, " SYSTEM
> > MAP: %s%s%s%s\n",
> > > > > > + pc->system_map,
> > > > > > is_livepatch() ? " [LIVEPATCH]"
> > > > > > : "",
> > > > > > + is_livepatch_transition() ? "
> > > > > > + [TRANSITION]" : "",
> > > > > > is_kernel_tainted() ? "
> > [TAINTED]" : "");
> > > > > > fprintf(fp, "DEBUG KERNEL: %s %s\n",
> > > > > > pc->namelist_orig ?
> > > > > > pc->namelist_orig :
> > > > > > pc->namelist,
> > > > > >
> > > > > debug_kernel_version(pc->namelist));
> > > > > > } else
> > > > > > - fprintf(fp, " KERNEL: %s%s%s\n",
> > > > > pc->namelist_orig ?
> > > > > > + fprintf(fp, " KERNEL: %s%s%s%s\n",
> > > > > pc->namelist_orig ?
> > > > > > pc->namelist_orig :
> > pc->namelist,
> > > > > > is_livepatch() ? " [LIVEPATCH]"
> > > > > > : "",
> > > > > > + is_livepatch_transition() ? "
> > > > > > + [TRANSITION]" : "",
> > > > > > is_kernel_tainted() ? "
> > [TAINTED]" : "");
> > > > > > }
> > > > > >
> > > > > > --
> > > > > > 2.47.3
> > > > > >
> > > >
>
1 month, 3 weeks
Re: [PATCH] arm64: Fix broken/incomplete gdb backtrace and unify output format
by lijiang
Hi, Pengfei
I did the test with your patch, and got an incorrect back trace, Can you
also help double check?
crash> gdb bt
#0 0xffffc8c40b0d9b14 in crash_setup_regs
(newregs=newregs@entry=0xffff80008862b638,
oldregs=oldregs@entry=0x0) at ./arch/arm64/include/asm/kexec.h:45
#1 0xffffc8c40b0d9dc4 in __crash_kexec (regs=regs@entry=0x0) at
kernel/crash_core.c:119
#2 0xffffc8c40aed6a44 in vpanic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq
triggered crash\n", args=<error reading variable: Cannot access memory at
address 0x0>) at kernel/panic.c:369
#3 0xffffc8c40aed6cd0 in panic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq
triggered crash\n") at kernel/panic.c:484
#4 0xffffc8c40b82a594 in sysrq_handle_crash (key=<optimized out>) at
drivers/tty/sysrq.c:154
#5 0xffffc8c40b82aee0 in __handle_sysrq (key=99 'c', check_mask=false)
at drivers/tty/sysrq.c:613
#6 0xffffc8c40b82b6b0 in write_sysrq_trigger (file=<optimized out>,
buf=<optimized out>, count=2, ppos=<optimized out>) at
drivers/tty/sysrq.c:1183
#7 0xffffc8c40b46bcec in pde_write (pde=0xffff0000c7fa6a80,
file=<optimized out>, buf=<optimized out>, count=<optimized out>,
ppos=<optimized out>) at fs/proc/inode.c:330
#8 proc_reg_write (file=<optimized out>,
buf=<optimized out>, count=<optimized out>, ppos=<optimized out>) at
fs/proc/inode.c:342
#9 0xffffc8c40b3ad52c in vfs_write (file=file@entry=0xffff0000c86aff00,
buf=buf@entry=0xaaab1a0c37f0 <error: Cannot access memory at address
0xaaab1a0c37f0>, count=count@entry=2, pos=pos@entry=0xffff80008862ba20) at
fs/read_write.c:681
#10 0xffffc8c40b3ad9a4 in ksys_write (fd=<optimized out>,
buf=0xaaab1a0c37f0 <error: Cannot access memory at address 0xaaab1a0c37f0>,
count=2) at fs/read_write.c:736
#11 0xffffc8c40b3ada6c in __do_sys_write (fd=<optimized out>,
buf=<optimized out>, count=<optimized out>) at fs/read_write.c:748
#12 __se_sys_write (fd=<optimized out>,
buf=<optimized out>, count=<optimized out>) at fs/read_write.c:745
#13 __arm64_sys_write (regs=<optimized out>) at
fs/read_write.c:745
#14 0xffffc8c40af0cc7c in __invoke_syscall (regs=0xffff80008862beb0,
syscall_fn=<optimized out>) at arch/arm64/kernel/syscall.c:35
#15 invoke_syscall (regs=regs@entry=0xffff80008862beb0,
scno=<optimized out>, sc_nr=sc_nr@entry=463, syscall_table=<optimized out>)
at arch/arm64/kernel/syscall.c:49
#16 0xffffc8c40af0cd88 in el0_svc_common (sc_nr=463,
syscall_table=<optimized out>, regs=0xffff80008862beb0, scno=<optimized
out>) at arch/arm64/kernel/syscall.c:132
#17 do_el0_svc (regs=regs@entry=0xffff80008862beb0)
at arch/arm64/kernel/syscall.c:151
#18 0xffffc8c40beb9e2c in el0_svc (regs=0xffff80008862beb0) at
arch/arm64/kernel/entry-common.c:879
#19 0xffffc8c40beba2b0 in el0t_64_sync_handler (regs=<optimized out>) at
arch/arm64/kernel/entry-common.c:898
#20 0xffffc8c40aed1684 in el0t_64_sync () at arch/arm64/kernel/entry.S:596
#21 machine_kexec (kimage=<unavailable>) at
arch/arm64/kernel/machine_kexec.c:194
#22 0xffffc8c40b0d9dd8 in __crash_kexec (regs=regs@entry=0x0) at
kernel/crash_core.c:122
#23 0xffffc8c40aed6a44 in vpanic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq
triggered crash\n", args=<error reading variable: Cannot access memory at
address 0x0>) at kernel/panic.c:369
#24 0xffffc8c40aed6cd0 in panic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq
triggered crash\n") at kernel/panic.c:484
#25 0xffffc8c40b82a594 in sysrq_handle_crash (key=<optimized out>) at
drivers/tty/sysrq.c:154
#26 0xffffc8c40b82aee0 in __handle_sysrq (key=99 'c',
check_mask=<unavailable>) at drivers/tty/sysrq.c:613
#27 0xffffc8c40b82b6b0 in write_sysrq_trigger (file=<optimized out>,
buf=<optimized out>, count=2, ppos=<optimized out>) at
drivers/tty/sysrq.c:1183
#28 0xffffc8c40b46bcec in pde_write (pde=0xffff0000c7fa6a80,
file=<optimized out>, buf=<optimized out>, count=<optimized out>,
ppos=<optimized out>) at fs/proc/inode.c:330
#29 proc_reg_write (file=<optimized out>,
buf=<optimized out>, count=<optimized out>, ppos=<optimized out>) at
fs/proc/inode.c:342
#30 0xffffc8c40b3ad52c in vfs_write (file=file@entry=0xffff0000c86aff00,
buf=buf@entry=0xaaab1a0c37f0 <error: Cannot access memory at address
0xaaab1a0c37f0>, count=count@entry=2, pos=pos@entry=0xffff80008862ba20) at
fs/read_write.c:681
#31 0xffffc8c40b3ad9a4 in ksys_write (fd=<optimized out>,
buf=0xaaab1a0c37f0 <error: Cannot access memory at address 0xaaab1a0c37f0>,
count=2) at fs/read_write.c:736
#32 0xffffc8c40b3ada6c in __do_sys_write (fd=<optimized out>,
buf=<optimized out>, count=<optimized out>) at fs/read_write.c:748
#33 __se_sys_write (fd=<optimized out>,
buf=<optimized out>, count=<optimized out>) at fs/read_write.c:745
#34 __arm64_sys_write (regs=<optimized out>) at
fs/read_write.c:745
#35 0xffffc8c40af0cc7c in __invoke_syscall (regs=0xffff80008862beb0,
syscall_fn=<optimized out>) at arch/arm64/kernel/syscall.c:35
#36 invoke_syscall (regs=regs@entry=0xffff80008862beb0,
scno=<optimized out>, sc_nr=sc_nr@entry=463, syscall_table=<optimized out>)
at arch/arm64/kernel/syscall.c:49
#37 0xffffc8c40af0cd88 in el0_svc_common (sc_nr=463,
syscall_table=<optimized out>, regs=0xffff80008862beb0, scno=<optimized
out>) at arch/arm64/kernel/syscall.c:132
#38 do_el0_svc (regs=regs@entry=0xffff80008862beb0)
at arch/arm64/kernel/syscall.c:151
#39 0xffffc8c40beb9e2c in el0_svc (regs=0xffff80008862beb0) at
arch/arm64/kernel/entry-common.c:879
#40 0xffffc8c40beba2b0 in el0t_64_sync_handler (regs=<optimized out>) at
arch/arm64/kernel/entry-common.c:898
#41 0xffffc8c40aed1684 in el0t_64_sync () at arch/arm64/kernel/entry.S:596
I can get the correct back trace without the patch:
crash> gdb bt
#0 0xffffc8c40b0d9b14 in crash_setup_regs
(newregs=newregs@entry=0xffff80008862b638,
oldregs=oldregs@entry=0x0) at ./arch/arm64/include/asm/kexec.h:45
#1 0xffffc8c40b0d9dc4 in __crash_kexec (regs=regs@entry=0x0) at
kernel/crash_core.c:119
#2 0xffffc8c40aed6a44 in vpanic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq
triggered crash\n", args=<error reading variable: Cannot access memory at
address 0x0>) at kernel/panic.c:369
#3 0xffffc8c40aed6cd0 in panic (fmt=fmt@entry=0xffffc8c40c527558 "sysrq
triggered crash\n") at kernel/panic.c:484
#4 0xffffc8c40b82a594 in sysrq_handle_crash (key=<optimized out>) at
drivers/tty/sysrq.c:154
#5 0xffffc8c40b82aee0 in __handle_sysrq (key=99 'c', check_mask=false) at
drivers/tty/sysrq.c:613
#6 0xffffc8c40b82b6b0 in write_sysrq_trigger (file=<optimized out>,
buf=<optimized out>, count=2, ppos=<optimized out>) at
drivers/tty/sysrq.c:1183
#7 0xffffc8c40b46bcec in pde_write (pde=0xffff0000c7fa6a80,
file=<optimized out>, buf=<optimized out>, count=<optimized out>,
ppos=<optimized out>) at fs/proc/inode.c:330
#8 proc_reg_write (file=<optimized out>, buf=<optimized out>,
count=<optimized out>, ppos=<optimized out>) at fs/proc/inode.c:342
#9 0xffffc8c40b3ad52c in vfs_write (file=file@entry=0xffff0000c86aff00,
buf=buf@entry=0xaaab1a0c37f0 <error: Cannot access memory at address
0xaaab1a0c37f0>, count=count@entry=2, pos=pos@entry=0xffff80008862ba20) at
fs/read_write.c:681
#10 0xffffc8c40b3ad9a4 in ksys_write (fd=<optimized out>,
buf=0xaaab1a0c37f0 <error: Cannot access memory at address 0xaaab1a0c37f0>,
count=2) at fs/read_write.c:736
#11 0xffffc8c40b3ada6c in __do_sys_write (fd=<optimized out>,
buf=<optimized out>, count=<optimized out>) at fs/read_write.c:748
#12 __se_sys_write (fd=<optimized out>, buf=<optimized out>,
count=<optimized out>) at fs/read_write.c:745
#13 __arm64_sys_write (regs=<optimized out>) at fs/read_write.c:745
#14 0xffffc8c40af0cc7c in __invoke_syscall (regs=0xffff80008862beb0,
syscall_fn=<optimized out>) at arch/arm64/kernel/syscall.c:35
#15 invoke_syscall (regs=regs@entry=0xffff80008862beb0, scno=<optimized
out>, sc_nr=sc_nr@entry=463, syscall_table=<optimized out>) at
arch/arm64/kernel/syscall.c:49
#16 0xffffc8c40af0cd88 in el0_svc_common (sc_nr=463,
syscall_table=<optimized out>, regs=0xffff80008862beb0, scno=<optimized
out>) at arch/arm64/kernel/syscall.c:132
#17 do_el0_svc (regs=regs@entry=0xffff80008862beb0) at
arch/arm64/kernel/syscall.c:151
#18 0xffffc8c40beb9e2c in el0_svc (regs=0xffff80008862beb0) at
arch/arm64/kernel/entry-common.c:879
#19 0xffffc8c40beba2b0 in el0t_64_sync_handler (regs=<optimized out>) at
arch/arm64/kernel/entry-common.c:898
#20 0xffffc8c40aed1684 in el0t_64_sync () at arch/arm64/kernel/entry.S:596
Anyway, I haven't checked the patch carefully, just tried to test it and
found this error.
In addition, I would suggest splitting this patch into smaller patches, and
each patch should only do one thing(keep its functionality independent),
which will help us to review it easily.
Thanks
Lianbo
On Fri, Jan 30, 2026 at 5:21 PM <devel-request(a)lists.crash-utility.osci.io>
wrote:
> Date: Mon, 26 Jan 2026 11:43:42 -0000
> From: lipengfei28(a)xiaomi.com
> Subject: [Crash-utility] [PATCH] arm64: Fix broken/incomplete gdb
> backtrace and unify output format
> To: devel(a)lists.crash-utility.osci.io
> Message-ID: <20260126114342.13119.56270(a)lists.crash-utility.osci.io>
> Content-Type: text/plain; charset="utf-8"
>
> >From 4d832a33ebd80bd109cc5a47f98c6b35fdcbd956 Mon Sep 17 00:00:00 2001
> From: lipengfei28 <lipengfei28(a)xiaomi.com>
> Date: Fri, 23 Jan 2026 16:24:07 +0800
> Subject: [PATCH] arm64: Fix broken/incomplete gdb backtrace and unify
> output
> format
>
> This patch fixes multiple issues with 'gdb bt' on ARM64, where the
> backtrace
> would be interrupted, contain garbage threads, or display fragmented
> output.
>
> 1. Fix Out-of-Bounds Read in Exception Frame Handling:
> In `arm64_print_exception_frame`, the code previously used `memcpy` to
> copy
> `sizeof(struct arm64_pt_regs)` bytes from a `struct arm64_stackframe
> *` source.
> Since `stackframe` is significantly smaller than `pt_regs`, this
> caused an
> out-of-bounds read, populating the GDB thread registers with stack
> garbage
> (often resulting in invalid addresses like -3/0xff...fd).
> This is fixed by manually copying only the valid registers (PC, SP,
> FP, etc.)
> and properly initializing the bitmap.
>
> 2. Bridge the Gap Between IRQ and Process Stacks:
> Previously, GDB unwinding would stop at `call_on_irq_stack` because it
> could
> not automatically unwind through the assembly trampoline back to the
> process
> stack.
> Modified `arm64_switch_stack` (and the overflow variant) to "peek" one
> frame
> ahead (reading the saved FP/PC of the caller) before registering the
> new
> GDB substack. This effectively bridges the discontinuity, allowing GDB
> to
> show frames like `do_interrupt_handler` that were previously missing.
>
> 3. Unify and Format GDB Output:
> Modified `gdb_interface.c` to:
> - Strip "Thread <id>" headers to present a continuous backtrace
> similar to
> the native `crash bt`.
> - Renumber stack frames sequentially (e.g., #0 to #30) instead of
> resetting
> at each stack switch.
> - Add indentation/alignment for frames where GDB omits the address
> (e.g.,
> inline functions) to improve readability.
>
> 4. Prevent Invalid Thread Creation:
> Added checks to ensure a GDB substack is only created if the Program
> Counter
> (PC) is non-zero, preventing the display of "corrupt" or empty threads.
>
> Tested on: Android 6.x ARM64
>
> Signed-off-by: lipengfei28 <lipengfei28(a)xiaomi.com>
> ---
> arm64.c | 117 +++++++++++++++++++++++++++++++++++++------
> gdb_interface.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 229 insertions(+), 18 deletions(-)
>
> diff --git a/arm64.c b/arm64.c
> index c125655..f842739 100644
> --- a/arm64.c
> +++ b/arm64.c
> @@ -3026,6 +3026,9 @@ static char *arm64_exception_functions[] = {
> "do_el0_irq_bp_hardening",
> "do_sp_pc_abort",
> "handle_bad_stack",
> + "el1h_64_sync",
> + "el1h_64_irq",
> + "el1h_64_error",
> NULL
> };
>
> @@ -3123,6 +3126,11 @@ arm64_print_stackframe_entry(struct bt_info *bt,
> int level, struct arm64_stackfr
>
> fprintf(ofp, "\n");
>
> + if (STREQ(name, "el1h_64_irq") || STREQ(name, "el1h_64_sync"))
> + if (arm64_is_kernel_exception_frame(bt, frame->sp)) {
> + arm64_print_exception_frame(bt, frame->sp,
> KERNEL_MODE, ofp);
> + }
> +
> if (bt->flags & BT_LINE_NUMBERS) {
> get_line_number(branch_pc, buf, FALSE);
> if (strlen(buf))
> @@ -3775,11 +3783,12 @@ arm64_back_trace_cmd(struct bt_info *bt)
> REG_SEQ(arm64_pt_regs, pc));
> SET_BIT(extra_stacks_regs[extra_stacks_idx]->bitmap,
> REG_SEQ(arm64_pt_regs, sp));
> - if (!bt->machdep ||
> + if (extra_stacks_regs[extra_stacks_idx]->ur.pc &&
> + (!bt->machdep ||
> (extra_stacks_regs[extra_stacks_idx]->ur.sp !=
> ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.sp &&
> extra_stacks_regs[extra_stacks_idx]->ur.pc !=
> - ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.pc)) {
> + ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.pc))) {
> gdb_add_substack (extra_stacks_idx++);
> }
> }
> @@ -3925,11 +3934,12 @@ arm64_back_trace_cmd_v2(struct bt_info *bt)
> REG_SEQ(arm64_pt_regs, pc));
> SET_BIT(extra_stacks_regs[extra_stacks_idx]->bitmap,
> REG_SEQ(arm64_pt_regs, sp));
> - if (!bt->machdep ||
> + if (extra_stacks_regs[extra_stacks_idx]->ur.pc &&
> + (!bt->machdep ||
> (extra_stacks_regs[extra_stacks_idx]->ur.sp !=
> ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.sp &&
> extra_stacks_regs[extra_stacks_idx]->ur.pc !=
> - ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.pc)) {
> + ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.pc))) {
> gdb_add_substack (extra_stacks_idx++);
> }
> }
> @@ -4263,8 +4273,40 @@ arm64_switch_stack(struct bt_info *bt, struct
> arm64_stackframe *frame, FILE *ofp
> if (frame->fp == 0)
> return USER_MODE;
>
> - if (!(machdep->flags & UNW_4_14))
> + if (!(machdep->flags & UNW_4_14)) {
> arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE,
> ofp);
> + } else {
> + if (!extra_stacks_regs[extra_stacks_idx]) {
> + extra_stacks_regs[extra_stacks_idx] = (struct
> user_regs_bitmap_struct *)
> + malloc(sizeof(struct
> user_regs_bitmap_struct));
> + }
> + memset(extra_stacks_regs[extra_stacks_idx], 0,
> sizeof(struct user_regs_bitmap_struct));
> + struct user_regs_bitmap_struct *ur_ptr =
> extra_stacks_regs[extra_stacks_idx];
> +
> + ulong next_fp = GET_STACK_ULONG(frame->fp);
> + ulong next_pc = GET_STACK_ULONG(frame->fp + 8);
> + ulong next_sp = frame->fp + 16;
> +
> + if (is_kernel_text(next_pc |
> ms->CONFIG_ARM64_KERNELPACMASK))
> + next_pc |= ms->CONFIG_ARM64_KERNELPACMASK;
> +
> + ur_ptr->ur.pc = next_pc;
> + ur_ptr->ur.sp = next_sp;
> + ur_ptr->ur.regs[29] = next_fp;
> +
> + SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, pc));
> + SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, sp));
> + SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, regs[0]) +
> 29);
> +
> + if (ur_ptr->ur.pc &&
> + (!bt->machdep ||
> + (ur_ptr->ur.sp !=
> + ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.sp &&
> + ur_ptr->ur.pc !=
> + ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.pc))) {
> + gdb_add_substack (extra_stacks_idx++);
> + }
> + }
>
> return KERNEL_MODE;
> }
> @@ -4300,8 +4342,40 @@ arm64_switch_stack_from_overflow(struct bt_info
> *bt, struct arm64_stackframe *fr
> if (frame->fp == 0)
> return USER_MODE;
>
> - if (!(machdep->flags & UNW_4_14))
> + if (!(machdep->flags & UNW_4_14)) {
> arm64_print_exception_frame(bt, frame->sp, KERNEL_MODE,
> ofp);
> + } else {
> + if (!extra_stacks_regs[extra_stacks_idx]) {
> + extra_stacks_regs[extra_stacks_idx] = (struct
> user_regs_bitmap_struct *)
> + malloc(sizeof(struct
> user_regs_bitmap_struct));
> + }
> + memset(extra_stacks_regs[extra_stacks_idx], 0,
> sizeof(struct user_regs_bitmap_struct));
> + struct user_regs_bitmap_struct *ur_ptr =
> extra_stacks_regs[extra_stacks_idx];
> +
> + ulong next_fp = GET_STACK_ULONG(frame->fp);
> + ulong next_pc = GET_STACK_ULONG(frame->fp + 8);
> + ulong next_sp = frame->fp + 16;
> +
> + if (is_kernel_text(next_pc |
> ms->CONFIG_ARM64_KERNELPACMASK))
> + next_pc |= ms->CONFIG_ARM64_KERNELPACMASK;
> +
> + ur_ptr->ur.pc = next_pc;
> + ur_ptr->ur.sp = next_sp;
> + ur_ptr->ur.regs[29] = next_fp;
> +
> + SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, pc));
> + SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, sp));
> + SET_BIT(ur_ptr->bitmap, REG_SEQ(arm64_pt_regs, regs[0]) +
> 29);
> +
> + if (ur_ptr->ur.pc &&
> + (!bt->machdep ||
> + (ur_ptr->ur.sp !=
> + ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.sp &&
> + ur_ptr->ur.pc !=
> + ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.pc))) {
> + gdb_add_substack (extra_stacks_idx++);
> + }
> + }
>
> return KERNEL_MODE;
> }
> @@ -4556,16 +4630,27 @@ arm64_print_exception_frame(struct bt_info *bt,
> ulong pt_regs, int mode, FILE *o
> }
> memset(extra_stacks_regs[extra_stacks_idx], 0,
> sizeof(struct user_regs_bitmap_struct));
> - memcpy(&extra_stacks_regs[extra_stacks_idx]->ur,
> regs,
> - sizeof(struct arm64_pt_regs));
> - for (int i = 0; i < sizeof(struct
> arm64_pt_regs)/sizeof(long); i++)
> -
> SET_BIT(extra_stacks_regs[extra_stacks_idx]->bitmap, i);
> - if (!bt->machdep ||
> - (extra_stacks_regs[extra_stacks_idx]->ur.sp !=
> - ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.sp &&
> - extra_stacks_regs[extra_stacks_idx]->ur.pc !=
> - ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.pc)) {
> - gdb_add_substack (extra_stacks_idx++);
> + {
> + struct user_regs_bitmap_struct *ur_ptr =
> extra_stacks_regs[extra_stacks_idx];
> + int i;
> +
> + ur_ptr->ur.pc = regs->pc;
> + ur_ptr->ur.sp = regs->sp;
> + ur_ptr->ur.pstate = regs->pstate;
> + for (i = 0; i < 31; i++)
> + ur_ptr->ur.regs[i] = regs->regs[i];
> +
> + for (i = 0; i < 34; i++)
> + SET_BIT(ur_ptr->bitmap, i);
> +
> + if (ur_ptr->ur.pc &&
> + (!bt->machdep ||
> + (ur_ptr->ur.sp !=
> + ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.sp &&
> + ur_ptr->ur.pc !=
> + ((struct user_regs_bitmap_struct
> *)(bt->machdep))->ur.pc))) {
> + gdb_add_substack
> (extra_stacks_idx++);
> + }
> }
> }
> }
> diff --git a/gdb_interface.c b/gdb_interface.c
> index 9f76f85..d14144e 100644
> --- a/gdb_interface.c
> +++ b/gdb_interface.c
> @@ -16,6 +16,7 @@
> */
>
> #include "defs.h"
> +#include <ctype.h>
>
> #if !defined(GDB_10_2) && !defined(GDB_16_2)
> static void exit_after_gdb_info(void);
> @@ -779,22 +780,53 @@ strip_redirection(char *buf)
> /*
> * Command for passing strings directly to gdb.
> */
> +static void format_and_print_gdb_bt(FILE *input_fp);
> +
> void
> cmd_gdb(void)
> {
> char buf[BUFSIZE];
> char **argv;
> + int i;
>
> argv = STREQ(args[0], "gdb") ? &args[1] : &args[0];
>
> if (*argv == NULL)
> cmd_usage(pc->curcmd, SYNOPSIS);
>
> + if (STREQ(*argv, "bt")) {
> + FILE *tmp_fp;
> +
> + if ((tmp_fp = tmpfile()) == NULL) {
> + error(FATAL, "cannot create temporary file for GDB
> output\n");
> + }
> +
> + strcpy(buf, "thread apply all bt");
> + /* Append any arguments that were passed to 'bt' */
> + /* args[0] is "gdb", args[1] is "bt", so options start at
> index 2 */
> + for (i = 2; i < argcnt; i++) {
> + strcat(buf, " ");
> + strcat(buf, args[i]);
> + }
> +
> + if (!gdb_pass_through(buf, tmp_fp, GNU_RETURN_ON_ERROR)) {
> + fclose(tmp_fp);
> + error(INFO, "gdb request failed: %s\n", buf);
> + return;
> + }
> +
> + rewind(tmp_fp);
> + format_and_print_gdb_bt(tmp_fp);
> +
> + fclose(tmp_fp);
> + return;
> + }
> +
> if (STREQ(*argv, "set") && argv[1]) {
> /*
> * Intercept set commands in case something has to be
> done
> - * here or elsewhere.
> - */
> + * here or elsewhere.
> + */
> if (STREQ(argv[1], "gdb")) {
> cmd_set();
> return;
> @@ -821,6 +853,100 @@ cmd_gdb(void)
> }
> }
>
> +#define MAX_BT_LINES 1024
> +#define MAX_THREAD_BLOCKS 64
> +
> +/*
> + * Helper function to parse 'thread apply all bt' output, reverse the
> + * thread blocks, and print the result.
> + */
> +static void format_and_print_gdb_bt(FILE *input_fp)
> +{
> + char *lines[MAX_BT_LINES];
> + int line_count = 0;
> + int thread_starts[MAX_THREAD_BLOCKS];
> + int thread_count = 0;
> + char line_buffer[BUFSIZE];
> + int i, j;
> + int global_frame_cnt = 0;
> +
> + // Read all lines into memory
> + while (fgets(line_buffer, BUFSIZE, input_fp) && line_count <
> MAX_BT_LINES) {
> + if (strstr(line_buffer, "Thread ") == line_buffer) {
> + if (thread_count < MAX_THREAD_BLOCKS) {
> + thread_starts[thread_count++] = line_count;
> + }
> + }
> + lines[line_count] = strdup(line_buffer);
> + if (!lines[line_count]) {
> + error(FATAL, "strdup failed while reading gdb output\n");
> + }
> + line_count++;
> + }
> +
> + if (thread_count == 0) { // If no threads, just print everything as
> is.
> + for (i = 0; i < line_count; i++) {
> + fputs(lines[i], fp);
> + }
> + } else {
> + // Iterate threads in reverse order to fix the display order
> + for (i = thread_count - 1; i >= 0; i--) {
> + int start_line = thread_starts[i];
> + int end_line = (i == thread_count - 1) ? line_count :
> thread_starts[i+1];
> +
> + // Print thread frames, stripping header and renumbering
> + for (j = start_line; j < end_line; j++) {
> + char *line = lines[j];
> + // Skip "Thread " line
> + if (strncmp(line, "Thread ", 7) == 0) continue;
> + // Skip "Backtrace stopped" or similar noise if desired,
> + // but usually GDB prints "Backtrace stopped" at the very
> end.
> + // We'll keep it for info unless it's in the middle of
> our merge.
> + // Actually, duplicate frames or stops might appear.
> + // For now, simple renumbering.
> +
> + char *ptr = line;
> + while (*ptr == ' ' || *ptr == '\t') ptr++;
> +
> + if (*ptr == '#') {
> + // Frame line: #0 0x...
> + char *rest = ptr + 1;
> + while (isdigit(*rest)) rest++; // Skip old number
> +
> + // Parse content to check for address
> + char *p = rest;
> + while (*p == ' ' || *p == '\t') p++;
> +
> + int has_addr = (strncmp(p, "0x", 2) == 0);
> +
> + // Print number
> + fprintf(fp, "#%-3d", global_frame_cnt++);
> +
> + // Align if address is missing
> + if (!has_addr) {
> + // Align function name with frames that have
> addresses
> + // 64-bit: 0x... (18 chars) + " in " (4 chars) =
> 22 chars
> + // 32-bit: 0x... (10 chars) + " in " (4 chars) =
> 14 chars
> + int width = (machdep->bits == 64) ? 22 : 14;
> + for (int k = 0; k < width; k++) fputc(' ', fp);
> + }
> +
> + fputs(rest, fp);
> + } else {
> + // Other lines (e.g. variable info, code)
> + fputs(line, fp);
> + }
> + }
> + }
> + }
> +
> + // Cleanup
> + for (i = 0; i < line_count; i++) {
> + free(lines[i]);
> + }
> +}
> +
> +
> /*
> * The gdb target_xfer_memory() has a hook installed to re-route
> * all memory accesses back here; reads of 1 or 4 bytes come primarily
> --
> 2.34.1
>
1 month, 3 weeks
Re: [PATCH v2] sys: Display livepatch transition status in KERNEL line
by Tao Liu
Hi Fuli,
On Thu, Feb 12, 2026 at 6:57 PM Fuli Qi (Fujitsu) <qi.fuli(a)fujitsu.com> wrote:
>
> Hello Tao Liu,
>
> Thank you for the review.
> Could you please kindly proceed with merging this patch?
Sure, I will merge it today, sorry for the delay.
Thanks,
Tao Liu
>
> Best,
> Fuli
>
> > -----Original Message-----
> > From: Tao Liu <ltao(a)redhat.com>
> > Sent: Tuesday, December 30, 2025 1:32 PM
> > To: Motomasa Suzuki <moto0123moto(a)gmail.com>
> > Cc: devel(a)lists.crash-utility.osci.io; Qi, Fuli/斉 福利 <qi.fuli(a)fujitsu.com>
> > Subject: Re: [PATCH v2] sys: Display livepatch transition status in KERNEL line
> >
> > [You don't often get email from ltao(a)redhat.com. Learn why this is important at
> > https://aka.ms/LearnAboutSenderIdentification ]
> >
> > On Tue, Dec 23, 2025 at 6:51 PM Motomasa Suzuki
> > <moto0123moto(a)gmail.com> wrote:
> > >
> > > This commit enhances the 'sys' command to show if a kernel livepatch
> > > is currently in a transition phase, directly within the KERNEL output line.
> > >
> > > Currently, diagnosing system state during or immediately after
> > > livepatch operations can be ambiguous. While 'livepatch' is indicated
> > > by '[LIVEPATCH]', there's no direct indicator within 'crash' itself to
> > > show if a livepatch is actively applying, reverting, or in some other
> > > transient state. This lack of immediate visibility can complicate
> > > crash analysis, as the system might be in an inconsistent state due to
> > > an ongoing patch application/reversion.
> > >
> > > This change introduces a new '[TRANSITION]' flag which appears next to
> > > '[LIVEPATCH]' and '[TAINTED]' in the 'sys' command output. This flag
> > > is set if the livepatch subsystem indicates an in-progress transition
> > > (e.g., as exposed via '/sys/kernel/livepatch/<patch_name>/transition').
> > >
> > > Example 'sys' output with this change:
> > > KERNEL: /usr/lib/debug/lib/modules/<version_name>/vmlinux
> > > [LIVEPATCH] [TRANSITION] [TAINTED]
> > >
> > > This enhancement provides critical, at-a-glance information for
> > > developers and administrators, allowing them to quickly ascertain if
> > > ongoing livepatch activity might be influencing a system's behavior
> > > during crash investigations. It directly leverages existing kernel
> > > livepatch status infrastructure to enrich the crash utility's
> > > diagnostic capabilities.
> > >
> > >
> > > Changes v1 -> v2:
> > > - Reworked klp_patches list traversal to use the crash utility’s
> > > do_list() helper instead of manual list handling.
> >
> > The v2 LGTM, so ack.
> >
> > Thanks,
> > Tao Liu
> > >
> > > Signed-off-by: Motomasa Suzuki <moto0123moto(a)gmail.com>
> > > ---
> > > defs.h | 1 +
> > > kernel.c | 75
> > >
> > +++++++++++++++++++++++++++++++++++++++++++++++++++
> > +++--
> > > 2 files changed, 74 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/defs.h b/defs.h
> > > index ceed3a9..cfdfa08 100644
> > > --- a/defs.h
> > > +++ b/defs.h
> > > @@ -2289,6 +2289,7 @@ struct offset_table { /* stash of
> > commonly-used offsets */
> > > long bpf_ringbuf_consumer_pos;
> > > long bpf_ringbuf_nr_pages;
> > > long hrtimer_clock_base_index;
> > > + long klp_patch_list;
> > > };
> > >
> > > struct size_table { /* stash of commonly-used sizes */
> > > diff --git a/kernel.c b/kernel.c
> > > index bb148d0..ccc4b3d 100644
> > > --- a/kernel.c
> > > +++ b/kernel.c
> > > @@ -464,6 +464,11 @@ kernel_init()
> > > "list_head.next offset: %ld: list command may fail\n",
> > > OFFSET(list_head_next));
> > >
> > > + if (STRUCT_EXISTS("klp_patch")) {
> > > + if (MEMBER_EXISTS("klp_patch", "list"))
> > > + MEMBER_OFFSET_INIT(klp_patch_list, "klp_patch",
> > "list");
> > > + }
> > > +
> > > MEMBER_OFFSET_INIT(hlist_node_next, "hlist_node", "next");
> > > MEMBER_OFFSET_INIT(hlist_node_pprev, "hlist_node", "pprev");
> > > STRUCT_SIZE_INIT(hlist_head, "hlist_head"); @@ -5689,6
> > > +5694,70 @@ is_livepatch(void)
> > > return FALSE;
> > > }
> > >
> > > +struct klp_transition_ctx {
> > > + ulong transition_patch;
> > > + int found;
> > > +};
> > > +
> > > +static int
> > > +klp_transition_match(void *entry, void *data) {
> > > + struct klp_transition_ctx *ctx = data;
> > > +
> > > + if ((ulong)entry == ctx->transition_patch) {
> > > + ctx->found = TRUE;
> > > + return TRUE;
> > > + }
> > > +
> > > + return FALSE;
> > > +}
> > > +
> > > +static int
> > > +is_livepatch_transition(void)
> > > +{
> > > + struct kernel_list_head head;
> > > + struct list_data ld;
> > > + struct klp_transition_ctx ctx;
> > > + ulong transition_patch;
> > > + ulong list_addr;
> > > + int ret;
> > > +
> > > + if (!try_get_symbol_data("klp_transition_patch",
> > > + sizeof(ulong), &transition_patch) || !transition_patch)
> > > + return FALSE;
> > > +
> > > + if (!STRUCT_EXISTS("klp_patch")
> > || !VALID_MEMBER(klp_patch_list) ||
> > > + !kernel_symbol_exists("klp_patches"))
> > > + return TRUE;
> > > +
> > > + list_addr = symbol_value("klp_patches");
> > > + if (!readmem(list_addr, KVADDR, &head, sizeof(head), "klp_patches",
> > > + RETURN_ON_ERROR | QUIET))
> > > + return TRUE;
> > > +
> > > + if (!head.next || head.next == (void *)list_addr)
> > > + return TRUE;
> > > +
> > > + BZERO(&ctx, sizeof(ctx));
> > > + ctx.transition_patch = transition_patch;
> > > +
> > > + BZERO(&ld, sizeof(ld));
> > > + ld.flags =
> > LIST_CALLBACK|CALLBACK_RETURN|RETURN_ON_LIST_ERROR|
> > > + RETURN_ON_DUPLICATE|LIST_ALLOCATE;
> > > + ld.start = (ulong)head.next;
> > > + ld.end = list_addr;
> > > + ld.member_offset = OFFSET(list_head_next);
> > > + ld.list_head_offset = OFFSET(klp_patch_list);
> > > + ld.callback_func = klp_transition_match;
> > > + ld.callback_data = &ctx;
> > > +
> > > + ret = do_list(&ld);
> > > + if (ret < 0)
> > > + return FALSE;
> > > +
> > > + return ctx.found;
> > > +}
> > > +
> > > /*
> > > * Display system stats at init-time or for the sys command.
> > > */
> > > @@ -5732,17 +5801,19 @@ display_sys_stats(void)
> > > }
> > > } else {
> > > if (pc->system_map) {
> > > - fprintf(fp, " SYSTEM MAP: %s%s%s\n",
> > pc->system_map,
> > > + fprintf(fp, " SYSTEM MAP: %s%s%s%s\n",
> > > + pc->system_map,
> > > is_livepatch() ? " [LIVEPATCH]" : "",
> > > + is_livepatch_transition() ? "
> > > + [TRANSITION]" : "",
> > > is_kernel_tainted() ? " [TAINTED]" : "");
> > > fprintf(fp, "DEBUG KERNEL: %s %s\n",
> > > pc->namelist_orig ?
> > > pc->namelist_orig : pc->namelist,
> > >
> > debug_kernel_version(pc->namelist));
> > > } else
> > > - fprintf(fp, " KERNEL: %s%s%s\n",
> > pc->namelist_orig ?
> > > + fprintf(fp, " KERNEL: %s%s%s%s\n",
> > pc->namelist_orig ?
> > > pc->namelist_orig : pc->namelist,
> > > is_livepatch() ? " [LIVEPATCH]" : "",
> > > + is_livepatch_transition() ? "
> > > + [TRANSITION]" : "",
> > > is_kernel_tainted() ? " [TAINTED]" : "");
> > > }
> > >
> > > --
> > > 2.47.3
> > >
>
1 month, 3 weeks
[PATCH] maple_tree: add support for maple_tree.c output to respect the global radix and per-command -x/d flags
by stalexan@redhat.com
The commands that generate maple tree output do not currently respect the
global radix setting, nor do they respect the -x output flag. This
patch aims to fix this inconsistency, so that the output commands
respect both the global radix setting as well as the per-command -x/d
flags.
Signed-off-by: Sterling Alexander <stalexan(a)redhat.com>
---
maple_tree.c | 93 ++++++++++++++++++++++++++++++++++------------------
1 file changed, 61 insertions(+), 32 deletions(-)
diff --git a/maple_tree.c b/maple_tree.c
index 8c804d0..3b11ddd 100644
--- a/maple_tree.c
+++ b/maple_tree.c
@@ -67,12 +67,15 @@ struct req_entry *fill_member_offsets(char *);
void dump_struct_members_fast(struct req_entry *, int, ulong);
void dump_struct_members_for_tree(struct tree_data *, int, ulong);
-static void mt_dump_range(ulong min, ulong max, uint depth)
+static void mt_dump_range(ulong min, ulong max, uint depth, int radix)
{
- if (min == max)
- fprintf(fp, "%.*s%lu: ", depth * 2, spaces, min);
- else
- fprintf(fp, "%.*s%lu-%lu: ", depth * 2, spaces, min, max);
+ if (min == max) {
+ fprintf(fp, (radix == 16) ? "%.*s%lx: " : "%.*s%lu: ",
+ depth * 2, spaces, min);
+ } else {
+ fprintf(fp, (radix == 16) ? "%.*s%lx-%lx: " : "%.*s%lu-%lu: ",
+ depth * 2, spaces, min, max);
+ }
}
static inline bool mt_is_reserved(ulong entry)
@@ -92,13 +95,28 @@ static uint mt_height(char *mt_buf)
>> MT_FLAGS_HEIGHT_OFFSET;
}
-static void dump_mt_range64(char *mr64_buf)
+/*
+ * Determine the output radix for maple tree display.
+ * Priority: 1) -x/-d flags, 2) global pc->output_radix
+ */
+static inline int mt_output_radix(struct tree_data *td)
+{
+ if (td) {
+ if (td->flags & TREE_STRUCT_RADIX_10)
+ return 10;
+ else if (td->flags & TREE_STRUCT_RADIX_16)
+ return 16;
+ }
+ return pc->output_radix;
+}
+
+static void dump_mt_range64(char *mr64_buf, int radix)
{
int i;
fprintf(fp, " contents: ");
for (i = 0; i < mt_slots[maple_range_64] - 1; i++)
- fprintf(fp, "%p %lu ",
+ fprintf(fp, (radix == 16) ? "%p %lx " : "%p %lu ",
VOID_PTR(mr64_buf + OFFSET(maple_range_64_slot)
+ sizeof(void *) * i),
ULONG(mr64_buf + OFFSET(maple_range_64_pivot)
@@ -107,14 +125,15 @@ static void dump_mt_range64(char *mr64_buf)
+ sizeof(void *) * i));
}
-static void dump_mt_arange64(char *ma64_buf)
+static void dump_mt_arange64(char *ma64_buf, int radix)
{
int i;
fprintf(fp, " contents: ");
for (i = 0; i < mt_slots[maple_arange_64]; i++)
- fprintf(fp, "%lu ", ULONG(ma64_buf + OFFSET(maple_arange_64_gap)
- + sizeof(ulong) * i));
+ fprintf(fp, (radix == 16) ? "%lx " : "%lu ",
+ ULONG(ma64_buf + OFFSET(maple_arange_64_gap)
+ + sizeof(ulong) * i));
fprintf(fp, "| %02X %02X| ",
UCHAR(ma64_buf + OFFSET(maple_arange_64_meta) +
@@ -123,7 +142,7 @@ static void dump_mt_arange64(char *ma64_buf)
OFFSET(maple_metadata_gap)));
for (i = 0; i < mt_slots[maple_arange_64] - 1; i++)
- fprintf(fp, "%p %lu ",
+ fprintf(fp, (radix == 16) ? "%p %lx " : "%p %lu ",
VOID_PTR(ma64_buf + OFFSET(maple_arange_64_slot) +
sizeof(void *) * i),
ULONG(ma64_buf + OFFSET(maple_arange_64_pivot) +
@@ -132,25 +151,27 @@ static void dump_mt_arange64(char *ma64_buf)
sizeof(void *) * i));
}
-static void dump_mt_entry(ulong entry, ulong min, ulong max, uint depth)
+static void dump_mt_entry(ulong entry, ulong min, ulong max, uint depth, int radix)
{
- mt_dump_range(min, max, depth);
+ mt_dump_range(min, max, depth, radix);
- if (xa_is_value(entry))
- fprintf(fp, "value %ld (0x%lx) [0x%lx]\n", xa_to_value(entry),
+ if (xa_is_value(entry)) {
+ fprintf(fp, (radix == 16) ? "value 0x%lx [0x%lx]\n" : "value %ld [0x%lx]\n",
xa_to_value(entry), entry);
- else if (xa_is_zero(entry))
- fprintf(fp, "zero (%ld)\n", xa_to_internal(entry));
- else if (mt_is_reserved(entry))
+ } else if (xa_is_zero(entry)) {
+ fprintf(fp, (radix == 16) ? "zero (0x%lx)\n" : "zero (%ld)\n",
+ xa_to_internal(entry));
+ } else if (mt_is_reserved(entry)) {
fprintf(fp, "UNKNOWN ENTRY (0x%lx)\n", entry);
- else
- fprintf(fp, "0x%lx\n", entry);
+ } else {
+ fprintf(fp, (radix == 16) ? "0x%lx\n" : "%lu\n", entry);
+ }
}
static void dump_mt_node(ulong maple_node, char *node_data, uint type,
- ulong min, ulong max, uint depth)
+ ulong min, ulong max, uint depth, int radix)
{
- mt_dump_range(min, max, depth);
+ mt_dump_range(min, max, depth, radix);
fprintf(fp, "node 0x%lx depth %d type %d parent %p",
maple_node, depth, type,
@@ -169,6 +190,7 @@ static void do_mt_range64(ulong entry, ulong min, ulong max,
int i;
int len = strlen(path);
struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
+ int radix = mt_output_radix(td);
char *mr64_buf;
if (SIZE(maple_node) > MAPLE_BUFSIZE)
@@ -180,7 +202,7 @@ static void do_mt_range64(ulong entry, ulong min, ulong max,
mr64_buf = node_buf + OFFSET(maple_node_mr64);
if (td && td->flags & TREE_STRUCT_VERBOSE) {
- dump_mt_range64(mr64_buf);
+ dump_mt_range64(mr64_buf, radix);
}
for (i = 0; i < mt_slots[maple_range_64]; i++) {
@@ -230,6 +252,7 @@ static void do_mt_arange64(ulong entry, ulong min, ulong max,
int i;
int len = strlen(path);
struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
+ int radix = mt_output_radix(td);
char *ma64_buf;
if (SIZE(maple_node) > MAPLE_BUFSIZE)
@@ -241,7 +264,7 @@ static void do_mt_arange64(ulong entry, ulong min, ulong max,
ma64_buf = node_buf + OFFSET(maple_node_ma64);
if (td && td->flags & TREE_STRUCT_VERBOSE) {
- dump_mt_arange64(ma64_buf);
+ dump_mt_arange64(ma64_buf, radix);
}
for (i = 0; i < mt_slots[maple_arange_64]; i++) {
@@ -286,6 +309,7 @@ static void do_mt_entry(ulong entry, ulong min, ulong max, uint depth,
int print_radix = 0, i;
static struct req_entry **e = NULL;
struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
+ int output_radix = mt_output_radix(td);
if (ops->entry && entry)
ops->entry(entry, entry, path, max, ops->private);
@@ -306,12 +330,15 @@ static void do_mt_entry(ulong entry, ulong min, ulong max, uint depth,
td->count++;
if (td->flags & TREE_STRUCT_VERBOSE) {
- dump_mt_entry(entry, min, max, depth);
- } else if (td->flags & VERBOSE && entry)
- fprintf(fp, "%lx\n", entry);
- if (td->flags & TREE_POSITION_DISPLAY && entry)
- fprintf(fp, " index: %ld position: %s/%u\n",
+ dump_mt_entry(entry, min, max, depth, output_radix);
+ } else if (td->flags & VERBOSE && entry) {
+ fprintf(fp, (output_radix == 16) ? "%lx\n" : "%lu\n", entry);
+ }
+ if (td->flags & TREE_POSITION_DISPLAY && entry) {
+ fprintf(fp, (output_radix == 16) ? " index: %lx position: %s/%u\n" :
+ " index: %ld position: %s/%u\n",
++(*global_index), path, index);
+ }
if (td->structname && entry) {
if (td->flags & TREE_STRUCT_RADIX_10)
@@ -319,7 +346,7 @@ static void do_mt_entry(ulong entry, ulong min, ulong max, uint depth,
else if (td->flags & TREE_STRUCT_RADIX_16)
print_radix = 16;
else
- print_radix = 0;
+ print_radix = output_radix;
for (i = 0; i < td->structname_args; i++) {
switch (count_chars(td->structname[i], '.')) {
@@ -348,6 +375,7 @@ static void do_mt_node(ulong entry, ulong min, ulong max,
uint i;
char node_buf[MAPLE_BUFSIZE];
struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
+ int radix = mt_output_radix(td);
if (SIZE(maple_node) > MAPLE_BUFSIZE)
error(FATAL, "MAPLE_BUFSIZE should be larger than maple_node struct");
@@ -356,7 +384,7 @@ static void do_mt_node(ulong entry, ulong min, ulong max,
"mt_dump_node read maple_node", FAULT_ON_ERROR);
if (td && td->flags & TREE_STRUCT_VERBOSE) {
- dump_mt_node(maple_node, node_buf, type, min, max, depth);
+ dump_mt_node(maple_node, node_buf, type, min, max, depth, radix);
}
switch (type) {
@@ -457,7 +485,8 @@ static void do_maple_tree_dump(ulong node, ulong slot, const char *path,
ulong index, void *private)
{
struct do_maple_tree_info *info = private;
- fprintf(fp, "[%lu] %lx\n", index, slot);
+ fprintf(fp, (pc->output_radix == 16) ? "[%lx] %lx\n" : "[%lu] %lx\n",
+ index, slot);
info->count++;
}
--
2.52.0
1 month, 3 weeks
Re: [PATCH] Ensure all child processes are properly cleaned up in restore_ifile_sanity
by Lianbo Jiang
Hi, Feng
Thank you for the patch. This looks good to me, so: Ack.
Lianbo
On 1/28/26 9:42 AM, devel-request(a)lists.crash-utility.osci.io wrote:
> Date: Wed, 3 Dec 2025 10:35:57 +0800
> From: neilfsun<loyou85(a)gmail.com>
> Subject: [Crash-utility] [PATCH] Ensure all child processes are
> properly cleaned up in restore_ifile_sanity
> To:devel@lists.crash-utility.osci.io
> Cc: neilfsun<neilfsun(a)tencent.com>, Feng Sun<loyou85(a)gmail.com>
> Message-ID:<20251203023557.55333-1-neilfsun(a)tencent.com>
>
> Run input file with pipe cmdlines will get nothing output.
>
> crash> p cpu_info:0 | grep 'x86 ='
> x86 = 0x19,
> crash> cat crashrc
> p cpu_info:0 | grep 'x86 ='
> p cpu_info:0 | grep 'x86 ='
> crash> < crashrc
> crash> p cpu_info:0 | grep 'x86 ='
> x86 = 0x19,
> crash> p cpu_info:0 | grep 'x86 ='
>
> crash>
>
> Signed-off-by: neilfsun<neilfsun(a)tencent.com>
> Signed-off-by: Feng Sun<loyou85(a)gmail.com>
> ---
> cmdline.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/cmdline.c b/cmdline.c
> index 65da04c..4add548 100644
> --- a/cmdline.c
> +++ b/cmdline.c
> @@ -1285,6 +1285,8 @@ restore_ifile_sanity(void)
> close_tmpfile2();
> }
>
> + wait_for_children(ALL_CHILDREN);
> +
> restore_gdb_sanity();
>
> free_all_bufs();
> -- 2.50.1
1 month, 3 weeks
Re: [PATCH] Fix prompt output interfering with piped commands in input files
by Lianbo Jiang
Hi, Feng
Thank you for the patch.
For this one: Ack.
Lianbo
On 1/28/26 9:42 AM, devel-request(a)lists.crash-utility.osci.io wrote:
> Date: Thu, 4 Dec 2025 14:34:37 +0800
> From: neilfsun<loyou85(a)gmail.com>
> Subject: [Crash-utility] [PATCH] Fix prompt output interfering with
> piped commands in input files
> To:devel@lists.crash-utility.osci.io
> Cc: neilfsun<neilfsun(a)tencent.com>, Feng Sun<loyou85(a)gmail.com>
> Message-ID:<20251204063437.4008-1-neilfsun(a)tencent.com>
>
> When executing piped commands from input files, the prompt text was
> incorrectly written to the pipe instead of stdout.
> This caused commands read the prompt as their first line,
> consuming it instead of the actual command output.
>
> crash> p cpu_info:0 | head -1
> per_cpu(cpu_info, 0) = $29 = {
> crash> p cpu_info:0 | head -2
> per_cpu(cpu_info, 0) = $4 = {
> x86 = 0x6,
> crash> cat crashrc1
> p cpu_info:0 | head -1
> crash> < crashrc1
> crash> p cpu_info:0 | head -1
>
> crash> cat crashrc2
> p cpu_info:0 | head -2
> crash> < crashrc2
> crash> p cpu_info:0 | head -2
> per_cpu(cpu_info, 0) = $30 = {
> crash>
>
> Fix: Output prompt to incoming_fp (stdout) instead of fp (which may be the pipe
> after setup_redirect()), ensuring prompts display on terminal while command output
> goes to the pipe as intended.
>
> Signed-off-by: neilfsun<neilfsun(a)tencent.com>
> Signed-off-by: Feng Sun<loyou85(a)gmail.com>
> ---
> cmdline.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/cmdline.c b/cmdline.c
> index 4add548..030ae56 100644
> --- a/cmdline.c
> +++ b/cmdline.c
> @@ -1488,8 +1488,8 @@ exec_input_file(void)
> continue;
>
> if (!(pc->flags & SILENT)) {
> - fprintf(fp, "%s%s", pc->prompt, buf);
> - fflush(fp);
> + fprintf(incoming_fp, "%s%s", pc->prompt, buf);
> + fflush(incoming_fp);
> }
>
> exec_command();
> -- 2.50.1
1 month, 3 weeks