Debrand for AlmaLinux
This commit is contained in:
commit
fee1bc9bdd
1
.fmf/version
Normal file
1
.fmf/version
Normal file
@ -0,0 +1 @@
|
||||
1
|
||||
99
0001-crash-9.0.1-crash-9.0.2.patch
Normal file
99
0001-crash-9.0.1-crash-9.0.2.patch
Normal file
@ -0,0 +1,99 @@
|
||||
From 61fe107ff96a22e7df0029877529b7ce6da36850 Mon Sep 17 00:00:00 2001
|
||||
From: Tao Liu <ltao@redhat.com>
|
||||
Date: Fri, 24 Apr 2026 15:14:08 +1200
|
||||
Subject: [PATCH 01/39] crash-9.0.1 -> crash-9.0.2
|
||||
|
||||
Signed-off-by: Tao Liu <ltao@redhat.com>
|
||||
---
|
||||
.rh_rpm_package | 2 +-
|
||||
README | 18 +++++++++---------
|
||||
help.c | 2 +-
|
||||
3 files changed, 11 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/.rh_rpm_package b/.rh_rpm_package
|
||||
index 1ef1fd1e0ed7..3beeadd423d3 100644
|
||||
--- a/.rh_rpm_package
|
||||
+++ b/.rh_rpm_package
|
||||
@@ -1 +1 @@
|
||||
-9.0.1++
|
||||
+9.0.2
|
||||
diff --git a/README b/README
|
||||
index 9ef8c75d5485..e2d740a57f8f 100644
|
||||
--- a/README
|
||||
+++ b/README
|
||||
@@ -80,8 +80,8 @@
|
||||
|
||||
To build the crash utility:
|
||||
|
||||
- $ tar -xf crash-9.0.1.tar.gz
|
||||
- $ cd crash-9.0.1
|
||||
+ $ tar -xf crash-9.0.2.tar.gz
|
||||
+ $ cd crash-9.0.2
|
||||
$ make
|
||||
|
||||
To cross compile the crash utility for aarch64 on x86_64:
|
||||
@@ -137,7 +137,7 @@
|
||||
If neither /dev/mem or /dev/crash are available, then /proc/kcore will be
|
||||
be used as the live memory source. If /proc/kcore is also restricted, then
|
||||
the Red Hat /dev/crash driver may be compiled and installed; its source
|
||||
- is included in the crash-9.0.1/memory_driver subdirectory.
|
||||
+ is included in the crash-9.0.2/memory_driver subdirectory.
|
||||
|
||||
If the kernel file is stored in /boot, /, /boot/efi, or in any /usr/src
|
||||
or /usr/lib/debug/lib/modules subdirectory, then no command line arguments
|
||||
@@ -148,8 +148,8 @@
|
||||
|
||||
$ crash
|
||||
|
||||
- crash 9.0.1
|
||||
- Copyright (C) 2002-2025 Red Hat, Inc.
|
||||
+ crash 9.0.2
|
||||
+ Copyright (C) 2002-2026 Red Hat, Inc.
|
||||
Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation
|
||||
Copyright (C) 1999-2006 Hewlett-Packard Co
|
||||
Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited
|
||||
@@ -174,7 +174,7 @@
|
||||
KERNEL: /boot/vmlinux
|
||||
DUMPFILE: /dev/mem
|
||||
CPUS: 1
|
||||
- DATE: Tue Jun 10 18:03:09 CST 2025
|
||||
+ DATE: Fri Apr 24 10:38:29 CST 2026
|
||||
UPTIME: 10 days, 22:55:18
|
||||
LOAD AVERAGE: 0.08, 0.03, 0.01
|
||||
TASKS: 42
|
||||
@@ -216,8 +216,8 @@
|
||||
|
||||
$ crash vmlinux vmcore
|
||||
|
||||
- crash 9.0.0
|
||||
- Copyright (C) 2002-2025 Red Hat, Inc.
|
||||
+ crash 9.0.2
|
||||
+ Copyright (C) 2002-2026 Red Hat, Inc.
|
||||
Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation
|
||||
Copyright (C) 1999-2006 Hewlett-Packard Co
|
||||
Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited
|
||||
@@ -242,7 +242,7 @@
|
||||
KERNEL: vmlinux
|
||||
DUMPFILE: vmcore
|
||||
CPUS: 4
|
||||
- DATE: Tue Jun 10 18:03:09 CST 2025
|
||||
+ DATE: Fri Apr 24 10:38:29 CST 2026
|
||||
UPTIME: 00:02:40
|
||||
LOAD AVERAGE: 2.24, 0.96, 0.37
|
||||
TASKS: 70
|
||||
diff --git a/help.c b/help.c
|
||||
index 91d155098993..810075b97f35 100644
|
||||
--- a/help.c
|
||||
+++ b/help.c
|
||||
@@ -8557,7 +8557,7 @@ display_version(void)
|
||||
static
|
||||
char *version_info[] = {
|
||||
|
||||
-"Copyright (C) 2002-2025 Red Hat, Inc.",
|
||||
+"Copyright (C) 2002-2026 Red Hat, Inc.",
|
||||
"Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation",
|
||||
"Copyright (C) 1999-2006 Hewlett-Packard Co",
|
||||
"Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited",
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
From 89d36e12d7b753028038dfb93068fdfd0f6f1501 Mon Sep 17 00:00:00 2001
|
||||
From: Tao Liu <ltao@redhat.com>
|
||||
Date: Fri, 24 Apr 2026 15:15:19 +1200
|
||||
Subject: [PATCH 02/39] Mark start of 9.0.3 development phase with version
|
||||
9.0.2++
|
||||
|
||||
Signed-off-by: Tao Liu <ltao@redhat.com>
|
||||
---
|
||||
.rh_rpm_package | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/.rh_rpm_package b/.rh_rpm_package
|
||||
index 3beeadd423d3..a3cb14a5a842 100644
|
||||
--- a/.rh_rpm_package
|
||||
+++ b/.rh_rpm_package
|
||||
@@ -1 +1 @@
|
||||
-9.0.2
|
||||
+9.0.2++
|
||||
--
|
||||
2.54.0
|
||||
|
||||
91
0003-RISCV64-introduce-riscv64_VTOP-and-riscv64_PTOV.patch
Normal file
91
0003-RISCV64-introduce-riscv64_VTOP-and-riscv64_PTOV.patch
Normal file
@ -0,0 +1,91 @@
|
||||
From 4e4dc1c89310e4106f7d0da8029084124c5e016d Mon Sep 17 00:00:00 2001
|
||||
From: Austin Kim <austindh.kim@gmail.com>
|
||||
Date: Mon, 6 Apr 2026 13:53:37 +0900
|
||||
Subject: [PATCH 03/39] RISCV64: introduce riscv64_VTOP() and riscv64_PTOV()
|
||||
|
||||
The VTOP and PTOV macros are typically implemented using architecture-specific
|
||||
functions to improve maintainability and debugging capabilities.
|
||||
|
||||
This patch moves the RISCV64-specific VTOP/PTOV logic from inline macros
|
||||
in defs.h to dedicated functions in riscv64.c. This refactoring makes the
|
||||
code easier to understand and provides a better location for adding
|
||||
future debugging or validation checks.
|
||||
|
||||
No functional changes are introduced by this patch.
|
||||
|
||||
Signed-off-by: Austin Kim <austindh.kim@gmail.com>
|
||||
---
|
||||
defs.h | 14 ++++----------
|
||||
riscv64.c | 24 ++++++++++++++++++++++++
|
||||
2 files changed, 28 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index a6f43725b6b8..54f1725d089a 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -3803,16 +3803,8 @@ typedef signed int s32;
|
||||
/*
|
||||
* Direct memory mapping
|
||||
*/
|
||||
-#define PTOV(X) \
|
||||
- (((unsigned long)(X)+(machdep->kvbase)) - machdep->machspec->phys_base)
|
||||
-#define VTOP(X) ({ \
|
||||
- ulong _X = X; \
|
||||
- (THIS_KERNEL_VERSION >= LINUX(5,13,0) && \
|
||||
- (_X) >= machdep->machspec->kernel_link_addr) ? \
|
||||
- ((unsigned long)(_X)-(machdep->machspec->va_kernel_pa_offset)): \
|
||||
- (((unsigned long)(_X)-(machdep->kvbase)) + \
|
||||
- machdep->machspec->phys_base); \
|
||||
- })
|
||||
+#define PTOV(X) riscv64_PTOV((ulong)(X))
|
||||
+#define VTOP(X) riscv64_VTOP((ulong)(X))
|
||||
#define PAGEBASE(X) (((ulong)(X)) & (ulong)machdep->pagemask)
|
||||
|
||||
/*
|
||||
@@ -7211,6 +7203,8 @@ void riscv64_display_regs_from_elf_notes(int, FILE *);
|
||||
void riscv64_init(int);
|
||||
void riscv64_dump_machdep_table(ulong);
|
||||
int riscv64_IS_VMALLOC_ADDR(ulong);
|
||||
+ulong riscv64_PTOV(ulong);
|
||||
+ulong riscv64_VTOP(ulong);
|
||||
|
||||
#define display_idt_table() \
|
||||
error(FATAL, "-d option is not applicable to RISCV64 architecture\n")
|
||||
diff --git a/riscv64.c b/riscv64.c
|
||||
index ee9d4e321f6b..ff7b19eeb0d7 100644
|
||||
--- a/riscv64.c
|
||||
+++ b/riscv64.c
|
||||
@@ -1606,6 +1606,30 @@ riscv64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verb
|
||||
}
|
||||
}
|
||||
|
||||
+ulong riscv64_PTOV(ulong paddr)
|
||||
+{
|
||||
+ ulong vaddr;
|
||||
+ ulong offset = paddr - machdep->machspec->phys_base;
|
||||
+
|
||||
+ vaddr = offset + machdep->kvbase;
|
||||
+
|
||||
+ return vaddr;
|
||||
+}
|
||||
+
|
||||
+ulong
|
||||
+riscv64_VTOP(ulong addr)
|
||||
+{
|
||||
+ ulong paddr;
|
||||
+
|
||||
+ if ( (THIS_KERNEL_VERSION >= LINUX(5,13,0)) &&
|
||||
+ (addr >= machdep->machspec->kernel_link_addr))
|
||||
+ paddr = (addr - (machdep->machspec->va_kernel_pa_offset));
|
||||
+ else
|
||||
+ paddr = (addr - (ulong)machdep->kvbase + machdep->machspec->phys_base);
|
||||
+
|
||||
+ return paddr;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
riscv64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
|
||||
{
|
||||
--
|
||||
2.54.0
|
||||
|
||||
39
0004-Fix-wrong-detection-of-LIVEPATCH-on-old-kernels.patch
Normal file
39
0004-Fix-wrong-detection-of-LIVEPATCH-on-old-kernels.patch
Normal file
@ -0,0 +1,39 @@
|
||||
From c0097c84fed048e3e073f73a72ec9f16f8232c4b Mon Sep 17 00:00:00 2001
|
||||
From: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
Date: Thu, 16 Apr 2026 04:35:42 +0000
|
||||
Subject: [PATCH 04/39] Fix wrong detection of "[LIVEPATCH]" on old kernels
|
||||
|
||||
The crash-utility wrongly prints "[LIVEPATCH]" occasionally on old
|
||||
kernels:
|
||||
|
||||
KERNEL: vmlinux [LIVEPATCH]
|
||||
DUMPFILE: dump.d31 [PARTIAL DUMP]
|
||||
...
|
||||
RELEASE: 2.6.24
|
||||
|
||||
In is_livepatch(), show_kernel_tains() does not set any value to buf on
|
||||
kernels that have the "tainted" symbol, so it's printed when the
|
||||
uninitialized buf has "K" by chance. On very old kernels, but this
|
||||
issue affects makedumpfile tests.
|
||||
|
||||
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
---
|
||||
kernel.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/kernel.c b/kernel.c
|
||||
index 8781d6a22414..1e639ec6a007 100644
|
||||
--- a/kernel.c
|
||||
+++ b/kernel.c
|
||||
@@ -5678,7 +5678,7 @@ is_livepatch(void)
|
||||
{
|
||||
int i;
|
||||
struct load_module *lm;
|
||||
- char buf[BUFSIZE];
|
||||
+ char buf[BUFSIZE] = {0};
|
||||
|
||||
show_kernel_taints(buf, !VERBOSE);
|
||||
if (strstr(buf, "K")) /* TAINT_LIVEPATCH */
|
||||
--
|
||||
2.54.0
|
||||
|
||||
103
0005-Fix-unwinding-with-32k-stacks-in-ppc64le.patch
Normal file
103
0005-Fix-unwinding-with-32k-stacks-in-ppc64le.patch
Normal file
@ -0,0 +1,103 @@
|
||||
From 5da4d159a5efec95988349abfa12050dfc6578a6 Mon Sep 17 00:00:00 2001
|
||||
From: Lucas Oakley <soakley@redhat.com>
|
||||
Date: Wed, 6 May 2026 09:26:51 -0400
|
||||
Subject: [PATCH 05/39] Fix unwinding with 32k stacks in ppc64le
|
||||
|
||||
With commit 18f14afe2816 ("powerpc/64s: Increase default stack
|
||||
size to 32KB") in upstream ppc64le, the stack size was adjusted
|
||||
from 16k to 32k. As a result, ppc64_back_trace() can bail
|
||||
prematurely when checking if the stack pointer exists in the
|
||||
range of the range of the irq stacks, since SIZE(irq_ctx), used
|
||||
in ppc64_in_irqstack(), is set to 16k. This patch ensures that
|
||||
irq_ctx is updated to 32k if a 32k stack size is used.
|
||||
|
||||
Tested against:
|
||||
el6 x86_64
|
||||
el7 ppc64le s390x x86_64
|
||||
el8 aarch64 ppc64le s390x x86_64
|
||||
el9 aarch64 ppc64le s390x x86_64
|
||||
el10 aarch64 ppc64le s390x x86_64
|
||||
|
||||
Without the commit:
|
||||
|
||||
crash> bt -c 3
|
||||
PID: 17524 TASK: c0000000b2c0e400 CPU: 3 COMMAND: "xyz"
|
||||
cannot find the stack info.
|
||||
|
||||
With the commit:
|
||||
|
||||
crash> bt -c 3
|
||||
PID: 17524 TASK: c0000000b2c0e400 CPU: 3 COMMAND: "xyz"
|
||||
#0 [c000001dff7d7c10] smp_call_function_single_async at c00000000028dd38
|
||||
#1 [c000001dff7d7d30] _raw_spin_lock_irqsave at c000000001023f1c
|
||||
#2 [c000001dff7d7d60] ibmvscsi_handle_crq at c0080000044635ec [ibmvscsi]
|
||||
#3 [c000001dff7d7de0] ibmvscsi_task at c008000004463804 [ibmvscsi]
|
||||
#4 [c000001dff7d7e30] tasklet_action_common.constprop.0 at c0000000001624cc
|
||||
#5 [c000001dff7d7e90] __do_softirq at c0000000010244cc
|
||||
#6 [c000001dff7d7f90] do_softirq_own_stack at c000000000016480
|
||||
#7 [c000000140d67700] __irq_exit_rcu at c0000000001613b8
|
||||
#8 [c000000140d67730] irq_exit at c000000000162170
|
||||
#9 [c000000140d67750] do_IRQ at c000000000015fa4
|
||||
#10 [c000000140d67780] hardware_interrupt_common_virt at c000000000009080
|
||||
Hardware Interrupt [500] exception frame:
|
||||
R0: c000000001023de0 R1: c000000140d67a90 R2: c000000002c02500
|
||||
R3: c00800000b30269c R4: 0000000000000001 R5: 0000000000000001
|
||||
R6: ffffffffffffffff R7: 0000000000000000 R8: 0000000000000000
|
||||
R9: fffffffffffe0000 R10: 0000000000000002 R11: 0000000048422824
|
||||
R12: c000000001023d70 R13: c000001dffffd480 R14: 00007ffd6ef6d238
|
||||
R15: 0000000000000028 R16: c000001dfc1e2280 R17: c000001dfc1e2280
|
||||
R18: 00000000ab97fa48 R19: 0000000000000000 R20: 0000000000000001
|
||||
R21: 0000001df9ff0000 R22: 0000000000000028 R23: c0000000021f2280
|
||||
R24: 0000000000000000 R25: c0000000021f2280 R26: c0000000021f2380
|
||||
R27: 0000000000000000 R28: c00800000b30269c R29: 0000000000000000
|
||||
R30: c000000002c47190 R31: 000000000020000b
|
||||
NIP: c0000000000aea14 MSR: 800000000280b033 OR3: c0000000000ae944
|
||||
CTR: c000000001023d70 LR: c000000001023de0 XER: 0000000020040001
|
||||
CCR: 0000000088422824 MQ: 0000000000000000 DAR: 0000000000000001
|
||||
DSISR: c0080000073b1e94 Syscall Result: 0000000000000000
|
||||
[NIP : queued_spin_lock_slowpath+1204]
|
||||
[LR : _raw_spin_lock+112]
|
||||
#11 [c000000140d67a90] queued_spin_lock_slowpath at c0000000000aea14
|
||||
#12 [c000000140d67bb0] _raw_spin_lock at c000000001023de0 (unreliable)
|
||||
#13 [c000000140d67bd0] dm_blk_close at c00800000b2c6850 [dm_mod]
|
||||
#14 [c000000140d67c00] blkdev_put_whole at c0000000007d2738
|
||||
#15 [c000000140d67c30] bdev_release at c0000000007d3a38
|
||||
#16 [c000000140d67c90] blkdev_release at c0000000007d4224
|
||||
#17 [c000000140d67cb0] __fput at c0000000005d2e98
|
||||
#18 [c000000140d67d00] task_work_run at c00000000018fb14
|
||||
#19 [c000000140d67d50] do_notify_resume at c000000000020bd4
|
||||
#20 [c000000140d67d80] interrupt_exit_user_prepare_main at c00000000002ed98
|
||||
#21 [c000000140d67de0] syscall_exit_prepare at c00000000002f240
|
||||
#22 [c000000140d67e10] system_call_vectored_common at c00000000000bff4
|
||||
|
||||
Signed-off-by: Lucas Oakley <soakley@redhat.com>
|
||||
---
|
||||
task.c | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/task.c b/task.c
|
||||
index ec04b556c337..d7f3c129a709 100644
|
||||
--- a/task.c
|
||||
+++ b/task.c
|
||||
@@ -739,6 +739,18 @@ irqstacks_init(void)
|
||||
if (!(tt->softirq_tasks = (ulong *)calloc(NR_CPUS, sizeof(ulong))))
|
||||
error(FATAL, "cannot malloc softirq_tasks space.");
|
||||
|
||||
+ /*
|
||||
+ * With the stack size adjusted from 16k to 32k for ppc64le,
|
||||
+ * such as rhel-9.4.z. We need to ensure that SIZE(irq_ctx) is
|
||||
+ * correctly set so the unwinder doesn't prematurely bail
|
||||
+ * when switching between the kernel stack and irq stacks.
|
||||
+ * The stack size is updated in task_init(), which calls
|
||||
+ * this routine, irqstacks_init() after checking for the
|
||||
+ * existence of irq_ctx.
|
||||
+ */
|
||||
+ if (STACKSIZE() > SIZE(irq_ctx))
|
||||
+ ASSIGN_SIZE(irq_ctx) = STACKSIZE();
|
||||
+
|
||||
thread_info_buf = GETBUF(SIZE(irq_ctx));
|
||||
|
||||
if ((hard_sp = per_cpu_symbol_search("per_cpu__hardirq_ctx")) ||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
232
0006-arm64-fix-gdb-register-feeding-for-exception-frames-.patch
Normal file
232
0006-arm64-fix-gdb-register-feeding-for-exception-frames-.patch
Normal file
@ -0,0 +1,232 @@
|
||||
From fa4ba91e0383343112478decce41cea3b499da15 Mon Sep 17 00:00:00 2001
|
||||
From: lipengfei28 <lipengfei28@xiaomi.com>
|
||||
Date: Wed, 1 Apr 2026 10:32:35 +0800
|
||||
Subject: [PATCH 06/39] arm64: fix gdb register feeding for exception frames
|
||||
and stack switching
|
||||
|
||||
On ARM64, crash's gdb bt relies on feeding a register snapshot (PC/SP/FP,
|
||||
etc.) into gdb and letting gdb unwind from there. Before this change, the
|
||||
register snapshot handling across exception frames / stack switching could be
|
||||
broken in several ways, leading to truncated backtraces, garbage substacks, or
|
||||
invalid addresses (e.g. -3 / 0xff...fd) showing up in gdb output.
|
||||
|
||||
Fixes included in this patch:
|
||||
|
||||
Fix out-of-bounds read when populating gdb registers from an exception frame
|
||||
In arm64_print_exception_frame() the previous code copied
|
||||
sizeof(struct arm64_pt_regs) bytes from a smaller stackframe-derived
|
||||
buffer, which could read past valid data and poison the gdb registers.
|
||||
Replace this with explicit field/register assignment and initialize the
|
||||
bitmap accordingly.
|
||||
|
||||
Improve unwinding across IRQ/overflow stack transitions on newer kernels
|
||||
When switching stacks (IRQ / overflow), gdb may stop at the trampoline (e.g.
|
||||
call_on_irq_stack) because the discontinuity prevents it from recovering
|
||||
the caller frame automatically. For UNW_4_14+, "peek" one frame ahead by
|
||||
reading the saved FP/PC from the current frame, and register that as the
|
||||
next gdb substack, so gdb can continue unwinding on the process stack.
|
||||
|
||||
Avoid creating invalid/empty substacks
|
||||
Only add a gdb substack when the recovered PC is non-zero, preventing bogus
|
||||
threads from being created.
|
||||
|
||||
This patch only changes ARM64 unwinding/register setup logic. It does not try
|
||||
to reformat or merge gdb output.
|
||||
|
||||
Tested on: Android Linux 6.x, arm64
|
||||
|
||||
Signed-off-by: lipengfei28 <lipengfei28@xiaomi.com>
|
||||
---
|
||||
arm64.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 87 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/arm64.c b/arm64.c
|
||||
index c125655d6807..d17709299b2d 100644
|
||||
--- a/arm64.c
|
||||
+++ b/arm64.c
|
||||
@@ -228,7 +228,7 @@ arm64_get_current_task_reg(int regno, const char *name,
|
||||
return FALSE;
|
||||
|
||||
if (sid && sid <= extra_stacks_idx) {
|
||||
- ur_bitmap = extra_stacks_regs[extra_stacks_idx - 1];
|
||||
+ ur_bitmap = extra_stacks_regs[sid - 1];
|
||||
goto get_sub;
|
||||
}
|
||||
|
||||
@@ -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,13 @@ 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->task != tt->panic_task) &&
|
||||
+ (!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 +3935,13 @@ 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->task != tt->panic_task) &&
|
||||
+ (!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++);
|
||||
}
|
||||
}
|
||||
@@ -4232,6 +4244,46 @@ arm64_in_kdump_text_on_irq_stack(struct bt_info *bt)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+static void
|
||||
+arm64_gdb_add_next_frame_substack(struct bt_info *bt, const struct arm64_stackframe *frame)
|
||||
+{
|
||||
+ struct machine_specific *ms = machdep->machspec;
|
||||
+ struct user_regs_bitmap_struct *ur_ptr;
|
||||
+ ulong next_fp, next_pc, next_sp;
|
||||
+
|
||||
+ 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));
|
||||
+ ur_ptr = extra_stacks_regs[extra_stacks_idx];
|
||||
+
|
||||
+ next_fp = GET_STACK_ULONG(frame->fp);
|
||||
+ next_pc = GET_STACK_ULONG(frame->fp + 8);
|
||||
+ 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++);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int
|
||||
arm64_switch_stack(struct bt_info *bt, struct arm64_stackframe *frame, FILE *ofp)
|
||||
{
|
||||
@@ -4263,8 +4315,11 @@ 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 {
|
||||
+ arm64_gdb_add_next_frame_substack(bt, frame);
|
||||
+ }
|
||||
|
||||
return KERNEL_MODE;
|
||||
}
|
||||
@@ -4300,8 +4355,11 @@ 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 {
|
||||
+ arm64_gdb_add_next_frame_substack(bt, frame);
|
||||
+ }
|
||||
|
||||
return KERNEL_MODE;
|
||||
}
|
||||
@@ -4549,6 +4607,9 @@ arm64_print_exception_frame(struct bt_info *bt, ulong pt_regs, int mode, FILE *o
|
||||
(ulong)regs->orig_x0, (ulong)regs->syscallno);
|
||||
fprintf(ofp, " PSTATE: %08lx\n", (ulong)regs->pstate);
|
||||
} else if (!(bt->flags & BT_EFRAME_SEARCH)) {
|
||||
+ struct user_regs_bitmap_struct *ur_ptr;
|
||||
+ int i;
|
||||
+
|
||||
if (!extra_stacks_regs[extra_stacks_idx]) {
|
||||
extra_stacks_regs[extra_stacks_idx] =
|
||||
(struct user_regs_bitmap_struct *)
|
||||
@@ -4556,17 +4617,26 @@ 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 !=
|
||||
+
|
||||
+ ur_ptr = extra_stacks_regs[extra_stacks_idx];
|
||||
+
|
||||
+ 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 &&
|
||||
- extra_stacks_regs[extra_stacks_idx]->ur.pc !=
|
||||
- ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc)) {
|
||||
- gdb_add_substack (extra_stacks_idx++);
|
||||
- }
|
||||
+ ur_ptr->ur.pc !=
|
||||
+ ((struct user_regs_bitmap_struct *)(bt->machdep))->ur.pc))) {
|
||||
+ gdb_add_substack(extra_stacks_idx++);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From 4f66cea2487d511dbc9b7ff10a7e9fb98337273f Mon Sep 17 00:00:00 2001
|
||||
From: Rui Qi <qirui.001@bytedance.com>
|
||||
Date: Wed, 29 Apr 2026 14:13:25 +0800
|
||||
Subject: [PATCH 07/39] RISCV64: fix pmd address calculation in
|
||||
riscv64_vtop_4level_4k
|
||||
|
||||
Fix a bug in the PMD address calculation where the operator was
|
||||
incorrectly using '+' instead of '*'. This caused the PMD index
|
||||
to be added as an offset rather than multiplied by the entry size,
|
||||
resulting in incorrect page table traversal for 4-level 4KB paging.
|
||||
|
||||
Signed-off-by: Rui Qi <qirui.001@bytedance.com>
|
||||
---
|
||||
riscv64.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/riscv64.c b/riscv64.c
|
||||
index ff7b19eeb0d7..8c6aa9557ec5 100644
|
||||
--- a/riscv64.c
|
||||
+++ b/riscv64.c
|
||||
@@ -1241,7 +1241,7 @@ riscv64_vtop_4level_4k(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
|
||||
|
||||
/* PMD */
|
||||
FILL_PMD(PAGEBASE(pmd_base), PHYSADDR, PAGESIZE());
|
||||
- pmd_addr = pmd_base + sizeof(pmd_t) + pmd_index_l4_4k(vaddr);
|
||||
+ pmd_addr = pmd_base + sizeof(pmd_t) * pmd_index_l4_4k(vaddr);
|
||||
pmd_val = ULONG(machdep->pmd + PAGEOFFSET(pmd_addr));
|
||||
if (verbose)
|
||||
fprintf(fp, " PMD: %016lx => %016lx\n", pmd_addr, pmd_val);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
From ce0fc6b73de86e448fd13541a4ea6b60d7af0e1c Mon Sep 17 00:00:00 2001
|
||||
From: Rui Qi <qirui.001@bytedance.com>
|
||||
Date: Wed, 6 May 2026 12:27:29 +0800
|
||||
Subject: [PATCH 08/39] symbols: optimize symname_hash with larger table and
|
||||
FNV-1a hash
|
||||
|
||||
Optimize the symbol name hash table to reduce collision and improve
|
||||
performance, especially on RISC-V architecture where symbol lookup
|
||||
is a hotspot.
|
||||
|
||||
Changes:
|
||||
- Increase SYMNAME_HASH from 512 to 16384 (32x) to reduce collisions
|
||||
- Replace simple hash with FNV-1a algorithm for better distribution
|
||||
- Remove strlen() call, compute hash in single pass
|
||||
|
||||
This reduces the average chain length in hash buckets significantly,
|
||||
improving symbol lookup performance at the cost of ~248KB additional
|
||||
memory.
|
||||
|
||||
Signed-off-by: Rui Qi <qirui.001@bytedance.com>
|
||||
---
|
||||
defs.h | 2 +-
|
||||
symbols.c | 15 +++++++++------
|
||||
2 files changed, 10 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index 54f1725d089a..6a91343f0313 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -2900,7 +2900,7 @@ struct downsized {
|
||||
#define SYMVAL_HASH_INDEX(vaddr) \
|
||||
(((vaddr) >> machdep->pageshift) % SYMVAL_HASH)
|
||||
|
||||
-#define SYMNAME_HASH (512)
|
||||
+#define SYMNAME_HASH (16384)
|
||||
|
||||
#define PATCH_KERNEL_SYMBOLS_START ((char *)(1))
|
||||
#define PATCH_KERNEL_SYMBOLS_STOP ((char *)(2))
|
||||
diff --git a/symbols.c b/symbols.c
|
||||
index e6865cabef74..afdf4a61cea2 100644
|
||||
--- a/symbols.c
|
||||
+++ b/symbols.c
|
||||
@@ -1170,16 +1170,19 @@ symname_hash_init(void)
|
||||
static unsigned int
|
||||
symname_hash_index(char *name)
|
||||
{
|
||||
- unsigned int len, value;
|
||||
- unsigned char *array = (unsigned char *)name;
|
||||
+ unsigned int hash = 2166136261U;
|
||||
+ unsigned char *p = (unsigned char *)name;
|
||||
|
||||
- len = strlen(name);
|
||||
- if (!len)
|
||||
+ if (!*p)
|
||||
error(FATAL, "The length of the symbol name is zero!\n");
|
||||
|
||||
- value = array[len - 1] * array[len / 2];
|
||||
+ /* FNV-1a hash algorithm for better distribution */
|
||||
+ while (*p) {
|
||||
+ hash ^= *p++;
|
||||
+ hash *= 16777619;
|
||||
+ }
|
||||
|
||||
- return (array[0] ^ value) % SYMNAME_HASH;
|
||||
+ return hash % SYMNAME_HASH;
|
||||
}
|
||||
|
||||
/*
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,76 @@
|
||||
From ad1e05f3d1ae96ce5862b2877db4bded9a9a6336 Mon Sep 17 00:00:00 2001
|
||||
From: Rui Qi <qirui.001@bytedance.com>
|
||||
Date: Wed, 6 May 2026 12:27:30 +0800
|
||||
Subject: [PATCH 09/39] RISCV64: add mapping symbol filter in
|
||||
riscv64_verify_symbol
|
||||
|
||||
Add mapping symbol filter in riscv64_verify_symbol() to filter out
|
||||
linker mapping symbols like '.L*', 'L0*' and '$*'. These symbols
|
||||
should not end up in the symbol list.
|
||||
|
||||
Also optimize riscv64_verify_symbol() by consolidating name validity
|
||||
checks at the function entry.
|
||||
|
||||
Changes:
|
||||
- riscv64.c: Add mapping symbol filter and optimize name checks
|
||||
- symbols.c: Add machine_type("RISCV64") to enable verify_symbol()
|
||||
call in store_module_kallsyms_v2()
|
||||
|
||||
Signed-off-by: Rui Qi <qirui.001@bytedance.com>
|
||||
---
|
||||
riscv64.c | 14 +++++++++++---
|
||||
symbols.c | 5 ++++-
|
||||
2 files changed, 15 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/riscv64.c b/riscv64.c
|
||||
index 8c6aa9557ec5..f0783d570c7b 100644
|
||||
--- a/riscv64.c
|
||||
+++ b/riscv64.c
|
||||
@@ -209,15 +209,23 @@ riscv64_cmd_mach(void)
|
||||
static int
|
||||
riscv64_verify_symbol(const char *name, ulong value, char type)
|
||||
{
|
||||
- if (CRASHDEBUG(8) && name && strlen(name))
|
||||
+ if (!name || !strlen(name))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (CRASHDEBUG(8))
|
||||
fprintf(fp, "%08lx %s\n", value, name);
|
||||
|
||||
+ /* Filter out mapping symbols */
|
||||
+ if ((name[0] == '.' && name[1] == 'L') ||
|
||||
+ (name[0] == 'L' && name[1] == '0') ||
|
||||
+ (name[0] == '$'))
|
||||
+ return FALSE;
|
||||
+
|
||||
if (!(machdep->flags & KSYMS_START)) {
|
||||
if (STREQ(name, "_text") || STREQ(name, "_stext"))
|
||||
machdep->flags |= KSYMS_START;
|
||||
|
||||
- return (name && strlen(name) && !STRNEQ(name, "__func__.") &&
|
||||
- !STRNEQ(name, "__crc_"));
|
||||
+ return (!STRNEQ(name, "__func__.") && !STRNEQ(name, "__crc_"));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
diff --git a/symbols.c b/symbols.c
|
||||
index afdf4a61cea2..8eb8b37abc23 100644
|
||||
--- a/symbols.c
|
||||
+++ b/symbols.c
|
||||
@@ -2990,9 +2990,12 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr,
|
||||
* or '$x' for ARM64, and '$d'.
|
||||
* On LoongArch we have linker mapping symbols like '.L'
|
||||
* or 'L0'.
|
||||
+ * On RISCV64 we have linker mapping symbols like '.L',
|
||||
+ * 'L0' or '$'.
|
||||
* Make sure that these don't end up into our symbol list.
|
||||
*/
|
||||
- if ((machine_type("ARM") || machine_type("ARM64") || machine_type("LOONGARCH64")) &&
|
||||
+ if ((machine_type("ARM") || machine_type("ARM64") || machine_type("LOONGARCH64") ||
|
||||
+ machine_type("RISCV64")) &&
|
||||
!machdep->verify_symbol(nameptr, ec->st_value, ec->st_info))
|
||||
continue;
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
71
0010-Fix-get_xtime-for-kernel-6.13-and-higher.patch
Normal file
71
0010-Fix-get_xtime-for-kernel-6.13-and-higher.patch
Normal file
@ -0,0 +1,71 @@
|
||||
From 7ff3146d46ea9afb0724b57b3425c9a965a67d12 Mon Sep 17 00:00:00 2001
|
||||
From: "Aureau, Georges (Kernel Tools ERT)" <georges.aureau@hpe.com>
|
||||
Date: Thu, 7 May 2026 04:12:32 +0000
|
||||
Subject: [PATCH 10/39] Fix get_xtime() for kernel 6.13 and higher
|
||||
|
||||
On kernels 6.13 and higher, DATE is not displayed properly:
|
||||
crash> sys | grep -e DATE -e REL
|
||||
DATE: Wed Dec 31 18:00:00 CST 1969
|
||||
RELEASE: 7.0.0-14-generic
|
||||
|
||||
The function get_xtime() was enhanced to support:
|
||||
- kernel 6.13 ("shadow_timekeeper" moved to "struct tk_data tk_core")
|
||||
- kernel 6.17 ("tk_core" is now "timekeeper_data[0]).
|
||||
|
||||
With this get_xtime() fix:
|
||||
crash> sys | grep DATE
|
||||
DATE: Mon Apr 27 09:19:50 CDT 2026
|
||||
|
||||
Signed-off-by: Georges Aureau <georges.aureau@hpe.com>
|
||||
---
|
||||
defs.h | 1 +
|
||||
kernel.c | 14 +++++++++++++-
|
||||
2 files changed, 14 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index 6a91343f0313..89044b18cdbe 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -2290,6 +2290,7 @@ struct offset_table { /* stash of commonly-used offsets */
|
||||
long bpf_ringbuf_nr_pages;
|
||||
long hrtimer_clock_base_index;
|
||||
long klp_patch_list;
|
||||
+ long tk_data_timekeeper;
|
||||
};
|
||||
|
||||
struct size_table { /* stash of commonly-used sizes */
|
||||
diff --git a/kernel.c b/kernel.c
|
||||
index 1e639ec6a007..6dfc8714a1ff 100644
|
||||
--- a/kernel.c
|
||||
+++ b/kernel.c
|
||||
@@ -258,6 +258,7 @@ kernel_init()
|
||||
|
||||
MEMBER_OFFSET_INIT(timekeeper_xtime, "timekeeper", "xtime");
|
||||
MEMBER_OFFSET_INIT(timekeeper_xtime_sec, "timekeeper", "xtime_sec");
|
||||
+ MEMBER_OFFSET_INIT(tk_data_timekeeper, "tk_data", "timekeeper");
|
||||
get_xtime(&kt->date);
|
||||
if (CRASHDEBUG(1))
|
||||
fprintf(fp, "xtime timespec.tv_sec: %lx: %s\n",
|
||||
@@ -11134,7 +11135,18 @@ get_xtime(struct timespec *date)
|
||||
struct syment *sp;
|
||||
uint64_t xtime_sec;
|
||||
|
||||
- if (VALID_MEMBER(timekeeper_xtime) &&
|
||||
+ if (VALID_MEMBER(tk_data_timekeeper) &&
|
||||
+ VALID_MEMBER(timekeeper_xtime_sec)) {
|
||||
+ long offset = OFFSET(tk_data_timekeeper) +
|
||||
+ OFFSET(timekeeper_xtime_sec);
|
||||
+ if ((sp = kernel_symbol_search("timekeeper_data")) ||
|
||||
+ (sp = kernel_symbol_search("tk_core"))) {
|
||||
+ readmem(sp->value + offset, KVADDR,
|
||||
+ &xtime_sec, sizeof(uint64_t),
|
||||
+ "tk_data timekeeper xtime_sec", RETURN_ON_ERROR);
|
||||
+ date->tv_sec = (__time_t)xtime_sec;
|
||||
+ }
|
||||
+ } else if (VALID_MEMBER(timekeeper_xtime) &&
|
||||
(sp = kernel_symbol_search("timekeeper"))) {
|
||||
readmem(sp->value + OFFSET(timekeeper_xtime), KVADDR,
|
||||
date, sizeof(struct timespec),
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
From 3a415c07a18a465df2580365b43b4d8f8a5d815b Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Egorenkov <egorenar@linux.ibm.com>
|
||||
Date: Tue, 28 Apr 2026 12:16:37 +0200
|
||||
Subject: [PATCH 11/39] symbols: Add support for mod symtab with combined GPL
|
||||
and non-GPL symbols
|
||||
|
||||
The commit b4760ff2a5e4 ("module: deprecate usage of *_gpl sections in module loader")
|
||||
eliminated separate GPL symbol sections representing GPL only symbols.
|
||||
Therefore, depending on whether the member gpl_syms is present
|
||||
in struct module, decide whether GPL module symbols are separated or not.
|
||||
|
||||
https://lore.kernel.org/all/20260326-kflagstab-v5-4-fa0796fe88d9@google.com
|
||||
|
||||
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
|
||||
---
|
||||
kernel.c | 13 ++++++++-----
|
||||
symbols.c | 9 +++++++--
|
||||
2 files changed, 15 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/kernel.c b/kernel.c
|
||||
index 6dfc8714a1ff..eb9754c5e082 100644
|
||||
--- a/kernel.c
|
||||
+++ b/kernel.c
|
||||
@@ -3635,9 +3635,11 @@ module_init(void)
|
||||
case KMOD_V2:
|
||||
MEMBER_OFFSET_INIT(module_num_syms, "module", "num_syms");
|
||||
MEMBER_OFFSET_INIT(module_list, "module", "list");
|
||||
- MEMBER_OFFSET_INIT(module_gpl_syms, "module", "gpl_syms");
|
||||
- MEMBER_OFFSET_INIT(module_num_gpl_syms, "module",
|
||||
- "num_gpl_syms");
|
||||
+ if (MEMBER_EXISTS("module", "gpl_syms")) {
|
||||
+ MEMBER_OFFSET_INIT(module_gpl_syms, "module", "gpl_syms");
|
||||
+ MEMBER_OFFSET_INIT(module_num_gpl_syms, "module",
|
||||
+ "num_gpl_syms");
|
||||
+ }
|
||||
|
||||
if (MEMBER_EXISTS("module", "mem")) { /* 6.4 and later */
|
||||
kt->flags2 |= KMOD_MEMORY; /* MODULE_MEMORY() can be used. */
|
||||
@@ -3831,8 +3833,9 @@ module_init(void)
|
||||
nsyms = UINT(modbuf + OFFSET(module_nsyms));
|
||||
break;
|
||||
case KMOD_V2:
|
||||
- nsyms = UINT(modbuf + OFFSET(module_num_syms)) +
|
||||
- UINT(modbuf + OFFSET(module_num_gpl_syms));
|
||||
+ nsyms = UINT(modbuf + OFFSET(module_num_syms));
|
||||
+ if (VALID_MEMBER(module_num_gpl_syms))
|
||||
+ nsyms += UINT(modbuf + OFFSET(module_num_gpl_syms));
|
||||
break;
|
||||
}
|
||||
|
||||
diff --git a/symbols.c b/symbols.c
|
||||
index 8eb8b37abc23..3c62f54d4a93 100644
|
||||
--- a/symbols.c
|
||||
+++ b/symbols.c
|
||||
@@ -1979,9 +1979,14 @@ store_module_symbols_6_4(ulong total, int mods_installed)
|
||||
"module buffer", FAULT_ON_ERROR);
|
||||
|
||||
syms = ULONG(modbuf + OFFSET(module_syms));
|
||||
- gpl_syms = ULONG(modbuf + OFFSET(module_gpl_syms));
|
||||
nsyms = UINT(modbuf + OFFSET(module_num_syms));
|
||||
- ngplsyms = UINT(modbuf + OFFSET(module_num_gpl_syms));
|
||||
+ if (VALID_MEMBER(module_gpl_syms)) {
|
||||
+ gpl_syms = ULONG(modbuf + OFFSET(module_gpl_syms));
|
||||
+ ngplsyms = UINT(modbuf + OFFSET(module_num_gpl_syms));
|
||||
+ } else {
|
||||
+ gpl_syms = 0;
|
||||
+ ngplsyms = 0;
|
||||
+ }
|
||||
|
||||
nksyms = UINT(modbuf + OFFSET(module_num_symtab));
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
202
0012-add-folio_order-function.patch
Normal file
202
0012-add-folio_order-function.patch
Normal file
@ -0,0 +1,202 @@
|
||||
From 744dfa3a190d3dd2b1cc42d3378a1cb299958c0a Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <huangsj@hygon.cn>
|
||||
Date: Mon, 18 May 2026 19:31:38 +0800
|
||||
Subject: [PATCH 12/39] add folio_order function
|
||||
|
||||
The folio_order() has three versions:
|
||||
1.) In verion 1, folio_order() uses page[1].compound_order to
|
||||
get the folio order. We use "folio_batch" as the indicator.
|
||||
|
||||
Please refer to patch set:
|
||||
https://lore.kernel.org/all/20211208042256.1923824-1-willy@infradead.org/
|
||||
|
||||
2.) In version 2, the following patch introduces _folio_order:
|
||||
c3a15bff46cb5149 "mm: reimplement folio_order() and folio_nr_pages()"
|
||||
We use "_folio_order" as the indicator.
|
||||
|
||||
Please refer to patch set:
|
||||
https://lore.kernel.org/all/20220808193430.3378317-1-willy@infradead.org/
|
||||
|
||||
3.) In version 3, the following patch replaces the _folio_order with _flags_1:
|
||||
ebc1baf5c9b46c22 "mm: free up a word in the first tail page"
|
||||
folio_order() uses _flags_1 to get the folio order.
|
||||
|
||||
We use "free_huge_folio" as the indicator.
|
||||
Please refer to patch set:
|
||||
https://lore.kernel.org/linux-mm/20230816151201.3655946-1-willy@infradead.org/
|
||||
(Note, we do not use the struct modifications within the patch set as the indicator,
|
||||
since they have been removed in later kernel.)
|
||||
|
||||
This patch will be used in later patches.
|
||||
|
||||
Signed-off-by: Huang Shijie <huangsj@hygon.cn>
|
||||
---
|
||||
defs.h | 8 ++++++
|
||||
memory.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
symbols.c | 6 +++++
|
||||
3 files changed, 93 insertions(+)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index 89044b18cdbe..bd996ef38707 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -2291,6 +2291,9 @@ struct offset_table { /* stash of commonly-used offsets */
|
||||
long hrtimer_clock_base_index;
|
||||
long klp_patch_list;
|
||||
long tk_data_timekeeper;
|
||||
+ long page_compound_order;
|
||||
+ long folio__folio_order;
|
||||
+ long folio__flags_1;
|
||||
};
|
||||
|
||||
struct size_table { /* stash of commonly-used sizes */
|
||||
@@ -2470,6 +2473,9 @@ struct size_table { /* stash of commonly-used sizes */
|
||||
long cpumask_t;
|
||||
long task_struct_exit_state;
|
||||
long bpf_ringbuf_map;
|
||||
+ long page_compound_order;
|
||||
+ long folio__folio_order;
|
||||
+ long folio__flags_1;
|
||||
};
|
||||
|
||||
struct array_table {
|
||||
@@ -5998,6 +6004,8 @@ ulong do_xarray(ulong, int, struct list_pair *);
|
||||
#define XARRAY_TAG_MASK (3UL)
|
||||
#define XARRAY_TAG_INTERNAL (2UL)
|
||||
|
||||
+int folio_order(ulong folio);
|
||||
+
|
||||
int file_dump(ulong, ulong, ulong, int, int);
|
||||
#define DUMP_FULL_NAME 0x1
|
||||
#define DUMP_INODE_ONLY 0x2
|
||||
diff --git a/memory.c b/memory.c
|
||||
index 17423a588464..502f8fdd0ea7 100644
|
||||
--- a/memory.c
|
||||
+++ b/memory.c
|
||||
@@ -410,6 +410,10 @@ mem_init(void)
|
||||
DISPLAY_DEFAULT = (sizeof(long) == 8) ? DISPLAY_64 : DISPLAY_32;
|
||||
}
|
||||
|
||||
+#define FOLIO_ORDER_V1 1
|
||||
+#define FOLIO_ORDER_V2 2
|
||||
+#define FOLIO_ORDER_V3 3
|
||||
+static int folio_order_version;
|
||||
|
||||
/*
|
||||
* Stash a few popular offsets and some basic kernel virtual memory
|
||||
@@ -547,6 +551,37 @@ vm_init(void)
|
||||
MEMBER_OFFSET_INIT(page_freelist, "page", "freelist");
|
||||
MEMBER_OFFSET_INIT(page_page_type, "page", "page_type");
|
||||
|
||||
+ /*
|
||||
+ * The "folio_batch" was introduced at patch set:
|
||||
+ * https://lore.kernel.org/all/20211208042256.1923824-1-willy@infradead.org/
|
||||
+ * Use it as the indicator for folio_order() version 1.
|
||||
+ */
|
||||
+ if (STRUCT_EXISTS("folio_batch"))
|
||||
+ folio_order_version = FOLIO_ORDER_V1;
|
||||
+
|
||||
+ MEMBER_OFFSET_INIT(page_compound_order, "page", "compound_order");
|
||||
+ MEMBER_SIZE_INIT(page_compound_order, "page", "compound_order");
|
||||
+
|
||||
+ /*
|
||||
+ * The "_folio_order" was introduced at patch set:
|
||||
+ * https://lore.kernel.org/all/20220808193430.3378317-1-willy@infradead.org/
|
||||
+ * Use it as the indicator for folio_order() version 2.
|
||||
+ */
|
||||
+ MEMBER_SIZE_INIT(folio__folio_order, "folio", "_folio_order");
|
||||
+ MEMBER_OFFSET_INIT(folio__folio_order, "folio", "_folio_order");
|
||||
+ if (VALID_MEMBER(folio__folio_order))
|
||||
+ folio_order_version = FOLIO_ORDER_V2;
|
||||
+
|
||||
+ /*
|
||||
+ * The "free_huge_folio()" was introduced at patch set:
|
||||
+ * https://lore.kernel.org/linux-mm/20230816151201.3655946-1-willy@infradead.org/
|
||||
+ * Use it as the indicator for folio_order() version 3.
|
||||
+ */
|
||||
+ MEMBER_OFFSET_INIT(folio__flags_1, "folio", "_flags_1");
|
||||
+ MEMBER_SIZE_INIT(folio__flags_1, "folio", "_flags_1");
|
||||
+ if (kernel_symbol_exists("free_huge_folio"))
|
||||
+ folio_order_version = FOLIO_ORDER_V3;
|
||||
+
|
||||
MEMBER_OFFSET_INIT(mm_struct_pgd, "mm_struct", "pgd");
|
||||
|
||||
MEMBER_OFFSET_INIT(swap_info_struct_swap_file,
|
||||
@@ -20426,6 +20461,50 @@ static unsigned int oo_objects(ulong oo)
|
||||
return (oo & ((1 << 16) - 1));
|
||||
}
|
||||
|
||||
+int
|
||||
+folio_order(ulong folio)
|
||||
+{
|
||||
+ ulong v = 0;
|
||||
+ int PG_head = 16;
|
||||
+
|
||||
+ if (folio_order_version == FOLIO_ORDER_V1) {
|
||||
+ readmem(folio + OFFSET(page_flags), KVADDR, &v, sizeof(ulong),
|
||||
+ "folio.page.flags", FAULT_ON_ERROR);
|
||||
+ if (!(v & (1 << PG_head)))
|
||||
+ return 0;
|
||||
+
|
||||
+ readmem(folio + SIZE(page) + OFFSET(page_compound_order), KVADDR, &v,
|
||||
+ SIZE(page_compound_order), "page[1].compound_order", FAULT_ON_ERROR);
|
||||
+
|
||||
+ return v;
|
||||
+ } else if (folio_order_version == FOLIO_ORDER_V2) {
|
||||
+ readmem(folio + OFFSET(page_flags), KVADDR, &v, sizeof(ulong),
|
||||
+ "folio.page.flags", FAULT_ON_ERROR);
|
||||
+ if (!(v & (1 << PG_head)))
|
||||
+ return 0;
|
||||
+
|
||||
+ readmem(folio + OFFSET(folio__folio_order), KVADDR, &v,
|
||||
+ SIZE(folio__folio_order), "folio->_folio_order", FAULT_ON_ERROR);
|
||||
+
|
||||
+ return v;
|
||||
+ } else if (folio_order_version == FOLIO_ORDER_V3) {
|
||||
+ /* The PG_head changes to bit 6 in this version */
|
||||
+ PG_head = 6;
|
||||
+
|
||||
+ readmem(folio + OFFSET(page_flags), KVADDR, &v, sizeof(ulong),
|
||||
+ "folio.page.flags", FAULT_ON_ERROR);
|
||||
+ if (!(v & (1 << PG_head)))
|
||||
+ return 0;
|
||||
+
|
||||
+ readmem(folio + OFFSET(folio__flags_1), KVADDR, &v,
|
||||
+ SIZE(folio__flags_1), "folio->_flags_1", FAULT_ON_ERROR);
|
||||
+
|
||||
+ return v & 0xff;
|
||||
+ } else {
|
||||
+ return 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
#ifdef NOT_USED
|
||||
ulong
|
||||
slab_to_kmem_cache_node(struct meminfo *si, ulong slab_page)
|
||||
diff --git a/symbols.c b/symbols.c
|
||||
index 3c62f54d4a93..c0285058c5cb 100644
|
||||
--- a/symbols.c
|
||||
+++ b/symbols.c
|
||||
@@ -10462,6 +10462,9 @@ dump_offset_table(char *spec, ulong makestruct)
|
||||
fprintf(fp, " page_private: %ld\n", OFFSET(page_private));
|
||||
fprintf(fp, " page_page_type: %ld\n",
|
||||
OFFSET(page_page_type));
|
||||
+ fprintf(fp, " page_compound_order: %ld\n", OFFSET(page_compound_order));
|
||||
+ fprintf(fp, " folio__folio_order: %ld\n", OFFSET(folio__folio_order));
|
||||
+ fprintf(fp, " folio__flags_1: %ld\n", OFFSET(folio__flags_1));
|
||||
|
||||
fprintf(fp, " trace_print_flags_mask: %ld\n",
|
||||
OFFSET(trace_print_flags_mask));
|
||||
@@ -11972,6 +11975,9 @@ dump_offset_table(char *spec, ulong makestruct)
|
||||
fprintf(fp, "\n size_table:\n");
|
||||
fprintf(fp, " page: %ld\n", SIZE(page));
|
||||
fprintf(fp, " page_flags: %ld\n", SIZE(page_flags));
|
||||
+ fprintf(fp, " page_compound_order: %ld\n", SIZE(page_compound_order));
|
||||
+ fprintf(fp, " folio__folio_order: %ld\n", SIZE(folio__folio_order));
|
||||
+ fprintf(fp, " folio__flags_1: %ld\n", SIZE(folio__flags_1));
|
||||
fprintf(fp, " trace_print_flags: %ld\n", SIZE(trace_print_flags));
|
||||
fprintf(fp, " free_area_struct: %ld\n",
|
||||
SIZE(free_area_struct));
|
||||
--
|
||||
2.54.0
|
||||
|
||||
232
0013-xarray-add-large-folio-support.patch
Normal file
232
0013-xarray-add-large-folio-support.patch
Normal file
@ -0,0 +1,232 @@
|
||||
From 5d494e101bdd7d87add51d13bc1b42af8d8a151d Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <huangsj@hygon.cn>
|
||||
Date: Mon, 18 May 2026 19:31:39 +0800
|
||||
Subject: [PATCH 13/39] xarray: add large folio support
|
||||
|
||||
We may meet a large folio at two cases:
|
||||
1.) when height is 1, the real data layout may looks like this:
|
||||
--------------------------------------------
|
||||
crash> p *(struct xa_node*)0xffff889883a6a910
|
||||
$5 = {
|
||||
shift = 0 '\000',
|
||||
offset = 0 '\000',
|
||||
count = 64 '@',
|
||||
nr_values = 0 '\000',
|
||||
.................
|
||||
slots = { 0xffffea0061d21000, 0x2, 0x2, 0x2,
|
||||
0xffffea0121d85c00, 0x12, 0x12, 0x12,
|
||||
0xffffea0121d9f400, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
|
||||
0xffffea0121583800, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
|
||||
0xffffea0121833e00, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62,
|
||||
0xffffea0121eb3800, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
|
||||
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
|
||||
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
|
||||
0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
|
||||
0x82, 0x82, 0x82
|
||||
},
|
||||
.................
|
||||
}
|
||||
--------------------------------------------
|
||||
The page orders for above folios:
|
||||
0xffffea0061d21000 --> order 2
|
||||
0xffffea0121d85c00 --> order 2
|
||||
0xffffea0121d9f400 --> order 3
|
||||
0xffffea0121583800 --> order 3
|
||||
0xffffea0121833e00 --> order 3
|
||||
0xffffea0121eb3800 --> order 5
|
||||
|
||||
2.) when height is not 1, the real data layout may looks like this:
|
||||
--------------------------------------------
|
||||
slot: { 0xffff8a2c866b745a, 0xffff8a2c866b16d2, 0xfffff9fcc4ea4000, 0xfffff9fcc4eb9000, ..}
|
||||
--------------------------------------------
|
||||
The 0xffff8a2c866b745a and 0xffff8a2c866b16d2 is a internal node, not a folio.
|
||||
The page orders for above folios:
|
||||
0xfffff9fcc4ea4000 --> order 6
|
||||
|
||||
Current code does not work correctly with large folio page cache.
|
||||
This patch adds the large folio support with following:
|
||||
|
||||
1.) Add XARRAY_TYPE_PAGE_CACHE flag for do_xarray().
|
||||
2.) Add update_count hook for do_xarray_info{},
|
||||
add update_off hook for xarray_ops{}.
|
||||
3.) changed the do_xarray_iter() to check the update_off
|
||||
at proper place (height == 1 and height > 1).
|
||||
4.) Implement the folio_update_count/folio_xarray_update_off
|
||||
hooks for large folio page cache.
|
||||
|
||||
Signed-off-by: Huang Shijie <huangsj@hygon.cn>
|
||||
---
|
||||
defs.h | 5 +++++
|
||||
filesys.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
tools.c | 15 +++++++++++++--
|
||||
3 files changed, 64 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index bd996ef38707..e7e97e7d80b2 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -5689,6 +5689,9 @@ int do_radix_tree_traverse(ulong ptr, int is_root, struct radix_tree_ops *ops);
|
||||
struct xarray_ops {
|
||||
void (*entry)(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private);
|
||||
+ uint (*update_off)(ulong node, uint height, char *path, ulong index,
|
||||
+ ulong slot, uint off, ulong shift, struct xarray_ops *ops,
|
||||
+ bool *should_continue);
|
||||
uint radix;
|
||||
void *private;
|
||||
};
|
||||
@@ -6003,6 +6006,8 @@ ulong do_xarray(ulong, int, struct list_pair *);
|
||||
#define XARRAY_DUMP_CB (5)
|
||||
#define XARRAY_TAG_MASK (3UL)
|
||||
#define XARRAY_TAG_INTERNAL (2UL)
|
||||
+#define XARRAY_TYPE_PAGE_CACHE 0x8
|
||||
+extern ulong XA_CHUNK_SHIFT;
|
||||
|
||||
int folio_order(ulong folio);
|
||||
|
||||
diff --git a/filesys.c b/filesys.c
|
||||
index 34944e2739aa..35d55a543739 100644
|
||||
--- a/filesys.c
|
||||
+++ b/filesys.c
|
||||
@@ -2289,7 +2289,7 @@ dump_inode_page_cache_info(ulong inode)
|
||||
if (root_rnode)
|
||||
count = do_radix_tree(root_rnode, RADIX_TREE_DUMP_CB, &lp);
|
||||
else if (xarray)
|
||||
- count = do_xarray(xarray, XARRAY_DUMP_CB, &lp);
|
||||
+ count = do_xarray(xarray, XARRAY_DUMP_CB | XARRAY_TYPE_PAGE_CACHE, &lp);
|
||||
|
||||
if (count != nrpages)
|
||||
error(INFO, "%s page count: %ld nrpages: %ld\n",
|
||||
@@ -4217,12 +4217,46 @@ struct do_xarray_info {
|
||||
ulong maxcount;
|
||||
ulong count;
|
||||
void *data;
|
||||
+ ulong (*update_count)(ulong);
|
||||
};
|
||||
+
|
||||
+static ulong
|
||||
+folio_update_count(ulong slot)
|
||||
+{
|
||||
+ return 1 << folio_order(slot);
|
||||
+}
|
||||
+
|
||||
+static uint folio_xarray_update_off(ulong node, uint height, char *path, ulong index,
|
||||
+ ulong slot, uint off, ulong shift, struct xarray_ops *ops, bool *should_continue)
|
||||
+{
|
||||
+ uint order;
|
||||
+
|
||||
+ *should_continue = false;
|
||||
+
|
||||
+ if (height == 1) {
|
||||
+ order = folio_order(slot) % XA_CHUNK_SHIFT;
|
||||
+ return 1 << order;
|
||||
+ }
|
||||
+
|
||||
+ /* height > 1 */
|
||||
+ if ((slot & XARRAY_TAG_MASK) == 0) {
|
||||
+ ops->entry(node, slot, path, index | off, ops->private);
|
||||
+ *should_continue = true;
|
||||
+ order = folio_order(slot) % XA_CHUNK_SHIFT;
|
||||
+ return 1 << order;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
static void do_xarray_count(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private)
|
||||
{
|
||||
struct do_xarray_info *info = private;
|
||||
- info->count++;
|
||||
+
|
||||
+ if (info->update_count)
|
||||
+ info->count += info->update_count(slot);
|
||||
+ else
|
||||
+ info->count++;
|
||||
}
|
||||
static void do_xarray_search(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private)
|
||||
@@ -4239,8 +4273,9 @@ static void do_xarray_dump(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private)
|
||||
{
|
||||
struct do_xarray_info *info = private;
|
||||
+
|
||||
fprintf(fp, "[%ld] %lx\n", index, slot);
|
||||
- info->count++;
|
||||
+ do_xarray_count(node, slot, path, index, private);
|
||||
}
|
||||
static void do_xarray_gather(ulong node, ulong slot, const char *path,
|
||||
ulong index, void *private)
|
||||
@@ -4274,7 +4309,8 @@ static void do_xarray_dump_cb(ulong node, ulong slot, const char *path,
|
||||
"operation failed: entry: %ld item: %lx\n",
|
||||
info->count, slot);
|
||||
}
|
||||
- info->count++;
|
||||
+
|
||||
+ do_xarray_count(node, slot, path, index, private);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4318,7 +4354,12 @@ do_xarray(ulong root, int flag, struct list_pair *xp)
|
||||
.private = &info,
|
||||
};
|
||||
|
||||
- switch (flag)
|
||||
+ if (flag & XARRAY_TYPE_PAGE_CACHE) {
|
||||
+ info.update_count = folio_update_count;
|
||||
+ ops.update_off = folio_xarray_update_off;
|
||||
+ }
|
||||
+
|
||||
+ switch (flag & 0x7)
|
||||
{
|
||||
case XARRAY_COUNT:
|
||||
ops.entry = do_xarray_count;
|
||||
diff --git a/tools.c b/tools.c
|
||||
index 69250c48fa91..7dc11aedf56b 100644
|
||||
--- a/tools.c
|
||||
+++ b/tools.c
|
||||
@@ -4728,7 +4728,7 @@ error_height:
|
||||
return -1;
|
||||
}
|
||||
|
||||
-static ulong XA_CHUNK_SHIFT = UNINITIALIZED;
|
||||
+ulong XA_CHUNK_SHIFT = UNINITIALIZED;
|
||||
static ulong XA_CHUNK_SIZE = UNINITIALIZED;
|
||||
static ulong XA_CHUNK_MASK = UNINITIALIZED;
|
||||
|
||||
@@ -4737,21 +4737,32 @@ do_xarray_iter(ulong node, uint height, char *path,
|
||||
ulong index, struct xarray_ops *ops)
|
||||
{
|
||||
uint off;
|
||||
+ uint update_off;
|
||||
+ bool should_continue;
|
||||
|
||||
if (!hq_enter(node))
|
||||
error(FATAL,
|
||||
"\nduplicate tree node: %lx\n", node);
|
||||
|
||||
- for (off = 0; off < XA_CHUNK_SIZE; off++) {
|
||||
+ for (off = 0; off < XA_CHUNK_SIZE; off += update_off) {
|
||||
ulong slot;
|
||||
ulong shift = (height - 1) * XA_CHUNK_SHIFT;
|
||||
|
||||
+ update_off = 1;
|
||||
+
|
||||
readmem(node + OFFSET(xa_node_slots) +
|
||||
sizeof(void *) * off, KVADDR, &slot, sizeof(void *),
|
||||
"xa_node.slots[off]", FAULT_ON_ERROR);
|
||||
if (!slot)
|
||||
continue;
|
||||
|
||||
+ if (ops->update_off) {
|
||||
+ update_off = ops->update_off(node, height, path, index,
|
||||
+ slot, off, shift, ops, &should_continue);
|
||||
+ if (should_continue)
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
if ((slot & XARRAY_TAG_MASK) == XARRAY_TAG_INTERNAL)
|
||||
slot &= ~XARRAY_TAG_INTERNAL;
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
216
0014-add-files-n-command-for-an-inode.patch
Normal file
216
0014-add-files-n-command-for-an-inode.patch
Normal file
@ -0,0 +1,216 @@
|
||||
From 28889183d3f55c581b0810aa8bdac31e20bbf364 Mon Sep 17 00:00:00 2001
|
||||
From: Huang Shijie <huangsj@hygon.cn>
|
||||
Date: Mon, 18 May 2026 19:31:40 +0800
|
||||
Subject: [PATCH 14/39] add "files -n" command for an inode
|
||||
|
||||
In the NUMA machine, it is useful to know the memory distribution of
|
||||
an inode page cache:
|
||||
How many pages in the node 0?
|
||||
How many pages in the node 1?
|
||||
|
||||
Add "files -n" command to get the memory distribution information:
|
||||
1.) Add new argument for dump_inode_page_cache_info()
|
||||
2.) make page_to_nid() a global function.
|
||||
3.) Add summary_inode_page() to check each page's node
|
||||
information.
|
||||
4.) Use print_inode_summary_info() to print the
|
||||
memory distribution information of an inode.
|
||||
|
||||
Signed-off-by: Huang Shijie <huangsj@hygon.cn>
|
||||
---
|
||||
defs.h | 1 +
|
||||
filesys.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
help.c | 24 +++++++++++++++++++++-
|
||||
memory.c | 4 ++--
|
||||
4 files changed, 81 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index e7e97e7d80b2..6373ee1831af 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -5948,6 +5948,7 @@ int dump_inode_page(ulong);
|
||||
ulong valid_section_nr(ulong);
|
||||
void display_memory_from_file_offset(ulonglong, long, void *);
|
||||
void swap_info_init(void);
|
||||
+int page_to_nid(ulong);
|
||||
|
||||
/*
|
||||
* filesys.c
|
||||
diff --git a/filesys.c b/filesys.c
|
||||
index 35d55a543739..7ff47876bbb7 100644
|
||||
--- a/filesys.c
|
||||
+++ b/filesys.c
|
||||
@@ -49,7 +49,7 @@ static int match_file_string(char *, char *, char *);
|
||||
static ulong get_root_vfsmount(char *);
|
||||
static void check_live_arch_mismatch(void);
|
||||
static long get_inode_nrpages(ulong);
|
||||
-static void dump_inode_page_cache_info(ulong);
|
||||
+static void dump_inode_page_cache_info(ulong, void *callback);
|
||||
|
||||
#define DENTRY_CACHE (20)
|
||||
#define INODE_CACHE (20)
|
||||
@@ -2240,8 +2240,38 @@ get_inode_nrpages(ulong i_mapping)
|
||||
return nrpages;
|
||||
}
|
||||
|
||||
+/* Used to collect the numa information for an inode */
|
||||
+static ulong *numa_node;
|
||||
+
|
||||
static void
|
||||
-dump_inode_page_cache_info(ulong inode)
|
||||
+print_inode_summary_info(void)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ fprintf(fp, " NODE PAGES\n");
|
||||
+ for (i = 0; i < vt->numnodes; i++)
|
||||
+ fprintf(fp, " %2d %8ld\n", i, numa_node[i]);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+summary_inode_page(ulong page)
|
||||
+{
|
||||
+ int node;
|
||||
+
|
||||
+ if (!is_page_ptr(page, NULL))
|
||||
+ error(FATAL, "Invalid inode page(0x%lx)\n", page);
|
||||
+
|
||||
+ node = page_to_nid(page);
|
||||
+ if (node < 0 || node >= vt->numnodes)
|
||||
+ error(FATAL, "Invalid node(%d) for page(0x%lx)\n", node, page);
|
||||
+
|
||||
+ numa_node[node] += 1 << folio_order(page);
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+dump_inode_page_cache_info(ulong inode, void *callback)
|
||||
{
|
||||
char *inode_buf;
|
||||
ulong i_mapping, nrpages, root_rnode, xarray, count;
|
||||
@@ -2284,7 +2314,7 @@ dump_inode_page_cache_info(ulong inode)
|
||||
root_rnode = i_mapping + OFFSET(address_space_page_tree);
|
||||
|
||||
lp.index = 0;
|
||||
- lp.value = (void *)&dump_inode_page;
|
||||
+ lp.value = callback;
|
||||
|
||||
if (root_rnode)
|
||||
count = do_radix_tree(root_rnode, RADIX_TREE_DUMP_CB, &lp);
|
||||
@@ -2324,7 +2354,7 @@ cmd_files(void)
|
||||
ref = NULL;
|
||||
refarg = NULL;
|
||||
|
||||
- while ((c = getopt(argcnt, args, "d:R:p:c")) != EOF) {
|
||||
+ while ((c = getopt(argcnt, args, "d:n:R:p:c")) != EOF) {
|
||||
switch(c)
|
||||
{
|
||||
case 'R':
|
||||
@@ -2343,11 +2373,31 @@ cmd_files(void)
|
||||
display_dentry_info(value);
|
||||
return;
|
||||
|
||||
+ case 'n':
|
||||
+ if (VALID_MEMBER(address_space_page_tree) &&
|
||||
+ VALID_MEMBER(inode_i_mapping)) {
|
||||
+ value = htol(optarg, FAULT_ON_ERROR, NULL);
|
||||
+
|
||||
+ /* Allocate the array for this inode */
|
||||
+ numa_node = (ulong *)GETBUF(sizeof(ulong) * vt->numnodes);
|
||||
+ BZERO(numa_node, sizeof(ulong) * vt->numnodes);
|
||||
+
|
||||
+ dump_inode_page_cache_info(value, (void *)&summary_inode_page);
|
||||
+
|
||||
+ /* Print out the NUMA node information for this inode */
|
||||
+ print_inode_summary_info();
|
||||
+
|
||||
+ FREEBUF(numa_node);
|
||||
+ numa_node = NULL;
|
||||
+ } else
|
||||
+ option_not_supported('n');
|
||||
+ return;
|
||||
+
|
||||
case 'p':
|
||||
if (VALID_MEMBER(address_space_page_tree) &&
|
||||
VALID_MEMBER(inode_i_mapping)) {
|
||||
value = htol(optarg, FAULT_ON_ERROR, NULL);
|
||||
- dump_inode_page_cache_info(value);
|
||||
+ dump_inode_page_cache_info(value, (void *)&dump_inode_page);
|
||||
} else
|
||||
option_not_supported('p');
|
||||
return;
|
||||
diff --git a/help.c b/help.c
|
||||
index 810075b97f35..5cd5c30e99a3 100644
|
||||
--- a/help.c
|
||||
+++ b/help.c
|
||||
@@ -7900,7 +7900,7 @@ NULL
|
||||
char *help_files[] = {
|
||||
"files",
|
||||
"open files",
|
||||
-"[-d dentry] | [-p inode] | [-c] [-R reference] [pid | taskp] ... ",
|
||||
+"[-d dentry] | [-p inode] | [-n inode]|[-c] [-R reference] [pid | taskp] ... ",
|
||||
" This command displays information about open files of a context.",
|
||||
" It prints the context's current root directory and current working",
|
||||
" directory, and then for each open file descriptor it prints a pointer",
|
||||
@@ -7915,6 +7915,8 @@ char *help_files[] = {
|
||||
" super block, file type, and full pathname.",
|
||||
" -p inode given a hexadecimal inode address, dump all of its pages",
|
||||
" that are in the page cache.",
|
||||
+" -n inode given a hexadecimal inode address, check all the pages",
|
||||
+" in the page cache, and display a NUMA node distribution.",
|
||||
" -c for each open file descriptor, prints a pointer to its",
|
||||
" inode, a pointer to the inode's i_mapping address_space",
|
||||
" structure, the number of pages of the inode that are in",
|
||||
@@ -8024,6 +8026,26 @@ char *help_files[] = {
|
||||
" ca1ddde0 2eeef000 f59b91ac 3 2 82c referenced,uptodate,lru,private",
|
||||
" ca36b300 3b598000 f59b91ac 4 2 82c referenced,uptodate,lru,private",
|
||||
" ca202680 30134000 f59b91ac 5 2 82c referenced,uptodate,lru,private",
|
||||
+" ",
|
||||
+" For the inode at address ffff8898857c55a8, display the NUMA node",
|
||||
+" distribution of its pages that are in the page cache:",
|
||||
+" %s> files -n ffff8898857c55a8",
|
||||
+" INODE NRPAGES",
|
||||
+" ffff8898857c55a8 51748",
|
||||
+" ",
|
||||
+" NODE PAGES",
|
||||
+" 0 51536",
|
||||
+" 1 0",
|
||||
+" 2 0",
|
||||
+" 3 0",
|
||||
+" 4 0",
|
||||
+" 5 212",
|
||||
+" 6 0",
|
||||
+" 7 0",
|
||||
+" 8 0",
|
||||
+" 9 0",
|
||||
+" 10 0",
|
||||
+" 11 0",
|
||||
" ",
|
||||
NULL
|
||||
};
|
||||
diff --git a/memory.c b/memory.c
|
||||
index 502f8fdd0ea7..38c6a139e984 100644
|
||||
--- a/memory.c
|
||||
+++ b/memory.c
|
||||
@@ -301,7 +301,7 @@ static int dump_vm_event_state(void);
|
||||
static int dump_page_states(void);
|
||||
static int generic_read_dumpfile(ulonglong, void *, long, char *, ulong);
|
||||
static int generic_write_dumpfile(ulonglong, void *, long, char *, ulong);
|
||||
-static int page_to_nid(ulong);
|
||||
+int page_to_nid(ulong);
|
||||
static int get_kmem_cache_list(ulong **);
|
||||
static int get_kmem_cache_root_list(ulong **);
|
||||
static int get_kmem_cache_child_list(ulong **, ulong);
|
||||
@@ -20093,7 +20093,7 @@ is_kmem_cache_addr_common(ulong vaddr, char *kbuf)
|
||||
/*
|
||||
* Kernel-config-neutral page-to-node evaluator.
|
||||
*/
|
||||
-static int
|
||||
+int
|
||||
page_to_nid(ulong page)
|
||||
{
|
||||
int i;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
178
0015-x86_64-Fix-bt-command-for-noreturn-functions.patch
Normal file
178
0015-x86_64-Fix-bt-command-for-noreturn-functions.patch
Normal file
@ -0,0 +1,178 @@
|
||||
From 7b3f6e0f60be1dd2d4c1b20175be96137cf61438 Mon Sep 17 00:00:00 2001
|
||||
From: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
Date: Fri, 29 May 2026 05:00:03 +0000
|
||||
Subject: [PATCH 15/39] x86_64: Fix "bt" command for noreturn functions
|
||||
|
||||
On x86_64, the "bt" command resolves saved return addresses with
|
||||
value_search(textaddr). However, a return address is the instruction
|
||||
pointer after the call, not the call site itself.
|
||||
|
||||
This becomes a problem when the caller ends with a call to a noreturn
|
||||
function. In that case, the saved return address can match the start
|
||||
address of the following symbol, and "bt" loses track of the call chain
|
||||
and this can lead to very long session initialization.
|
||||
|
||||
The same issue also affects symbol+offset formatting, line number
|
||||
lookup, and ORC-based frame size resolution.
|
||||
|
||||
Fix it by resolving normal backtrace return addresses with textaddr-1,
|
||||
while keeping exact textaddr handling for real RIP values saved in
|
||||
exception frames. Add value_to_symstr_trace() so the displayed
|
||||
symbol+offset still reflects the original return address value.
|
||||
|
||||
Suggested-by: Kosuke Tatsukawa <tatsu-ab1@nec.com>
|
||||
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
---
|
||||
defs.h | 1 +
|
||||
symbols.c | 24 +++++++++++++++++++++---
|
||||
x86_64.c | 31 ++++++++++++++++++++++++++-----
|
||||
3 files changed, 48 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index 6373ee1831af..4a42bc962817 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -5807,6 +5807,7 @@ struct syment *prev_symbol(char *, struct syment *);
|
||||
void get_symbol_data(char *, long, void *);
|
||||
int try_get_symbol_data(char *, long, void *);
|
||||
char *value_to_symstr(ulong, char *, ulong);
|
||||
+char *value_to_symstr_trace(ulong, char *, ulong);
|
||||
char *value_symbol(ulong);
|
||||
ulong symbol_value(char *);
|
||||
ulong symbol_value_module(char *, char *);
|
||||
diff --git a/symbols.c b/symbols.c
|
||||
index c0285058c5cb..78e400ba3756 100644
|
||||
--- a/symbols.c
|
||||
+++ b/symbols.c
|
||||
@@ -104,6 +104,7 @@ static void free_structure(struct struct_elem *);
|
||||
static unsigned char is_right_brace(const char *);
|
||||
static struct struct_elem *find_node(struct struct_elem *, char *);
|
||||
static void dump_node(struct struct_elem *, char *, unsigned char, unsigned char);
|
||||
+static char *_value_to_symstr(ulong value, char *buf, ulong radix, int trace);
|
||||
|
||||
static int module_mem_type(ulong, struct load_module *);
|
||||
static ulong module_mem_end(ulong, struct load_module *);
|
||||
@@ -5973,14 +5974,25 @@ generic_machdep_value_to_symbol(ulong value, ulong *offset)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+char *
|
||||
+value_to_symstr(ulong value, char *buf, ulong radix)
|
||||
+{
|
||||
+ return _value_to_symstr(value, buf, radix, 0);
|
||||
+}
|
||||
+
|
||||
+char *
|
||||
+value_to_symstr_trace(ulong value, char *buf, ulong radix)
|
||||
+{
|
||||
+ return _value_to_symstr(value, buf, radix, 1);
|
||||
+}
|
||||
|
||||
/*
|
||||
* For a given value, format a string containing the nearest symbol name
|
||||
* plus the offset if appropriate. Display the offset in the specified
|
||||
* radix (10 or 16) -- if it's 0, set it to the current pc->output_radix.
|
||||
*/
|
||||
-char *
|
||||
-value_to_symstr(ulong value, char *buf, ulong radix)
|
||||
+static char *
|
||||
+_value_to_symstr(ulong value, char *buf, ulong radix, int trace)
|
||||
{
|
||||
struct syment *sp;
|
||||
ulong offset;
|
||||
@@ -5996,7 +6008,13 @@ value_to_symstr(ulong value, char *buf, ulong radix)
|
||||
if ((radix != 10) && (radix != 16))
|
||||
radix = 16;
|
||||
|
||||
- if ((sp = value_search(value, &offset))) {
|
||||
+ if (trace) {
|
||||
+ sp = value_search(value-1, &offset);
|
||||
+ offset++;
|
||||
+ } else
|
||||
+ sp = value_search(value, &offset);
|
||||
+
|
||||
+ if (sp) {
|
||||
if (offset)
|
||||
sprintf(buf, radix == 16 ? "%s+0x%lx" : "%s+%ld",
|
||||
sp->name, offset);
|
||||
diff --git a/x86_64.c b/x86_64.c
|
||||
index b2cddbf8ba3d..ff283ed68191 100644
|
||||
--- a/x86_64.c
|
||||
+++ b/x86_64.c
|
||||
@@ -3229,14 +3229,23 @@ x86_64_print_stack_entry(struct bt_info *bt, FILE *ofp, int level,
|
||||
if (!(bt->flags & BT_SAVE_EFRAME_IP))
|
||||
bt->eframe_ip = 0;
|
||||
offset = 0;
|
||||
- sp = value_search(text, &offset);
|
||||
+ if (bt->flags & BT_SAVE_EFRAME_IP)
|
||||
+ sp = value_search(text, &offset);
|
||||
+ else {
|
||||
+ sp = value_search(text-1, &offset);
|
||||
+ offset++;
|
||||
+ }
|
||||
if (!sp)
|
||||
return BACKTRACE_ENTRY_IGNORED;
|
||||
|
||||
name = sp->name;
|
||||
|
||||
if (offset && (bt->flags & BT_SYMBOL_OFFSET))
|
||||
- name_plus_offset = value_to_symstr(text, buf2, bt->radix);
|
||||
+ if (bt->flags & BT_SAVE_EFRAME_IP)
|
||||
+ name_plus_offset = value_to_symstr(text, buf2, bt->radix);
|
||||
+ else
|
||||
+ /* text-1 is used in the function */
|
||||
+ name_plus_offset = value_to_symstr_trace(text, buf2, bt->radix);
|
||||
else
|
||||
name_plus_offset = NULL;
|
||||
|
||||
@@ -3337,7 +3346,10 @@ x86_64_print_stack_entry(struct bt_info *bt, FILE *ofp, int level,
|
||||
fprintf(ofp, "\n");
|
||||
|
||||
if (bt->flags & BT_LINE_NUMBERS) {
|
||||
- get_line_number(text, buf1, FALSE);
|
||||
+ if (bt->flags & BT_SAVE_EFRAME_IP)
|
||||
+ get_line_number(text, buf1, FALSE);
|
||||
+ else
|
||||
+ get_line_number(text-1, buf1, FALSE);
|
||||
if (strlen(buf1))
|
||||
fprintf(ofp, " %s\n", buf1);
|
||||
}
|
||||
@@ -3864,8 +3876,10 @@ in_exception_stack:
|
||||
}
|
||||
|
||||
level++;
|
||||
+ bt->flags |= BT_SAVE_EFRAME_IP;
|
||||
if ((framesize = x86_64_get_framesize(bt, bt->instptr, rsp, NULL)) >= 0)
|
||||
rsp += framesize;
|
||||
+ bt->flags &= ~BT_SAVE_EFRAME_IP;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8811,7 +8825,13 @@ x86_64_get_framesize(struct bt_info *bt, ulong textaddr, ulong rsp, char *stack_
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (!(sp = value_search(textaddr, &offset))) {
|
||||
+ if (bt->flags & BT_SAVE_EFRAME_IP)
|
||||
+ sp = value_search(textaddr, &offset);
|
||||
+ else {
|
||||
+ sp = value_search(textaddr-1, &offset);
|
||||
+ offset++;
|
||||
+ }
|
||||
+ if (!sp) {
|
||||
if (!(bt->flags & BT_FRAMESIZE_DEBUG))
|
||||
bt->flags |= BT_FRAMESIZE_DISABLE;
|
||||
return 0;
|
||||
@@ -8887,7 +8907,8 @@ x86_64_get_framesize(struct bt_info *bt, ulong textaddr, ulong rsp, char *stack_
|
||||
if ((sp->value >= kt->init_begin) && (sp->value < kt->init_end))
|
||||
return 0;
|
||||
|
||||
- if ((machdep->flags & ORC) && (korc = orc_find(textaddr))) {
|
||||
+ if ((machdep->flags & ORC) &&
|
||||
+ (korc = orc_find(bt->flags & BT_SAVE_EFRAME_IP ? textaddr : textaddr-1))) {
|
||||
if (CRASHDEBUG(1)) {
|
||||
struct ORC_data *orc = &machdep->machspec->orc;
|
||||
fprintf(fp,
|
||||
--
|
||||
2.54.0
|
||||
|
||||
100
0016-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch
Normal file
100
0016-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch
Normal file
@ -0,0 +1,100 @@
|
||||
From d0ee428664f90beaf498fa0edc129cdead204abc Mon Sep 17 00:00:00 2001
|
||||
From: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
Date: Mon, 1 Jun 2026 05:38:11 +0000
|
||||
Subject: [PATCH 16/39] x86_64: Fix "bt" command to use correct ORC register
|
||||
values on Linux 7.1 and later
|
||||
|
||||
Kernel commit 1735858caa4b ("objtool/x86: Reorder ORC register numbering")
|
||||
changed the ORC register numbering. Without the patch, crash can interpret ORC
|
||||
entry incorrectly and the "bt" command may generate broken backtraces on Linux
|
||||
7.1 and later kernels like this:
|
||||
|
||||
crash> bt 1
|
||||
PID: 1 TASK: ffff8ab0009cd100 CPU: 2 COMMAND: "systemd"
|
||||
#0 [ffffd2218003b9c8] __schedule at ffffffffaa9d862b
|
||||
#1 [ffffd2218003ba20] schedule at ffffffffaa9d8993
|
||||
#2 [ffffd2218003ba30] schedule_hrtimeout_range_clock at ffffffffaa9df77b
|
||||
#3 [ffffd2218003bab0] ep_poll at ffffffffaa1231e4
|
||||
#4 [ffffd2218003bb50] do_epoll_wait at ffffffffaa123272
|
||||
#5 [ffffd2218003bb88] __x64_sys_epoll_wait at ffffffffaa123b1f
|
||||
#6 [ffffd2218003bbd8] do_syscall_64 at ffffffffaa9cca6c
|
||||
#7 [ffffd2218003bc58] __memcg_slab_free_hook at ffffffffaa079da3
|
||||
#8 [ffffd2218003bcf0] __memcg_slab_free_hook at ffffffffaa079da3
|
||||
#9 [ffffd2218003bd50] __x64_sys_gettid at ffffffffa9ce1656
|
||||
#10 [ffffd2218003bd58] do_syscall_64 at ffffffffaa9ccaa4
|
||||
#11 [ffffd2218003bdc0] update_cfs_rq_load_avg at ffffffffa9d1bf59
|
||||
#12 [ffffd2218003be00] __update_blocked_fair at ffffffffa9d214b8
|
||||
#13 [ffffd2218003be70] sched_clock at ffffffffa9c460dc
|
||||
#14 [ffffd2218003be78] sched_clock_cpu at ffffffffa9d4aeab
|
||||
#15 [ffffd2218003be98] irqtime_account_irq at ffffffffa9d3af0d
|
||||
#16 [ffffd2218003bec0] handle_softirqs at ffffffffa9cce5ac
|
||||
#17 [ffffd2218003bf40] entry_SYSCALL_64_after_hwframe at ffffffffa9a0012b
|
||||
|
||||
Fix this by making ORC_REG_SP and ORC_REG_PREV_SP depend on kernel version, as
|
||||
no other way was found.
|
||||
|
||||
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
---
|
||||
defs.h | 6 ++++--
|
||||
x86_64.c | 11 +++++++++++
|
||||
2 files changed, 15 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index 4a42bc962817..a4f70b773cd7 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -6650,6 +6650,8 @@ struct ORC_data {
|
||||
orc_entry orc_entry_data;
|
||||
int has_signal;
|
||||
int has_end;
|
||||
+ int reg_sp;
|
||||
+ int reg_prev_sp;
|
||||
};
|
||||
|
||||
#define ORC_TYPE_CALL ((machdep->flags & ORC_6_4) ? 2 : 0)
|
||||
@@ -6660,11 +6662,11 @@ struct ORC_data {
|
||||
#define UNWIND_HINT_TYPE_RESTORE 4
|
||||
|
||||
#define ORC_REG_UNDEFINED 0
|
||||
-#define ORC_REG_PREV_SP 1
|
||||
+#define ORC_REG_PREV_SP (machdep->machspec->orc.reg_prev_sp)
|
||||
#define ORC_REG_DX 2
|
||||
#define ORC_REG_DI 3
|
||||
#define ORC_REG_BP 4
|
||||
-#define ORC_REG_SP 5
|
||||
+#define ORC_REG_SP (machdep->machspec->orc.reg_sp)
|
||||
#define ORC_REG_R10 6
|
||||
#define ORC_REG_R13 7
|
||||
#define ORC_REG_BP_INDIRECT 8
|
||||
diff --git a/x86_64.c b/x86_64.c
|
||||
index ff283ed68191..55648697baf3 100644
|
||||
--- a/x86_64.c
|
||||
+++ b/x86_64.c
|
||||
@@ -999,6 +999,8 @@ x86_64_dump_machdep_table(ulong arg)
|
||||
fprintf(fp, " module_ORC: %s\n", ms->orc.module_ORC ? "TRUE" : "FALSE");
|
||||
fprintf(fp, " has_signal: %s\n", ms->orc.has_signal ? "TRUE" : "FALSE");
|
||||
fprintf(fp, " has_end: %s\n", ms->orc.has_end ? "TRUE" : "FALSE");
|
||||
+ fprintf(fp, " reg_sp: %d\n", ms->orc.reg_sp);
|
||||
+ fprintf(fp, " reg_prev_sp: %d\n", ms->orc.reg_prev_sp);
|
||||
fprintf(fp, " lookup_num_blocks: %d\n", ms->orc.lookup_num_blocks);
|
||||
fprintf(fp, " __start_orc_unwind_ip: %lx\n", ms->orc.__start_orc_unwind_ip);
|
||||
fprintf(fp, " __stop_orc_unwind_ip: %lx\n", ms->orc.__stop_orc_unwind_ip);
|
||||
@@ -6734,6 +6736,15 @@ x86_64_ORC_init(void)
|
||||
if (orc->has_signal && !orc->has_end)
|
||||
machdep->flags |= ORC_6_4;
|
||||
|
||||
+ /* See kernel commit 1735858caa4b */
|
||||
+ if (THIS_KERNEL_VERSION >= LINUX(7,1,0)) {
|
||||
+ ORC_REG_SP = 3;
|
||||
+ ORC_REG_PREV_SP = 8;
|
||||
+ } else {
|
||||
+ ORC_REG_SP = 5;
|
||||
+ ORC_REG_PREV_SP = 1;
|
||||
+ }
|
||||
+
|
||||
machdep->flags |= ORC;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
From c894f05d3cdc5d3e61775c3f67bd6a0a24362a92 Mon Sep 17 00:00:00 2001
|
||||
From: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
Date: Wed, 3 Jun 2026 07:12:57 +0000
|
||||
Subject: [PATCH 17/39] Fix "kmem -i" option to display swap usage on Linux
|
||||
6.18 and later
|
||||
|
||||
Kernel commit 8578e0c00dcf ("mm, swap: use the swap table to track the
|
||||
swap count"), which is contained in Linux 6.18 and later kernels,
|
||||
removed swapper_spaces symbol.
|
||||
|
||||
As a result, "kmem -i" skips swap usage output because the existing
|
||||
check only looks for swapper_space/swapper_spaces.
|
||||
|
||||
Also check for the swap_info symbol so dump_swap_info() is called on
|
||||
newer kernels as well.
|
||||
|
||||
Signed-off-by: Kazuhito Hagko <k-hagio-ab@nec.com>
|
||||
---
|
||||
memory.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/memory.c b/memory.c
|
||||
index 38c6a139e984..15946c58eaf2 100644
|
||||
--- a/memory.c
|
||||
+++ b/memory.c
|
||||
@@ -8871,7 +8871,8 @@ dump_kmeminfo(struct meminfo *mi)
|
||||
* get swap data from dump_swap_info().
|
||||
*/
|
||||
fprintf(fp, "\n");
|
||||
- if (symbol_exists("swapper_space") || symbol_exists("swapper_spaces")) {
|
||||
+ if (symbol_exists("swap_info") ||
|
||||
+ symbol_exists("swapper_space") || symbol_exists("swapper_spaces")) {
|
||||
if (dump_swap_info(RETURN_ON_ERROR, &totalswap_pages,
|
||||
&totalused_pages)) {
|
||||
fprintf(fp, "%13s %7ld %11s ----\n",
|
||||
--
|
||||
2.54.0
|
||||
|
||||
51
0018-Fix-swap-command-on-Linux-7.1-and-later.patch
Normal file
51
0018-Fix-swap-command-on-Linux-7.1-and-later.patch
Normal file
@ -0,0 +1,51 @@
|
||||
From fdb94ed20ac85e8354224b0d691af342f4b63922 Mon Sep 17 00:00:00 2001
|
||||
From: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
Date: Wed, 3 Jun 2026 07:12:58 +0000
|
||||
Subject: [PATCH 18/39] Fix "swap" command on Linux 7.1 and later
|
||||
|
||||
Kernel commit 0d6af9bcf383 ("mm, swap: use the swap table to track the
|
||||
swap count"), which is contained in Linux 7.1 and later kernels, removed
|
||||
swap_info_struct.swap_map member.
|
||||
|
||||
As a result, the "swap" command and "kmem -i" option fail with the
|
||||
following error:
|
||||
|
||||
swap: invalid structure member offset: swap_info_struct_swap_map
|
||||
FILE: memory.c LINE: 16293 FUNCTION: dump_swap_info()
|
||||
|
||||
Fix it by referencing swap_info_struct.swap_map only for SWAPINFO_V1,
|
||||
where it is actually needed. Newer kernels no longer have that member,
|
||||
and the command can use the existing inuse_pages handling instead.
|
||||
|
||||
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
---
|
||||
memory.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/memory.c b/memory.c
|
||||
index 15946c58eaf2..3f3aa274ab5a 100644
|
||||
--- a/memory.c
|
||||
+++ b/memory.c
|
||||
@@ -16290,9 +16290,6 @@ dump_swap_info(ulong swapflags, ulong *totalswap_pages, ulong *totalused_pages)
|
||||
OFFSET(swap_info_struct_inuse_pages));
|
||||
}
|
||||
|
||||
- swap_map = ULONG(vt->swap_info_struct +
|
||||
- OFFSET(swap_info_struct_swap_map));
|
||||
-
|
||||
if (swap_file) {
|
||||
if (VALID_MEMBER(swap_info_struct_swap_vfsmnt)) {
|
||||
vfsmnt = ULONG(vt->swap_info_struct +
|
||||
@@ -16322,6 +16319,9 @@ dump_swap_info(ulong swapflags, ulong *totalswap_pages, ulong *totalused_pages)
|
||||
if (vt->flags & SWAPINFO_V1) {
|
||||
smap = (ushort *)GETBUF(sizeof(ushort) * max);
|
||||
|
||||
+ swap_map = ULONG(vt->swap_info_struct +
|
||||
+ OFFSET(swap_info_struct_swap_map));
|
||||
+
|
||||
if (!readmem(swap_map, KVADDR, smap,
|
||||
sizeof(ushort) * max, "swap_info swap_map data",
|
||||
RETURN_ON_ERROR|QUIET)) {
|
||||
--
|
||||
2.54.0
|
||||
|
||||
115
0019-LoongArch64-Fix-CPU-registers-reading-from-dump-note.patch
Normal file
115
0019-LoongArch64-Fix-CPU-registers-reading-from-dump-note.patch
Normal file
@ -0,0 +1,115 @@
|
||||
From 32ac79ead77839e6a87657edfdccffa943c6ea19 Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Thu, 4 Jun 2026 19:52:40 +0800
|
||||
Subject: [PATCH 19/39] LoongArch64: Fix CPU registers reading from dump notes
|
||||
|
||||
LoongArch stores the register set exported in NT_PRSTATUS as an
|
||||
elf_gregset_t. The special registers are laid out as orig_a0, csr_era,
|
||||
csr_badvaddr, csr_crmd, csr_prmd, csr_euen, csr_ecfg and csr_estat
|
||||
after the 32 GPRs.
|
||||
|
||||
The old crash-local register layout put csr_crmd at the first
|
||||
special-register slot and placed epc near the end. That made help -r
|
||||
and active-task unwinding read nonsensical CSR values from dump notes.
|
||||
|
||||
Match the local register structure and indexes to the kernel
|
||||
pt_regs/elf_gregset_t layout. Also handle modern kernels where
|
||||
crash_notes may refer to the per-cpu note storage directly, and use
|
||||
NETDUMP ELF notes for libvirt/QEMU dump files when crash_notes does not
|
||||
provide usable data.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
loongarch64.c | 38 +++++++++++++++++++++++---------------
|
||||
1 file changed, 23 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index 6437c4aa4656..5adb7d8038db 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -18,20 +18,23 @@
|
||||
#include <elf.h>
|
||||
#include "defs.h"
|
||||
|
||||
-/* from arch/loongarch/include/asm/ptrace.h */
|
||||
+/*
|
||||
+ * This matches the beginning of both kernel struct pt_regs and the
|
||||
+ * elf_gregset_t layout exported in NT_PRSTATUS notes.
|
||||
+ */
|
||||
struct loongarch64_pt_regs {
|
||||
/* Saved main processor registers. */
|
||||
unsigned long regs[32];
|
||||
|
||||
/* Saved special registers. */
|
||||
+ unsigned long orig_a0;
|
||||
+ unsigned long csr_epc;
|
||||
+ unsigned long csr_badvaddr;
|
||||
unsigned long csr_crmd;
|
||||
unsigned long csr_prmd;
|
||||
unsigned long csr_euen;
|
||||
unsigned long csr_ecfg;
|
||||
unsigned long csr_estat;
|
||||
- unsigned long csr_epc;
|
||||
- unsigned long csr_badvaddr;
|
||||
- unsigned long orig_a0;
|
||||
};
|
||||
|
||||
struct loongarch64_unwind_frame {
|
||||
@@ -108,13 +111,14 @@ typedef struct { ulong pte; } pte_t;
|
||||
#define LOONGARCH64_EF_RA 1
|
||||
#define LOONGARCH64_EF_SP 3
|
||||
#define LOONGARCH64_EF_FP 22
|
||||
-#define LOONGARCH64_EF_CSR_EPC 32
|
||||
-#define LOONGARCH64_EF_CSR_BADVADDR 33
|
||||
-#define LOONGARCH64_EF_CSR_CRMD 34
|
||||
-#define LOONGARCH64_EF_CSR_PRMD 35
|
||||
-#define LOONGARCH64_EF_CSR_EUEN 36
|
||||
-#define LOONGARCH64_EF_CSR_ECFG 37
|
||||
-#define LOONGARCH64_EF_CSR_ESTAT 38
|
||||
+#define LOONGARCH64_EF_ORIG_A0 32
|
||||
+#define LOONGARCH64_EF_CSR_EPC 33
|
||||
+#define LOONGARCH64_EF_CSR_BADVADDR 34
|
||||
+#define LOONGARCH64_EF_CSR_CRMD 35
|
||||
+#define LOONGARCH64_EF_CSR_PRMD 36
|
||||
+#define LOONGARCH64_EF_CSR_EUEN 37
|
||||
+#define LOONGARCH64_EF_CSR_ECFG 38
|
||||
+#define LOONGARCH64_EF_CSR_ESTAT 39
|
||||
|
||||
static struct machine_specific loongarch64_machine_specific = { 0 };
|
||||
|
||||
@@ -911,8 +915,12 @@ loongarch64_get_crash_notes(void)
|
||||
/*
|
||||
* Add __per_cpu_offset for each cpu to form the pointer to the notes
|
||||
*/
|
||||
- for (i = 0; i < kt->cpus; i++)
|
||||
- notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i];
|
||||
+ for (i = 0; i < kt->cpus; i++) {
|
||||
+ if (IS_KVADDR(notes_ptrs[kt->cpus-1]))
|
||||
+ notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i];
|
||||
+ else
|
||||
+ notes_ptrs[i] = crash_notes + kt->__per_cpu_offset[i];
|
||||
+ }
|
||||
}
|
||||
|
||||
buf = GETBUF(SIZE(note_buf));
|
||||
@@ -1009,7 +1017,7 @@ loongarch64_get_elf_notes(void)
|
||||
struct machine_specific *ms = machdep->machspec;
|
||||
int i;
|
||||
|
||||
- if (!DISKDUMP_DUMPFILE() && !KDUMP_DUMPFILE())
|
||||
+ if (!DISKDUMP_DUMPFILE() && !KDUMP_DUMPFILE() && !NETDUMP_DUMPFILE())
|
||||
return FALSE;
|
||||
|
||||
panic_task_regs = calloc(kt->cpus, sizeof(*panic_task_regs));
|
||||
@@ -1022,7 +1030,7 @@ loongarch64_get_elf_notes(void)
|
||||
|
||||
if (DISKDUMP_DUMPFILE())
|
||||
note = diskdump_get_prstatus_percpu(i);
|
||||
- else if (KDUMP_DUMPFILE())
|
||||
+ else if (KDUMP_DUMPFILE() || NETDUMP_DUMPFILE())
|
||||
note = netdump_get_prstatus_percpu(i);
|
||||
|
||||
if (!note) {
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
From a6817d475c753f44d10bd5709be1d455768d496a Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Thu, 4 Jun 2026 19:52:41 +0800
|
||||
Subject: [PATCH 20/39] LoongArch64: Fix pt_regs initialization for active
|
||||
tasks
|
||||
|
||||
The offset of pt_regs.regs was missing, which prevented crash from
|
||||
falling back to real-time CPU registers for the active task. Initialize
|
||||
it correctly during architecture initialization.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
loongarch64.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index 5adb7d8038db..92481f3235b6 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -761,6 +761,8 @@ loongarch64_stackframe_init(void)
|
||||
|
||||
ASSIGN_OFFSET(task_struct_thread_reg03) =
|
||||
task_struct_thread + thread_reg03_sp;
|
||||
+ MEMBER_OFFSET_INIT(pt_regs_regs, "pt_regs", "regs");
|
||||
+ STRUCT_SIZE_INIT(pt_regs, "pt_regs");
|
||||
ASSIGN_OFFSET(task_struct_thread_reg01) =
|
||||
task_struct_thread + thread_reg01_ra;
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
From f3a02a49653b179a43b07a0befb82934af8ac542 Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Thu, 4 Jun 2026 19:52:42 +0800
|
||||
Subject: [PATCH 21/39] LoongArch64: Support backtracing across exception
|
||||
boundaries
|
||||
|
||||
LoongArch exception and syscall entry code saves pt_regs on the kernel
|
||||
stack before calling the C handlers. When a backtrace reaches one of
|
||||
these entry symbols, crash needs to recover the saved pt_regs and
|
||||
continue unwinding from the interrupted context.
|
||||
|
||||
Recognize the LoongArch entry symbols that leave a saved pt_regs at sp,
|
||||
including syscall, exception, interrupt-vector and TLB page-fault paths
|
||||
used by current upstream kernels and existing Loongnix variants. This
|
||||
prevents backtraces from stopping at the first entry frame and allows
|
||||
crash to print the saved pt_regs context without treating ordinary
|
||||
handler call frames as exception frames.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
loongarch64.c | 26 +++++++++++++++++++++++++-
|
||||
1 file changed, 25 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index 92481f3235b6..3ec184c908f8 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -707,7 +707,31 @@ loongarch64_is_exception_entry(struct syment *sym)
|
||||
return STREQ(sym->name, "ret_from_exception") ||
|
||||
STREQ(sym->name, "ret_from_irq") ||
|
||||
STREQ(sym->name, "work_resched") ||
|
||||
- STREQ(sym->name, "handle_sys");
|
||||
+ STREQ(sym->name, "handle_sys") ||
|
||||
+ STREQ(sym->name, "handle_syscall") ||
|
||||
+ STREQ(sym->name, "handle_ade") ||
|
||||
+ STREQ(sym->name, "handle_ale") ||
|
||||
+ STREQ(sym->name, "handle_bce") ||
|
||||
+ STREQ(sym->name, "handle_bp") ||
|
||||
+ STREQ(sym->name, "handle_fpe") ||
|
||||
+ STREQ(sym->name, "handle_fpu") ||
|
||||
+ STREQ(sym->name, "handle_iasub") ||
|
||||
+ STREQ(sym->name, "handle_ib") ||
|
||||
+ STREQ(sym->name, "handle_int") ||
|
||||
+ STREQ(sym->name, "handle_ipe") ||
|
||||
+ STREQ(sym->name, "handle_lbt") ||
|
||||
+ STREQ(sym->name, "handle_lsx") ||
|
||||
+ STREQ(sym->name, "handle_mcheck") ||
|
||||
+ STREQ(sym->name, "handle_oac") ||
|
||||
+ STREQ(sym->name, "handle_parchk") ||
|
||||
+ STREQ(sym->name, "handle_reserved") ||
|
||||
+ STREQ(sym->name, "handle_ri") ||
|
||||
+ STREQ(sym->name, "handle_tlb_protect") ||
|
||||
+ STREQ(sym->name, "tlb_do_page_fault_0") ||
|
||||
+ STREQ(sym->name, "tlb_do_page_fault_1") ||
|
||||
+ STREQ(sym->name, "handle_vint") ||
|
||||
+ STREQ(sym->name, "handle_watch") ||
|
||||
+ STREQ(sym->name, "handle_lasx");
|
||||
}
|
||||
|
||||
/*
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
From 40145cc1f001e7eedff7753377fb8e4b9e8787f7 Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Thu, 4 Jun 2026 19:52:43 +0800
|
||||
Subject: [PATCH 22/39] LoongArch64: Fix stack frame loop bounds for exception
|
||||
frames
|
||||
|
||||
Remove the incorrect -32 padding from stacktop limits in loongarch64.c.
|
||||
In modern LoongArch64 kernels, pt_regs rests exactly at the top of the
|
||||
stack, and this -32 padding forces the backtrace loop to terminate
|
||||
prematurely before reaching the exception frame.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
loongarch64.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index 3ec184c908f8..9980b35bdff1 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -461,7 +461,7 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
previous.pc = current.ra = regs->regs[LOONGARCH64_EF_RA];
|
||||
}
|
||||
|
||||
- while (current.sp <= bt->stacktop - 32 - SIZE(pt_regs)) {
|
||||
+ while (current.sp <= bt->stacktop - SIZE(pt_regs)) {
|
||||
struct syment *symbol = NULL;
|
||||
ulong offset;
|
||||
|
||||
@@ -501,7 +501,7 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
* * ret_from_kernel_thread
|
||||
*/
|
||||
if (symbol && !STRNEQ(symbol->name, "ret_from") && !offset &&
|
||||
- !current.ra && current.sp < bt->stacktop - 32 - SIZE(pt_regs)) {
|
||||
+ !current.ra && current.sp < bt->stacktop - SIZE(pt_regs)) {
|
||||
if (CRASHDEBUG(8))
|
||||
fprintf(fp, "zero offset at %s, try previous symbol\n",
|
||||
symbol->name);
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
From 523981942d8962b5246efa5c92f52abfb0f62e86 Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Thu, 4 Jun 2026 19:52:44 +0800
|
||||
Subject: [PATCH 23/39] LoongArch64: Add dummy eframe_search to avoid bt -e
|
||||
segfault
|
||||
|
||||
The lack of machdep->eframe_search initialization causes the crash tool
|
||||
to segment fault when executing `bt -e`. Provide a stub function that
|
||||
returns a fatal error indicating the option is not supported, matching
|
||||
the behavior of other architectures that lack this feature.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
loongarch64.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index 9980b35bdff1..b0ebf8b1d99e 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -64,6 +64,7 @@ static void loongarch64_dump_backtrace_entry(struct bt_info *bt,
|
||||
struct loongarch64_unwind_frame *previous, int level);
|
||||
static void loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs);
|
||||
static int loongarch64_is_exception_entry(struct syment *sym);
|
||||
+static int loongarch64_eframe_search(struct bt_info *bt);
|
||||
static void loongarch64_display_full_frame(struct bt_info *bt,
|
||||
struct loongarch64_unwind_frame *current,
|
||||
struct loongarch64_unwind_frame *previous);
|
||||
@@ -1267,6 +1268,7 @@ loongarch64_init(int when)
|
||||
machdep->kvtop = loongarch64_kvtop;
|
||||
machdep->cmd_mach = loongarch64_cmd_mach;
|
||||
machdep->back_trace = loongarch64_back_trace_cmd;
|
||||
+ machdep->eframe_search = loongarch64_eframe_search;
|
||||
machdep->get_stack_frame = loongarch64_get_stack_frame;
|
||||
machdep->vmalloc_start = loongarch64_vmalloc_start;
|
||||
machdep->processor_speed = loongarch64_processor_speed;
|
||||
@@ -1389,6 +1391,12 @@ loongarch64_display_regs_from_elf_notes(int cpu, FILE *ofp)
|
||||
regs->csr_euen);
|
||||
}
|
||||
|
||||
+static int
|
||||
+loongarch64_eframe_search(struct bt_info *bt)
|
||||
+{
|
||||
+ return error(FATAL, "-e option not supported on this architecture\n");
|
||||
+}
|
||||
+
|
||||
#else /* !LOONGARCH64 */
|
||||
|
||||
#include "defs.h"
|
||||
--
|
||||
2.54.0
|
||||
|
||||
49
0024-LoongArch64-print-exception-return-address-as-ERA.patch
Normal file
49
0024-LoongArch64-print-exception-return-address-as-ERA.patch
Normal file
@ -0,0 +1,49 @@
|
||||
From bf279fbd474f1f0c8783e0a0c5589d1bc0d7a16b Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Tue, 16 Jun 2026 20:47:41 +0800
|
||||
Subject: [PATCH 24/39] LoongArch64: print exception return address as ERA
|
||||
|
||||
LoongArch saves the exception return address in CSR.ERA. The crash
|
||||
LoongArch64 code currently labels this field as EPC in register and
|
||||
exception-frame output. That is misleading when comparing crash output
|
||||
with the architecture documentation and the kernel pt_regs layout.
|
||||
|
||||
Rename the displayed field to ERA and fix the CSR.EUEN label while
|
||||
updating the same output block. This is a display-only change and does
|
||||
not alter how the saved exception return address is collected or used by
|
||||
the unwinder.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
loongarch64.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index b0ebf8b1d99e..830c81826ebd 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -688,7 +688,7 @@ loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs)
|
||||
}
|
||||
|
||||
value_to_symstr(regs->csr_epc, buf, 16);
|
||||
- fprintf(fp, " epc : %016lx %s\n", regs->csr_epc, buf);
|
||||
+ fprintf(fp, " era : %016lx %s\n", regs->csr_epc, buf);
|
||||
|
||||
value_to_symstr(regs->regs[LOONGARCH64_EF_RA], buf, 16);
|
||||
fprintf(fp, " ra : %016lx %s\n", regs->regs[LOONGARCH64_EF_RA], buf);
|
||||
@@ -1346,10 +1346,10 @@ loongarch64_display_regs_from_elf_notes(int cpu, FILE *ofp)
|
||||
" R24: %016lx R25: %016lx R26: %016lx\n"
|
||||
" R27: %016lx R28: %016lx R29: %016lx\n"
|
||||
" R30: %016lx R31: %016lx\n"
|
||||
- " CSR epc : %016lx CSR badv: %016lx\n"
|
||||
+ " CSR era : %016lx CSR badv: %016lx\n"
|
||||
" CSR crmd: %08lx CSR prmd: %08lx\n"
|
||||
" CSR ecfg: %08lx CSR estat: %08lx\n"
|
||||
- " CSR eneu: %08lx",
|
||||
+ " CSR euen: %08lx",
|
||||
regs->regs[LOONGARCH64_EF_R0],
|
||||
regs->regs[LOONGARCH64_EF_R0 + 1],
|
||||
regs->regs[LOONGARCH64_EF_R0 + 2],
|
||||
--
|
||||
2.54.0
|
||||
|
||||
152
0025-LoongArch64-resolve-relocated-exception-vector-addre.patch
Normal file
152
0025-LoongArch64-resolve-relocated-exception-vector-addre.patch
Normal file
@ -0,0 +1,152 @@
|
||||
From 488777428c96d73964e659a3a6c229502f85d74d Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Tue, 16 Jun 2026 20:47:42 +0800
|
||||
Subject: [PATCH 25/39] LoongArch64: resolve relocated exception vector
|
||||
addresses
|
||||
|
||||
LoongArch copies exception entry code to the exception_handlers area and,
|
||||
on SMP systems, may execute vectors from per-cpu pcpu_handlers. A PC
|
||||
saved while running copied exception code therefore does not necessarily
|
||||
match the canonical symbol address in vmlinux.
|
||||
|
||||
Crash currently looks up those runtime addresses directly. That can
|
||||
leave frames such as handle_vint unresolved and prevents exception-frame
|
||||
handling from identifying the interrupted context reliably.
|
||||
|
||||
Translate PCs in the relocated exception vector range back to their
|
||||
canonical handler addresses before symbol lookup. Follow the kernel
|
||||
layout by folding per-cpu handler addresses back to eentry, computing the
|
||||
vector type and offset, mapping normal exceptions through
|
||||
exception_table[], and mapping interrupt vectors to handle_vint.
|
||||
|
||||
The per-cpu handler mapping is optional and exists only for NUMA non-RT
|
||||
kernels. When pcpu_handlers is absent, the normal eentry mapping still
|
||||
covers the boot-time exception handler area.
|
||||
|
||||
Co-developed-by: Xianglai Li <lixianglai@loongson.cn>
|
||||
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
loongarch64.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 77 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index 830c81826ebd..0b108e062b2e 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -43,6 +43,11 @@ struct loongarch64_unwind_frame {
|
||||
unsigned long ra;
|
||||
};
|
||||
|
||||
+#define LOONGARCH64_VECSIZE 0x200
|
||||
+#define LOONGARCH64_EXCEPTION_VECTOR_NUM 128
|
||||
+#define LOONGARCH64_EXCCODE_INT_START 64
|
||||
+#define LOONGARCH64_EXCCODE_INT_END 78
|
||||
+
|
||||
static int loongarch64_pgd_vtop(ulong *pgd, ulong vaddr,
|
||||
physaddr_t *paddr, int verbose);
|
||||
static int loongarch64_uvtop(struct task_context *tc, ulong vaddr,
|
||||
@@ -64,6 +69,7 @@ static void loongarch64_dump_backtrace_entry(struct bt_info *bt,
|
||||
struct loongarch64_unwind_frame *previous, int level);
|
||||
static void loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs);
|
||||
static int loongarch64_is_exception_entry(struct syment *sym);
|
||||
+static ulong loongarch64_exception_pc(int cpu, ulong pc);
|
||||
static int loongarch64_eframe_search(struct bt_info *bt);
|
||||
static void loongarch64_display_full_frame(struct bt_info *bt,
|
||||
struct loongarch64_unwind_frame *current,
|
||||
@@ -466,6 +472,9 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
struct syment *symbol = NULL;
|
||||
ulong offset;
|
||||
|
||||
+ current.pc = loongarch64_exception_pc(bt->tc->processor,
|
||||
+ current.pc);
|
||||
+
|
||||
if (CRASHDEBUG(8))
|
||||
fprintf(fp, "level %d pc %#lx ra %#lx sp %lx\n",
|
||||
level, current.pc, current.ra, current.sp);
|
||||
@@ -687,7 +696,8 @@ loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs)
|
||||
regs->regs[i+2], regs->regs[i+3]);
|
||||
}
|
||||
|
||||
- value_to_symstr(regs->csr_epc, buf, 16);
|
||||
+ value_to_symstr(loongarch64_exception_pc(bt->tc->processor,
|
||||
+ regs->csr_epc), buf, 16);
|
||||
fprintf(fp, " era : %016lx %s\n", regs->csr_epc, buf);
|
||||
|
||||
value_to_symstr(regs->regs[LOONGARCH64_EF_RA], buf, 16);
|
||||
@@ -735,6 +745,72 @@ loongarch64_is_exception_entry(struct syment *sym)
|
||||
STREQ(sym->name, "handle_lasx");
|
||||
}
|
||||
|
||||
+static ulong
|
||||
+loongarch64_exception_pc(int cpu, ulong pc)
|
||||
+{
|
||||
+ ulong eentry, pcpu_handler, offset, type, func;
|
||||
+ ulong exception_table, exception_handlers;
|
||||
+ int i;
|
||||
+
|
||||
+ if (!IS_KVADDR(pc) || !symbol_exists("exception_handlers"))
|
||||
+ return pc;
|
||||
+
|
||||
+ exception_handlers = symbol_value("exception_handlers");
|
||||
+ eentry = exception_handlers;
|
||||
+ if (symbol_exists("eentry"))
|
||||
+ readmem(symbol_value("eentry"), KVADDR, &eentry, sizeof(eentry),
|
||||
+ "LoongArch eentry", RETURN_ON_ERROR|QUIET);
|
||||
+
|
||||
+ /*
|
||||
+ * pcpu_handlers exists only for NUMA non-RT kernels. When absent,
|
||||
+ * the boot-time eentry/exception_handlers mapping below is still valid.
|
||||
+ */
|
||||
+ if (symbol_exists("pcpu_handlers")) {
|
||||
+ for (i = 0; i < kt->cpus; i++) {
|
||||
+ if (cpu >= 0 && cpu < kt->cpus && i != cpu)
|
||||
+ continue;
|
||||
+ if (!readmem(symbol_value("pcpu_handlers") +
|
||||
+ (i * sizeof(ulong)), KVADDR, &pcpu_handler,
|
||||
+ sizeof(pcpu_handler), "LoongArch pcpu_handlers",
|
||||
+ RETURN_ON_ERROR|QUIET))
|
||||
+ continue;
|
||||
+ if (!pcpu_handler)
|
||||
+ continue;
|
||||
+ if (pc >= pcpu_handler &&
|
||||
+ pc < pcpu_handler + LOONGARCH64_VECSIZE *
|
||||
+ LOONGARCH64_EXCEPTION_VECTOR_NUM) {
|
||||
+ pc = pc + eentry - pcpu_handler;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (pc < eentry || pc >= eentry + LOONGARCH64_EXCCODE_INT_END * LOONGARCH64_VECSIZE)
|
||||
+ return pc;
|
||||
+
|
||||
+ offset = (pc - eentry) % LOONGARCH64_VECSIZE;
|
||||
+ type = (pc - eentry) / LOONGARCH64_VECSIZE;
|
||||
+
|
||||
+ if (type < LOONGARCH64_EXCCODE_INT_START &&
|
||||
+ symbol_exists("exception_table")) {
|
||||
+ exception_table = symbol_value("exception_table");
|
||||
+ if (!readmem(exception_table + (type * sizeof(ulong)), KVADDR,
|
||||
+ &func, sizeof(func), "LoongArch exception_table",
|
||||
+ RETURN_ON_ERROR|QUIET))
|
||||
+ func = 0;
|
||||
+ } else if (type >= LOONGARCH64_EXCCODE_INT_START &&
|
||||
+ type <= LOONGARCH64_EXCCODE_INT_END &&
|
||||
+ symbol_exists("handle_vint")) {
|
||||
+ func = symbol_value("handle_vint");
|
||||
+ } else if (symbol_exists("handle_reserved")) {
|
||||
+ func = symbol_value("handle_reserved");
|
||||
+ } else {
|
||||
+ func = 0;
|
||||
+ }
|
||||
+
|
||||
+ return func ? func + offset : pc;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* 'bt -f' commend output
|
||||
* Display all stack data contained in a frame
|
||||
--
|
||||
2.54.0
|
||||
|
||||
515
0026-LoongArch64-add-initial-ORC-unwinder-support.patch
Normal file
515
0026-LoongArch64-add-initial-ORC-unwinder-support.patch
Normal file
@ -0,0 +1,515 @@
|
||||
From 9e8d1784b910db417c993e9de7ab2cbd0e9d4fc8 Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Tue, 16 Jun 2026 20:47:43 +0800
|
||||
Subject: [PATCH 26/39] LoongArch64: add initial ORC unwinder support
|
||||
|
||||
LoongArch kernels can provide ORC unwind tables. Without consuming those
|
||||
tables, crash falls back to a small prologue scanner, which is fragile
|
||||
around exception entries and functions whose frame layout does not match
|
||||
the simple scanner.
|
||||
|
||||
Add initial support for reading the kernel ORC IP table, lookup table and
|
||||
orc_entry records, and use them while unwinding LoongArch64 kernel text
|
||||
frames. The unwinder handles CALL and REGS entries, carries
|
||||
frame-pointer state, and normalizes relocated exception-vector PCs before
|
||||
using them as unwind targets.
|
||||
|
||||
For CALL entries, convert the saved return address back to the call
|
||||
instruction address before validation, matching the kernel unwinder
|
||||
convention. This avoids looking up the instruction after the call as the
|
||||
caller frame.
|
||||
|
||||
This intentionally covers core kernel text first. Module and ftrace ORC
|
||||
handling can be added separately.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
defs.h | 25 ++++
|
||||
loongarch64.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 378 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index a4f70b773cd7..b349872f49a4 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -7333,6 +7333,30 @@ void loongarch64_dump_machdep_table(ulong);
|
||||
|
||||
#define KSYMS_START (0x1)
|
||||
|
||||
+struct loongarch64_orc_entry {
|
||||
+ short sp_offset;
|
||||
+ short fp_offset;
|
||||
+ short ra_offset;
|
||||
+ uint sp_reg;
|
||||
+ uint fp_reg;
|
||||
+ uint ra_reg;
|
||||
+ uint type;
|
||||
+ uint signal;
|
||||
+};
|
||||
+
|
||||
+struct loongarch64_ORC_data {
|
||||
+ int enabled;
|
||||
+ uint lookup_num_blocks;
|
||||
+ ulong __start_orc_unwind_ip;
|
||||
+ ulong __stop_orc_unwind_ip;
|
||||
+ ulong __start_orc_unwind;
|
||||
+ ulong __stop_orc_unwind;
|
||||
+ ulong orc_lookup;
|
||||
+ ulong ip_entry;
|
||||
+ ulong orc_entry;
|
||||
+ struct loongarch64_orc_entry orc_entry_data;
|
||||
+};
|
||||
+
|
||||
struct machine_specific {
|
||||
ulong phys_base;
|
||||
ulong vmalloc_start_addr;
|
||||
@@ -7340,6 +7364,7 @@ struct machine_specific {
|
||||
ulong modules_end;
|
||||
|
||||
struct loongarch64_pt_regs *crash_task_regs;
|
||||
+ struct loongarch64_ORC_data orc;
|
||||
};
|
||||
|
||||
/*
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index 0b108e062b2e..2e9e28602b9b 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -41,8 +41,33 @@ struct loongarch64_unwind_frame {
|
||||
unsigned long sp;
|
||||
unsigned long pc;
|
||||
unsigned long ra;
|
||||
+ unsigned long fp;
|
||||
};
|
||||
|
||||
+typedef struct __attribute__((__packed__)) {
|
||||
+ short sp_offset;
|
||||
+ short fp_offset;
|
||||
+ short ra_offset;
|
||||
+ unsigned int sp_reg:4;
|
||||
+ unsigned int fp_reg:4;
|
||||
+ unsigned int ra_reg:4;
|
||||
+ unsigned int type:3;
|
||||
+ unsigned int signal:1;
|
||||
+} loongarch64_kernel_orc_entry;
|
||||
+
|
||||
+#define LOONGARCH64_ORC_REG_UNDEFINED 0
|
||||
+#define LOONGARCH64_ORC_REG_PREV_SP 1
|
||||
+#define LOONGARCH64_ORC_REG_SP 2
|
||||
+#define LOONGARCH64_ORC_REG_FP 3
|
||||
+
|
||||
+#define LOONGARCH64_ORC_TYPE_UNDEFINED 0
|
||||
+#define LOONGARCH64_ORC_TYPE_END_OF_STACK 1
|
||||
+#define LOONGARCH64_ORC_TYPE_CALL 2
|
||||
+#define LOONGARCH64_ORC_TYPE_REGS 3
|
||||
+
|
||||
+#define LOONGARCH64_LOOKUP_BLOCK_ORDER 8
|
||||
+#define LOONGARCH64_LOOKUP_BLOCK_SIZE (1 << LOONGARCH64_LOOKUP_BLOCK_ORDER)
|
||||
+#define LOONGARCH64_INSN_SIZE 4
|
||||
#define LOONGARCH64_VECSIZE 0x200
|
||||
#define LOONGARCH64_EXCEPTION_VECTOR_NUM 128
|
||||
#define LOONGARCH64_EXCCODE_INT_START 64
|
||||
@@ -70,6 +95,7 @@ static void loongarch64_dump_backtrace_entry(struct bt_info *bt,
|
||||
static void loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs);
|
||||
static int loongarch64_is_exception_entry(struct syment *sym);
|
||||
static ulong loongarch64_exception_pc(int cpu, ulong pc);
|
||||
+static int loongarch64_is_unwind_text(ulong pc);
|
||||
static int loongarch64_eframe_search(struct bt_info *bt);
|
||||
static void loongarch64_display_full_frame(struct bt_info *bt,
|
||||
struct loongarch64_unwind_frame *current,
|
||||
@@ -82,6 +108,10 @@ static int loongarch64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
|
||||
static int loongarch64_init_active_task_regs(void);
|
||||
static int loongarch64_get_crash_notes(void);
|
||||
static int loongarch64_get_elf_notes(void);
|
||||
+static void loongarch64_ORC_init(void);
|
||||
+static int loongarch64_orc_unwind(struct bt_info *bt,
|
||||
+ struct loongarch64_unwind_frame *current,
|
||||
+ struct loongarch64_unwind_frame *previous);
|
||||
|
||||
/*
|
||||
* 3 Levels paging PAGE_SIZE=16KB
|
||||
@@ -454,11 +484,12 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
if (bt->flags & BT_REGS_NOT_FOUND)
|
||||
return;
|
||||
|
||||
- previous.sp = previous.pc = previous.ra = 0;
|
||||
+ previous.sp = previous.pc = previous.ra = previous.fp = 0;
|
||||
|
||||
current.pc = bt->instptr;
|
||||
current.sp = bt->stkptr;
|
||||
current.ra = 0;
|
||||
+ current.fp = 0;
|
||||
|
||||
if (!INSTACK(current.sp, bt))
|
||||
return;
|
||||
@@ -466,6 +497,7 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
if (bt->machdep) {
|
||||
regs = (struct loongarch64_pt_regs *)bt->machdep;
|
||||
previous.pc = current.ra = regs->regs[LOONGARCH64_EF_RA];
|
||||
+ current.fp = regs->regs[LOONGARCH64_EF_FP];
|
||||
}
|
||||
|
||||
while (current.sp <= bt->stacktop - SIZE(pt_regs)) {
|
||||
@@ -523,12 +555,15 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
}
|
||||
}
|
||||
|
||||
- if (symbol && loongarch64_is_exception_entry(symbol)) {
|
||||
+ if (loongarch64_orc_unwind(bt, ¤t, &previous)) {
|
||||
+ /* ORC has already calculated the caller frame. */
|
||||
+ } else if (symbol && loongarch64_is_exception_entry(symbol)) {
|
||||
|
||||
GET_STACK_DATA(current.sp, pt_regs, sizeof(pt_regs));
|
||||
regs = (struct loongarch64_pt_regs *) (pt_regs + OFFSET(pt_regs_regs));
|
||||
previous.ra = regs->regs[LOONGARCH64_EF_RA];
|
||||
previous.sp = regs->regs[LOONGARCH64_EF_SP];
|
||||
+ previous.fp = regs->regs[LOONGARCH64_EF_FP];
|
||||
current.ra = regs->csr_epc;
|
||||
|
||||
if (CRASHDEBUG(8))
|
||||
@@ -554,12 +589,13 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
current.pc = current.ra;
|
||||
current.sp = previous.sp;
|
||||
current.ra = previous.ra;
|
||||
+ current.fp = previous.fp;
|
||||
|
||||
if (CRASHDEBUG(8))
|
||||
fprintf(fp, "next %d pc %#lx ra %#lx sp %lx\n",
|
||||
level, current.pc, current.ra, current.sp);
|
||||
|
||||
- previous.sp = previous.pc = previous.ra = 0;
|
||||
+ previous.sp = previous.pc = previous.ra = previous.fp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -811,6 +847,319 @@ loongarch64_exception_pc(int cpu, ulong pc)
|
||||
return func ? func + offset : pc;
|
||||
}
|
||||
|
||||
+
|
||||
+static int
|
||||
+loongarch64_is_unwind_text(ulong pc)
|
||||
+{
|
||||
+ struct syment *symbol;
|
||||
+ ulong offset;
|
||||
+
|
||||
+ if (!is_kernel_text(pc))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ symbol = value_search(pc, &offset);
|
||||
+ if (!symbol || symbol->name[0] == '.' ||
|
||||
+ STREQ(symbol->name, "_PROCEDURE_LINKAGE_TABLE_") ||
|
||||
+ STREQ(symbol->name, "empty_zero_page") ||
|
||||
+ STRNEQ(symbol->name, "__start_") ||
|
||||
+ STRNEQ(symbol->name, "__end_"))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+loongarch64_orc_ip(ulong ip_entry_addr, ulong *ip)
|
||||
+{
|
||||
+ int ip_entry;
|
||||
+
|
||||
+ if (!readmem(ip_entry_addr, KVADDR, &ip_entry, sizeof(ip_entry),
|
||||
+ "LoongArch ORC ip", RETURN_ON_ERROR|QUIET))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ *ip = ip_entry_addr + ip_entry;
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static struct loongarch64_orc_entry *
|
||||
+loongarch64_orc_get_entry(struct loongarch64_ORC_data *orc)
|
||||
+{
|
||||
+ loongarch64_kernel_orc_entry korc;
|
||||
+ struct loongarch64_orc_entry *entry = &orc->orc_entry_data;
|
||||
+
|
||||
+ if (!readmem(orc->orc_entry, KVADDR, &korc, sizeof(korc),
|
||||
+ "LoongArch ORC entry", RETURN_ON_ERROR|QUIET))
|
||||
+ return NULL;
|
||||
+
|
||||
+ entry->sp_offset = korc.sp_offset;
|
||||
+ entry->fp_offset = korc.fp_offset;
|
||||
+ entry->ra_offset = korc.ra_offset;
|
||||
+ entry->sp_reg = korc.sp_reg;
|
||||
+ entry->fp_reg = korc.fp_reg;
|
||||
+ entry->ra_reg = korc.ra_reg;
|
||||
+ entry->type = korc.type;
|
||||
+ entry->signal = korc.signal;
|
||||
+
|
||||
+ return entry;
|
||||
+}
|
||||
+
|
||||
+static struct loongarch64_orc_entry *
|
||||
+loongarch64_orc_find_in_table(ulong ip_table, ulong orc_table,
|
||||
+ uint num_entries, ulong ip)
|
||||
+{
|
||||
+ int index;
|
||||
+ ulong first, last, mid, found, vaddr;
|
||||
+ struct machine_specific *ms = machdep->machspec;
|
||||
+ struct loongarch64_ORC_data *orc = &ms->orc;
|
||||
+
|
||||
+ if (!num_entries)
|
||||
+ return NULL;
|
||||
+
|
||||
+ first = ip_table;
|
||||
+ last = ip_table + ((num_entries - 1) * sizeof(int));
|
||||
+ found = first;
|
||||
+
|
||||
+ while (first <= last) {
|
||||
+ mid = first + (((last - first) / sizeof(int)) / 2) *
|
||||
+ sizeof(int);
|
||||
+
|
||||
+ if (!loongarch64_orc_ip(mid, &vaddr))
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (vaddr <= ip) {
|
||||
+ found = mid;
|
||||
+ first = mid + sizeof(int);
|
||||
+ } else {
|
||||
+ if (mid == ip_table)
|
||||
+ break;
|
||||
+ last = mid - sizeof(int);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ index = (found - ip_table) / sizeof(int);
|
||||
+ orc->ip_entry = found;
|
||||
+ orc->orc_entry = orc_table + (index * SIZE(orc_entry));
|
||||
+
|
||||
+ return loongarch64_orc_get_entry(orc);
|
||||
+}
|
||||
+
|
||||
+static struct loongarch64_orc_entry *
|
||||
+loongarch64_orc_find(ulong ip)
|
||||
+{
|
||||
+ uint idx, start, stop, num_entries;
|
||||
+ struct machine_specific *ms = machdep->machspec;
|
||||
+ struct loongarch64_ORC_data *orc = &ms->orc;
|
||||
+
|
||||
+ if (!orc->enabled)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if ((ip >= kt->stext) && (ip < kt->etext)) {
|
||||
+ if (orc->lookup_num_blocks < 2)
|
||||
+ return NULL;
|
||||
+
|
||||
+ idx = (ip - kt->stext) / LOONGARCH64_LOOKUP_BLOCK_SIZE;
|
||||
+ if (idx >= orc->lookup_num_blocks - 1)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (!readmem(orc->orc_lookup + (idx * sizeof(uint)), KVADDR,
|
||||
+ &start, sizeof(start), "LoongArch ORC lookup start",
|
||||
+ RETURN_ON_ERROR|QUIET))
|
||||
+ return NULL;
|
||||
+ if (!readmem(orc->orc_lookup + ((idx + 1) * sizeof(uint)),
|
||||
+ KVADDR, &stop, sizeof(stop), "LoongArch ORC lookup stop",
|
||||
+ RETURN_ON_ERROR|QUIET))
|
||||
+ return NULL;
|
||||
+ stop++;
|
||||
+
|
||||
+ if ((orc->__start_orc_unwind + (start * SIZE(orc_entry))) >=
|
||||
+ orc->__stop_orc_unwind)
|
||||
+ return NULL;
|
||||
+ if ((orc->__start_orc_unwind + (stop * SIZE(orc_entry))) >
|
||||
+ orc->__stop_orc_unwind)
|
||||
+ return NULL;
|
||||
+
|
||||
+ return loongarch64_orc_find_in_table(
|
||||
+ orc->__start_orc_unwind_ip + (start * sizeof(int)),
|
||||
+ orc->__start_orc_unwind + (start * SIZE(orc_entry)),
|
||||
+ stop - start, ip);
|
||||
+ }
|
||||
+
|
||||
+ if (is_kernel_text(ip)) {
|
||||
+ num_entries = (orc->__stop_orc_unwind_ip -
|
||||
+ orc->__start_orc_unwind_ip) / sizeof(int);
|
||||
+ return loongarch64_orc_find_in_table(orc->__start_orc_unwind_ip,
|
||||
+ orc->__start_orc_unwind, num_entries, ip);
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+loongarch64_orc_read_stack(ulong addr, ulong *value)
|
||||
+{
|
||||
+ return readmem(addr, KVADDR, value, sizeof(*value),
|
||||
+ "LoongArch ORC stack", RETURN_ON_ERROR|QUIET);
|
||||
+}
|
||||
+
|
||||
+static ulong
|
||||
+loongarch64_orc_adjust_pc(int cpu, ulong ra)
|
||||
+{
|
||||
+ ra = loongarch64_exception_pc(cpu, ra);
|
||||
+ return loongarch64_is_unwind_text(ra) ? ra : 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+loongarch64_orc_unwind(struct bt_info *bt,
|
||||
+ struct loongarch64_unwind_frame *current,
|
||||
+ struct loongarch64_unwind_frame *previous)
|
||||
+{
|
||||
+ ulong cfa, pcval, fpval = current->fp;
|
||||
+ struct loongarch64_orc_entry *orc;
|
||||
+ struct loongarch64_pt_regs regs;
|
||||
+
|
||||
+ orc = loongarch64_orc_find(current->pc);
|
||||
+ if (!orc)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (CRASHDEBUG(8))
|
||||
+ fprintf(fp,
|
||||
+ "orc pc %lx sp %lx fp %lx -> spo %d fpo %d rao %d "
|
||||
+ "spr %u fpr %u rar %u type %u\n",
|
||||
+ current->pc, current->sp, current->fp, orc->sp_offset,
|
||||
+ orc->fp_offset, orc->ra_offset, orc->sp_reg, orc->fp_reg,
|
||||
+ orc->ra_reg, orc->type);
|
||||
+
|
||||
+ if (orc->type == LOONGARCH64_ORC_TYPE_UNDEFINED ||
|
||||
+ orc->type == LOONGARCH64_ORC_TYPE_END_OF_STACK)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ switch (orc->sp_reg) {
|
||||
+ case LOONGARCH64_ORC_REG_SP:
|
||||
+ cfa = current->sp + orc->sp_offset;
|
||||
+ break;
|
||||
+ case LOONGARCH64_ORC_REG_FP:
|
||||
+ if (!current->fp)
|
||||
+ return FALSE;
|
||||
+ cfa = current->fp;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ switch (orc->fp_reg) {
|
||||
+ case LOONGARCH64_ORC_REG_PREV_SP:
|
||||
+ if (!loongarch64_orc_read_stack(cfa + orc->fp_offset, &fpval))
|
||||
+ return FALSE;
|
||||
+ break;
|
||||
+ case LOONGARCH64_ORC_REG_UNDEFINED:
|
||||
+ break;
|
||||
+ default:
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ switch (orc->type) {
|
||||
+ case LOONGARCH64_ORC_TYPE_CALL:
|
||||
+ if (orc->ra_reg == LOONGARCH64_ORC_REG_PREV_SP) {
|
||||
+ if (!loongarch64_orc_read_stack(cfa + orc->ra_offset,
|
||||
+ &pcval))
|
||||
+ return FALSE;
|
||||
+ } else if (orc->ra_reg == LOONGARCH64_ORC_REG_UNDEFINED) {
|
||||
+ if (!current->ra || current->ra == current->pc)
|
||||
+ return FALSE;
|
||||
+ pcval = current->ra;
|
||||
+ } else {
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ if (pcval >= LOONGARCH64_INSN_SIZE)
|
||||
+ pcval -= LOONGARCH64_INSN_SIZE;
|
||||
+ pcval = loongarch64_orc_adjust_pc(bt->tc->processor, pcval);
|
||||
+ if (!pcval && current->ra >= LOONGARCH64_INSN_SIZE)
|
||||
+ pcval = loongarch64_orc_adjust_pc(bt->tc->processor,
|
||||
+ current->ra - LOONGARCH64_INSN_SIZE);
|
||||
+ if (!pcval)
|
||||
+ return FALSE;
|
||||
+ previous->sp = cfa;
|
||||
+ previous->fp = fpval;
|
||||
+ previous->ra = 0;
|
||||
+ current->ra = pcval;
|
||||
+ return TRUE;
|
||||
+
|
||||
+ case LOONGARCH64_ORC_TYPE_REGS:
|
||||
+ if (!readmem(cfa, KVADDR, ®s, sizeof(regs),
|
||||
+ "LoongArch ORC pt_regs", RETURN_ON_ERROR|QUIET))
|
||||
+ return FALSE;
|
||||
+ /*
|
||||
+ * The kernel unwinder treats user-mode or empty pt_regs as a
|
||||
+ * clean end. Crash does not need to distinguish that from a
|
||||
+ * fallback here; a non-kernel ERA simply stops ORC unwinding.
|
||||
+ */
|
||||
+ pcval = loongarch64_exception_pc(bt->tc->processor, regs.csr_epc);
|
||||
+ if (!loongarch64_is_unwind_text(pcval))
|
||||
+ return FALSE;
|
||||
+ previous->sp = regs.regs[LOONGARCH64_EF_SP];
|
||||
+ previous->fp = regs.regs[LOONGARCH64_EF_FP];
|
||||
+ previous->ra = regs.regs[LOONGARCH64_EF_RA];
|
||||
+ current->ra = pcval;
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+loongarch64_ORC_init(void)
|
||||
+{
|
||||
+ int i;
|
||||
+ char *orc_symbols[] = {
|
||||
+ "lookup_num_blocks",
|
||||
+ "__start_orc_unwind_ip",
|
||||
+ "__stop_orc_unwind_ip",
|
||||
+ "__start_orc_unwind",
|
||||
+ "__stop_orc_unwind",
|
||||
+ "orc_lookup",
|
||||
+ NULL
|
||||
+ };
|
||||
+ struct machine_specific *ms = machdep->machspec;
|
||||
+ struct loongarch64_ORC_data *orc = &ms->orc;
|
||||
+
|
||||
+ STRUCT_SIZE_INIT(orc_entry, "orc_entry");
|
||||
+ if (!VALID_STRUCT(orc_entry) ||
|
||||
+ SIZE(orc_entry) != sizeof(loongarch64_kernel_orc_entry)) {
|
||||
+ error(WARNING, "LoongArch64 ORC unwinder: "
|
||||
+ "orc_entry structure has changed\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!MEMBER_EXISTS("orc_entry", "sp_offset") ||
|
||||
+ !MEMBER_EXISTS("orc_entry", "fp_offset") ||
|
||||
+ !MEMBER_EXISTS("orc_entry", "ra_offset") ||
|
||||
+ !MEMBER_EXISTS("orc_entry", "sp_reg") ||
|
||||
+ !MEMBER_EXISTS("orc_entry", "fp_reg") ||
|
||||
+ !MEMBER_EXISTS("orc_entry", "ra_reg") ||
|
||||
+ !MEMBER_EXISTS("orc_entry", "type")) {
|
||||
+ error(WARNING, "LoongArch64 ORC unwinder: "
|
||||
+ "orc_entry members have changed\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; orc_symbols[i]; i++) {
|
||||
+ if (!symbol_exists(orc_symbols[i]))
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!readmem(symbol_value("lookup_num_blocks"), KVADDR,
|
||||
+ &orc->lookup_num_blocks, sizeof(orc->lookup_num_blocks),
|
||||
+ "LoongArch ORC lookup_num_blocks", RETURN_ON_ERROR|QUIET))
|
||||
+ return;
|
||||
+
|
||||
+ orc->__start_orc_unwind_ip = symbol_value("__start_orc_unwind_ip");
|
||||
+ orc->__stop_orc_unwind_ip = symbol_value("__stop_orc_unwind_ip");
|
||||
+ orc->__start_orc_unwind = symbol_value("__start_orc_unwind");
|
||||
+ orc->__stop_orc_unwind = symbol_value("__stop_orc_unwind");
|
||||
+ orc->orc_lookup = symbol_value("orc_lookup");
|
||||
+ orc->enabled = TRUE;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* 'bt -f' commend output
|
||||
* Display all stack data contained in a frame
|
||||
@@ -1374,6 +1723,7 @@ loongarch64_init(int when)
|
||||
&machdep->nr_irqs);
|
||||
|
||||
loongarch64_stackframe_init();
|
||||
+ loongarch64_ORC_init();
|
||||
|
||||
if (!machdep->hz)
|
||||
machdep->hz = 250;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
364
0027-LoongArch64-unwind-dumpfile-active-tasks-from-IRQ-st.patch
Normal file
364
0027-LoongArch64-unwind-dumpfile-active-tasks-from-IRQ-st.patch
Normal file
@ -0,0 +1,364 @@
|
||||
From a436361b2798534ea722ac696a4eeaa35d80ef33 Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Tue, 16 Jun 2026 20:47:44 +0800
|
||||
Subject: [PATCH 27/39] LoongArch64: unwind dumpfile active tasks from IRQ
|
||||
stacks
|
||||
|
||||
For dumpfile active tasks, the saved SP may point into the per-cpu IRQ
|
||||
stack instead of the task stack. The existing LoongArch64 unwinder only
|
||||
uses the task stack buffer, so it can stop early or pick stale task-stack
|
||||
words as caller frames.
|
||||
|
||||
Initialize the per-cpu IRQ stack addresses, switch the bt stack buffer
|
||||
when an active task starts on an IRQ stack, and continue unwinding back to
|
||||
the interrupted task stack using the task SP saved at the end of the IRQ
|
||||
stack. This saved-SP slot matches the kernel IRQ_STACK_START layout.
|
||||
When that saved task SP points to pt_regs, validate the saved ERA, SP and
|
||||
RA before using them as the handoff frame.
|
||||
|
||||
Hypervisor dump PRSTATUS RA values from IRQ stack contexts are not always
|
||||
a reliable caller. Keep them only for the narrow IRQ leaf case that
|
||||
preserves the in-flight generic_handle_domain_irq -> handle_cpu_irq
|
||||
chain; otherwise let ORC, exception frames, or the saved pt_regs handoff
|
||||
determine the next frame.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
defs.h | 2 +
|
||||
loongarch64.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
2 files changed, 223 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index b349872f49a4..bdb4eb3e0980 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -7363,6 +7363,8 @@ struct machine_specific {
|
||||
ulong modules_vaddr;
|
||||
ulong modules_end;
|
||||
|
||||
+ ulong irq_stack_size;
|
||||
+ ulong *irq_stacks;
|
||||
struct loongarch64_pt_regs *crash_task_regs;
|
||||
struct loongarch64_ORC_data orc;
|
||||
};
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index 2e9e28602b9b..c25a3bbf6d6c 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -70,6 +70,7 @@ typedef struct __attribute__((__packed__)) {
|
||||
#define LOONGARCH64_INSN_SIZE 4
|
||||
#define LOONGARCH64_VECSIZE 0x200
|
||||
#define LOONGARCH64_EXCEPTION_VECTOR_NUM 128
|
||||
+#define LOONGARCH64_IRQ_STACK_SAVED_SP_OFFSET 16
|
||||
#define LOONGARCH64_EXCCODE_INT_START 64
|
||||
#define LOONGARCH64_EXCCODE_INT_END 78
|
||||
|
||||
@@ -96,6 +97,9 @@ static void loongarch64_dump_exception_stack(struct bt_info *bt, char *pt_regs);
|
||||
static int loongarch64_is_exception_entry(struct syment *sym);
|
||||
static ulong loongarch64_exception_pc(int cpu, ulong pc);
|
||||
static int loongarch64_is_unwind_text(ulong pc);
|
||||
+static int loongarch64_use_irq_prstatus_ra(ulong pc, ulong ra);
|
||||
+static int loongarch64_valid_saved_regs(struct bt_info *bt,
|
||||
+ struct loongarch64_pt_regs *regs, ulong *pc);
|
||||
static int loongarch64_eframe_search(struct bt_info *bt);
|
||||
static void loongarch64_display_full_frame(struct bt_info *bt,
|
||||
struct loongarch64_unwind_frame *current,
|
||||
@@ -108,10 +112,17 @@ static int loongarch64_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp);
|
||||
static int loongarch64_init_active_task_regs(void);
|
||||
static int loongarch64_get_crash_notes(void);
|
||||
static int loongarch64_get_elf_notes(void);
|
||||
+static void loongarch64_irq_stack_init(void);
|
||||
static void loongarch64_ORC_init(void);
|
||||
static int loongarch64_orc_unwind(struct bt_info *bt,
|
||||
struct loongarch64_unwind_frame *current,
|
||||
struct loongarch64_unwind_frame *previous);
|
||||
+static int loongarch64_on_irq_stack(int cpu, ulong stkptr);
|
||||
+static void loongarch64_set_irq_stack(struct bt_info *bt);
|
||||
+static int loongarch64_switch_from_irq_stack(struct bt_info *bt,
|
||||
+ struct loongarch64_unwind_frame *current);
|
||||
+static int loongarch64_find_next_kernel_text(struct bt_info *bt,
|
||||
+ struct loongarch64_unwind_frame *current);
|
||||
|
||||
/*
|
||||
* 3 Levels paging PAGE_SIZE=16KB
|
||||
@@ -480,6 +491,7 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
char pt_regs[SIZE(pt_regs)];
|
||||
int level = 0;
|
||||
int invalid_ok = 1;
|
||||
+ int on_irq_stack;
|
||||
|
||||
if (bt->flags & BT_REGS_NOT_FOUND)
|
||||
return;
|
||||
@@ -491,16 +503,30 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
current.ra = 0;
|
||||
current.fp = 0;
|
||||
|
||||
+ if (!INSTACK(current.sp, bt) &&
|
||||
+ (bt->flags & BT_REGS_NOT_FOUND) == 0 &&
|
||||
+ loongarch64_on_irq_stack(bt->tc->processor, current.sp))
|
||||
+ loongarch64_set_irq_stack(bt);
|
||||
+
|
||||
if (!INSTACK(current.sp, bt))
|
||||
return;
|
||||
|
||||
+ on_irq_stack = loongarch64_on_irq_stack(bt->tc->processor, current.sp);
|
||||
if (bt->machdep) {
|
||||
regs = (struct loongarch64_pt_regs *)bt->machdep;
|
||||
- previous.pc = current.ra = regs->regs[LOONGARCH64_EF_RA];
|
||||
+ /*
|
||||
+ * PRSTATUS RA from IRQ stacks is not always a reliable caller for
|
||||
+ * hypervisor dumps. Use it only for IRQ leaf frames where it keeps
|
||||
+ * the in-flight interrupt call chain before crossing stacks.
|
||||
+ */
|
||||
+ if (!on_irq_stack ||
|
||||
+ loongarch64_use_irq_prstatus_ra(current.pc,
|
||||
+ regs->regs[LOONGARCH64_EF_RA]))
|
||||
+ previous.pc = current.ra = regs->regs[LOONGARCH64_EF_RA];
|
||||
current.fp = regs->regs[LOONGARCH64_EF_FP];
|
||||
}
|
||||
|
||||
- while (current.sp <= bt->stacktop - SIZE(pt_regs)) {
|
||||
+ while (current.sp < bt->stacktop) {
|
||||
struct syment *symbol = NULL;
|
||||
ulong offset;
|
||||
|
||||
@@ -511,14 +537,28 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
fprintf(fp, "level %d pc %#lx ra %#lx sp %lx\n",
|
||||
level, current.pc, current.ra, current.sp);
|
||||
|
||||
- if (!IS_KVADDR(current.pc) && !invalid_ok)
|
||||
+ if (!IS_KVADDR(current.pc) && !invalid_ok) {
|
||||
+ if (loongarch64_switch_from_irq_stack(bt, ¤t) ||
|
||||
+ loongarch64_find_next_kernel_text(bt, ¤t)) {
|
||||
+ invalid_ok = 1;
|
||||
+ continue;
|
||||
+ }
|
||||
return;
|
||||
+ }
|
||||
|
||||
symbol = value_search(current.pc, &offset);
|
||||
- if (!symbol && !invalid_ok) {
|
||||
+ if ((!symbol || !loongarch64_is_unwind_text(current.pc)) &&
|
||||
+ !invalid_ok) {
|
||||
+ if (loongarch64_switch_from_irq_stack(bt, ¤t) ||
|
||||
+ loongarch64_find_next_kernel_text(bt, ¤t)) {
|
||||
+ invalid_ok = 1;
|
||||
+ continue;
|
||||
+ }
|
||||
error(FATAL, "PC is unknown symbol (%lx)", current.pc);
|
||||
return;
|
||||
}
|
||||
+ if (symbol && !loongarch64_is_unwind_text(current.pc))
|
||||
+ symbol = NULL;
|
||||
invalid_ok = 0;
|
||||
|
||||
/*
|
||||
@@ -557,7 +597,8 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
|
||||
if (loongarch64_orc_unwind(bt, ¤t, &previous)) {
|
||||
/* ORC has already calculated the caller frame. */
|
||||
- } else if (symbol && loongarch64_is_exception_entry(symbol)) {
|
||||
+ } else if (symbol && loongarch64_is_exception_entry(symbol) &&
|
||||
+ current.sp <= bt->stacktop - SIZE(pt_regs)) {
|
||||
|
||||
GET_STACK_DATA(current.sp, pt_regs, sizeof(pt_regs));
|
||||
regs = (struct loongarch64_pt_regs *) (pt_regs + OFFSET(pt_regs_regs));
|
||||
@@ -596,6 +637,12 @@ loongarch64_back_trace_cmd(struct bt_info *bt)
|
||||
level, current.pc, current.ra, current.sp);
|
||||
|
||||
previous.sp = previous.pc = previous.ra = previous.fp = 0;
|
||||
+
|
||||
+ if (current.sp >= bt->stacktop &&
|
||||
+ loongarch64_switch_from_irq_stack(bt, ¤t)) {
|
||||
+ invalid_ok = 1;
|
||||
+ continue;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -868,6 +915,174 @@ loongarch64_is_unwind_text(ulong pc)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+
|
||||
+static int
|
||||
+loongarch64_use_irq_prstatus_ra(ulong pc, ulong ra)
|
||||
+{
|
||||
+ struct syment *pcsym, *rasym;
|
||||
+ ulong offset;
|
||||
+
|
||||
+ if (!loongarch64_is_unwind_text(pc) ||
|
||||
+ !loongarch64_is_unwind_text(ra))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ pcsym = value_search(pc, &offset);
|
||||
+ rasym = value_search(ra, &offset);
|
||||
+ if (!pcsym || !rasym)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ return STREQ(pcsym->name, "generic_handle_domain_irq") &&
|
||||
+ STREQ(rasym->name, "handle_cpu_irq");
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+loongarch64_valid_saved_regs(struct bt_info *bt,
|
||||
+ struct loongarch64_pt_regs *regs, ulong *pc)
|
||||
+{
|
||||
+ ulong saved_pc;
|
||||
+
|
||||
+ saved_pc = loongarch64_exception_pc(bt->tc->processor, regs->csr_epc);
|
||||
+ if (!loongarch64_is_unwind_text(saved_pc))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (!INSTACK(regs->regs[LOONGARCH64_EF_SP], bt))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (regs->regs[LOONGARCH64_EF_RA] &&
|
||||
+ !loongarch64_is_unwind_text(regs->regs[LOONGARCH64_EF_RA]))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ *pc = saved_pc;
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+loongarch64_irq_stack_init(void)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct syment *sp;
|
||||
+ struct machine_specific *ms = machdep->machspec;
|
||||
+ ulong p;
|
||||
+
|
||||
+ if (!(symbol_exists("irq_stack") &&
|
||||
+ (sp = per_cpu_symbol_search("irq_stack"))))
|
||||
+ return;
|
||||
+
|
||||
+ ms->irq_stack_size = machdep->stacksize;
|
||||
+ if (!(ms->irq_stacks = (ulong *)malloc((size_t)(kt->cpus *
|
||||
+ sizeof(ulong)))))
|
||||
+ error(FATAL, "cannot malloc irq_stack addresses\n");
|
||||
+
|
||||
+ machdep->flags |= IRQSTACKS;
|
||||
+
|
||||
+ for (i = 0; i < kt->cpus; i++) {
|
||||
+ p = kt->__per_cpu_offset[i] + sp->value;
|
||||
+ if (!readmem(p, KVADDR, &ms->irq_stacks[i], sizeof(ulong),
|
||||
+ "IRQ stack pointer", RETURN_ON_ERROR))
|
||||
+ ms->irq_stacks[i] = 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+loongarch64_on_irq_stack(int cpu, ulong stkptr)
|
||||
+{
|
||||
+ struct machine_specific *ms = machdep->machspec;
|
||||
+
|
||||
+ if (cpu < 0 || cpu >= kt->cpus || !ms->irq_stacks ||
|
||||
+ !ms->irq_stacks[cpu] || !ms->irq_stack_size)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ return (stkptr >= ms->irq_stacks[cpu]) &&
|
||||
+ (stkptr < (ms->irq_stacks[cpu] + ms->irq_stack_size));
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+loongarch64_set_irq_stack(struct bt_info *bt)
|
||||
+{
|
||||
+ struct machine_specific *ms = machdep->machspec;
|
||||
+
|
||||
+ bt->stackbase = ms->irq_stacks[bt->tc->processor];
|
||||
+ bt->stacktop = bt->stackbase + ms->irq_stack_size;
|
||||
+ alter_stackbuf(bt);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+loongarch64_switch_from_irq_stack(struct bt_info *bt,
|
||||
+ struct loongarch64_unwind_frame *current)
|
||||
+{
|
||||
+ struct machine_specific *ms = machdep->machspec;
|
||||
+ struct loongarch64_pt_regs *regs;
|
||||
+ char pt_regs[SIZE(pt_regs)];
|
||||
+ ulong irq_stack, saved_sp_addr, saved_sp, saved_pc;
|
||||
+ ulong task_stackbase, task_stacktop;
|
||||
+
|
||||
+ if (bt->tc->processor < 0 || bt->tc->processor >= kt->cpus ||
|
||||
+ !ms->irq_stacks || !ms->irq_stack_size)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ irq_stack = ms->irq_stacks[bt->tc->processor];
|
||||
+ if (!irq_stack || current->sp < irq_stack ||
|
||||
+ current->sp > irq_stack + ms->irq_stack_size + 64)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ /* Matches the kernel's IRQ_STACK_START layout. */
|
||||
+ saved_sp_addr = irq_stack + ms->irq_stack_size -
|
||||
+ LOONGARCH64_IRQ_STACK_SAVED_SP_OFFSET;
|
||||
+ if (!readmem(saved_sp_addr, KVADDR, &saved_sp, sizeof(saved_sp),
|
||||
+ "saved task stack pointer", RETURN_ON_ERROR))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ task_stackbase = GET_STACKBASE(bt->task);
|
||||
+ task_stacktop = GET_STACKTOP(bt->task);
|
||||
+ if (saved_sp < task_stackbase || saved_sp >= task_stacktop)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ bt->stackbase = task_stackbase;
|
||||
+ bt->stacktop = task_stacktop;
|
||||
+ alter_stackbuf(bt);
|
||||
+ if (saved_sp <= bt->stacktop - SIZE(pt_regs)) {
|
||||
+ GET_STACK_DATA(saved_sp, pt_regs, sizeof(pt_regs));
|
||||
+ regs = (struct loongarch64_pt_regs *)(pt_regs +
|
||||
+ OFFSET(pt_regs_regs));
|
||||
+ if (loongarch64_valid_saved_regs(bt, regs, &saved_pc)) {
|
||||
+ current->pc = saved_pc;
|
||||
+ current->sp = regs->regs[LOONGARCH64_EF_SP];
|
||||
+ current->ra = regs->regs[LOONGARCH64_EF_RA];
|
||||
+ current->fp = regs->regs[LOONGARCH64_EF_FP];
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ current->sp = saved_sp;
|
||||
+ current->ra = 0;
|
||||
+ return loongarch64_find_next_kernel_text(bt, current);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+loongarch64_find_next_kernel_text(struct bt_info *bt,
|
||||
+ struct loongarch64_unwind_frame *current)
|
||||
+{
|
||||
+ ulong sp, pc;
|
||||
+
|
||||
+ if (!INSTACK(current->sp, bt))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ sp = current->sp + sizeof(ulong);
|
||||
+ sp = roundup(sp, sizeof(ulong));
|
||||
+ for (; sp < bt->stacktop; sp += sizeof(ulong)) {
|
||||
+ GET_STACK_DATA(sp, &pc, sizeof(pc));
|
||||
+ pc = loongarch64_exception_pc(bt->tc->processor, pc);
|
||||
+ if (!loongarch64_is_unwind_text(pc))
|
||||
+ continue;
|
||||
+
|
||||
+ current->pc = pc;
|
||||
+ current->sp = sp;
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
loongarch64_orc_ip(ulong ip_entry_addr, ulong *ip)
|
||||
{
|
||||
@@ -1218,6 +1433,7 @@ loongarch64_stackframe_init(void)
|
||||
|
||||
MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus", "pr_reg");
|
||||
STRUCT_SIZE_INIT(note_buf, "note_buf_t");
|
||||
+ loongarch64_irq_stack_init();
|
||||
}
|
||||
|
||||
/*
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
From a35fcc79393cbe84dbf00b663a3be705efb256e0 Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Tue, 16 Jun 2026 20:47:45 +0800
|
||||
Subject: [PATCH 28/39] LoongArch64: avoid replacing a valid RA with stack
|
||||
noise
|
||||
|
||||
The fallback prologue scanner may find a saved RA slot and read a word
|
||||
from the stack. In corrupted, interrupted, or partially unwound frames,
|
||||
that word is not guaranteed to be a kernel return address.
|
||||
|
||||
Do not blindly replace the current RA with the scanned stack value. Keep
|
||||
the existing RA unless the scanned value is a kernel address, or unless
|
||||
the current RA is already not a kernel address. This keeps the fallback
|
||||
scanner from discarding a better caller candidate with obvious stack
|
||||
noise.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
loongarch64.c | 16 +++++++++++-----
|
||||
1 file changed, 11 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index c25a3bbf6d6c..34e29c9f2d67 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -702,11 +702,17 @@ loongarch64_analyze_function(ulong start, ulong offset,
|
||||
|
||||
previous->sp = current->sp + spadjust;
|
||||
|
||||
- if (rapos && !readmem(rapos, KVADDR, ¤t->ra,
|
||||
- sizeof(current->ra), "RA from stack",
|
||||
- RETURN_ON_ERROR)) {
|
||||
- error(FATAL, "Cannot read RA from stack %lx", rapos);
|
||||
- return;
|
||||
+ if (rapos) {
|
||||
+ ulong ra;
|
||||
+
|
||||
+ if (!readmem(rapos, KVADDR, &ra, sizeof(ra), "RA from stack",
|
||||
+ RETURN_ON_ERROR)) {
|
||||
+ error(FATAL, "Cannot read RA from stack %lx", rapos);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (IS_KVADDR(ra) || !IS_KVADDR(current->ra))
|
||||
+ current->ra = ra;
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
From 2946d9bfa656a59156c20641e743494c316b323c Mon Sep 17 00:00:00 2001
|
||||
From: Ming Wang <wangming01@loongson.cn>
|
||||
Date: Tue, 16 Jun 2026 20:47:46 +0800
|
||||
Subject: [PATCH 29/39] LoongArch64: print exception registers only with bt -f
|
||||
|
||||
LoongArch64 exception frames include a full pt_regs dump. Printing that
|
||||
register block in normal bt output makes the backtrace harder to scan and
|
||||
visually separates the exception frame from the frames that follow it.
|
||||
|
||||
Keep normal bt output focused on stack frames and print the exception
|
||||
register block only for full backtraces. The detailed data remains
|
||||
available with bt -f, where crash already prints per-frame stack details.
|
||||
|
||||
Signed-off-by: Ming Wang <wangming01@loongson.cn>
|
||||
---
|
||||
loongarch64.c | 9 ++++-----
|
||||
1 file changed, 4 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/loongarch64.c b/loongarch64.c
|
||||
index 34e29c9f2d67..39a05b854832 100644
|
||||
--- a/loongarch64.c
|
||||
+++ b/loongarch64.c
|
||||
@@ -755,13 +755,12 @@ loongarch64_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,
|
||||
fprintf(fp, " %s\n", buf);
|
||||
}
|
||||
|
||||
- if (sym && loongarch64_is_exception_entry(sym)) {
|
||||
- GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs));
|
||||
- loongarch64_dump_exception_stack(bt, pt_regs);
|
||||
- }
|
||||
-
|
||||
/* bt -f */
|
||||
if (bt->flags & BT_FULL) {
|
||||
+ if (sym && loongarch64_is_exception_entry(sym)) {
|
||||
+ GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs));
|
||||
+ loongarch64_dump_exception_stack(bt, pt_regs);
|
||||
+ }
|
||||
fprintf(fp, " "
|
||||
"[PC: %016lx RA: %016lx SP: %016lx SIZE: %ld]\n",
|
||||
current->pc, current->ra, current->sp,
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
From f6084e0dbf363d3d27075b3f3a193a9ae37c1df5 Mon Sep 17 00:00:00 2001
|
||||
From: Rui Qi <qirui.001@bytedance.com>
|
||||
Date: Mon, 22 Jun 2026 21:26:39 +0800
|
||||
Subject: [PATCH 30/39] riscv64: Set VMEMMAP flag to fix spurious mem_map[]
|
||||
warnings
|
||||
|
||||
RISC-V kernels use CONFIG_SPARSEMEM_VMEMMAP, and the crash utility
|
||||
correctly reads VMEMMAP_START/VMEMMAP_END from VMCOREINFO. However,
|
||||
riscv64.c never sets the VMEMMAP flag on machdep->flags, unlike arm64
|
||||
and x86_64 which always set it.
|
||||
|
||||
This causes fill_mem_map_cache() in memory.c to emit spurious warnings
|
||||
when it fails to read page structs from vmemmap holes:
|
||||
|
||||
WARNING: mem_map[] from ffff8d8002470000 to ffff8d8002471000 not accessible
|
||||
|
||||
With SPARSEMEM_VMEMMAP, unmapped holes in the vmemmap region are
|
||||
expected -- a mem_section that has no corresponding physical memory
|
||||
simply has no page struct mapped. The VMEMMAP flag tells crash that
|
||||
such read failures are normal, suppressing the inappropriate warnings.
|
||||
|
||||
Set VMEMMAP in the PRE_GDB stage when vmemmap_vaddr is valid, and
|
||||
display the flag in riscv64_dump_machdep_table() for debugging.
|
||||
|
||||
Signed-off-by: Rui Qi <qirui.001@bytedance.com>
|
||||
---
|
||||
riscv64.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/riscv64.c b/riscv64.c
|
||||
index f0783d570c7b..a43afbdcebd2 100644
|
||||
--- a/riscv64.c
|
||||
+++ b/riscv64.c
|
||||
@@ -244,6 +244,8 @@ riscv64_dump_machdep_table(ulong arg)
|
||||
fprintf(fp, "%sIRQ_STACKS", others++ ? "|" : "");
|
||||
if (machdep->flags & OVERFLOW_STACKS)
|
||||
fprintf(fp, "%sOVERFLOW_STACKS", others++ ? "|" : "");
|
||||
+ if (machdep->flags & VMEMMAP)
|
||||
+ fprintf(fp, "%sVMEMMAP", others++ ? "|" : "");
|
||||
fprintf(fp, ")\n");
|
||||
|
||||
fprintf(fp, " kvbase: %lx\n", machdep->kvbase);
|
||||
@@ -1749,6 +1751,9 @@ riscv64_init(int when)
|
||||
machdep->show_interrupts = generic_show_interrupts;
|
||||
machdep->get_irq_affinity = generic_get_irq_affinity;
|
||||
machdep->init_kernel_pgd = NULL; /* pgd set by symbol_value("swapper_pg_dir") */
|
||||
+
|
||||
+ if (machdep->machspec->vmemmap_vaddr)
|
||||
+ machdep->flags |= VMEMMAP;
|
||||
break;
|
||||
|
||||
case POST_GDB:
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,93 @@
|
||||
From f5ce0c39b5b414727f8c2d7491714a80f8ff4396 Mon Sep 17 00:00:00 2001
|
||||
From: Rui Qi <qirui.001@bytedance.com>
|
||||
Date: Mon, 22 Jun 2026 21:26:40 +0800
|
||||
Subject: [PATCH 31/39] riscv64: Guard verbose output in vtop page table walk
|
||||
functions
|
||||
|
||||
The riscv64_vtop_{3,4,5}level_4k() functions print "PAGE: not present"
|
||||
and "invalid for address" messages unconditionally, even when called
|
||||
with verbose=0. This produces noisy output during internal address
|
||||
translations such as kmem -p or dump_mem_map, where kvtop() is called
|
||||
non-verbosely to check whether a page struct is mapped.
|
||||
|
||||
All other diagnostic output in these functions is already guarded by
|
||||
"if (verbose)". Move the not-present and no_page messages inside
|
||||
the verbose block to match.
|
||||
|
||||
Also fix the 5-level function which used printf() instead of
|
||||
fprintf(fp, ...) for the !_PAGE_PRESENT debug message, and replace
|
||||
it with the same verbose-guarded format used by the 3-level and
|
||||
4-level functions.
|
||||
|
||||
Signed-off-by: Rui Qi <qirui.001@bytedance.com>
|
||||
---
|
||||
riscv64.c | 15 +++++++++------
|
||||
1 file changed, 9 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/riscv64.c b/riscv64.c
|
||||
index a43afbdcebd2..02210267862f 100644
|
||||
--- a/riscv64.c
|
||||
+++ b/riscv64.c
|
||||
@@ -683,8 +683,8 @@ riscv64_vtop_3level_4k(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
|
||||
if (verbose) {
|
||||
fprintf(fp, "\n");
|
||||
riscv64_translate_pte((ulong)pte_val, 0, 0);
|
||||
+ fprintf(fp, " PAGE: %016lx not present\n\n", PAGEBASE(*paddr));
|
||||
}
|
||||
- fprintf(fp, " PAGE: %016lx not present\n\n", PAGEBASE(*paddr));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -697,7 +697,8 @@ riscv64_vtop_3level_4k(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
|
||||
|
||||
return TRUE;
|
||||
no_page:
|
||||
- fprintf(fp, "invalid for %lx address\n", vaddr);
|
||||
+ if (verbose)
|
||||
+ fprintf(fp, "invalid for %lx address\n", vaddr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1275,8 +1276,8 @@ riscv64_vtop_4level_4k(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
|
||||
if (verbose) {
|
||||
fprintf(fp, "\n");
|
||||
riscv64_translate_pte((ulong)pte_val, 0, 0);
|
||||
+ fprintf(fp, " PAGE: %016lx not present\n\n", PAGEBASE(*paddr));
|
||||
}
|
||||
- fprintf(fp, " PAGE: %016lx not present\n\n", PAGEBASE(*paddr));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1289,7 +1290,8 @@ riscv64_vtop_4level_4k(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
|
||||
|
||||
return TRUE;
|
||||
no_page:
|
||||
- fprintf(fp, "invalid for %lx address\n", vaddr);
|
||||
+ if (verbose)
|
||||
+ fprintf(fp, "invalid for %lx address\n", vaddr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1364,8 +1366,8 @@ riscv64_vtop_5level_4k(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
|
||||
if (verbose) {
|
||||
fprintf(fp, "\n");
|
||||
riscv64_translate_pte((ulong)pte_val, 0, 0);
|
||||
+ fprintf(fp, " PAGE: %016lx not present\n\n", PAGEBASE(*paddr));
|
||||
}
|
||||
- printf("!_PAGE_PRESENT\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -1378,7 +1380,8 @@ riscv64_vtop_5level_4k(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
|
||||
|
||||
return TRUE;
|
||||
no_page:
|
||||
- fprintf(fp, "invalid for %lx address\n", vaddr);
|
||||
+ if (verbose)
|
||||
+ fprintf(fp, "invalid for %lx address\n", vaddr);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,98 @@
|
||||
From 18d6e9f4852f19fddcd17fe14b7dfadae92fbc70 Mon Sep 17 00:00:00 2001
|
||||
From: Rui Qi <qirui.001@bytedance.com>
|
||||
Date: Mon, 22 Jun 2026 21:26:41 +0800
|
||||
Subject: [PATCH 32/39] riscv64: Add get_kvaddr_ranges callback for kernel
|
||||
address ranges
|
||||
|
||||
Register an architecture-specific get_kvaddr_ranges callback so that
|
||||
the search command can properly enumerate all kernel virtual address
|
||||
regions including modules and vmemmap.
|
||||
|
||||
Without this callback, riscv64 falls back to generic_get_kvaddr_ranges()
|
||||
which only knows about KVADDR_UNITY_MAP and KVADDR_VMALLOC, missing
|
||||
the modules and vmemmap regions. While the generic VMALLOC range covers
|
||||
these addresses (its end is -1), the type information is lost, making
|
||||
it impossible for consumers to distinguish between different kernel
|
||||
address space regions.
|
||||
|
||||
Signed-off-by: Rui Qi <qirui.001@bytedance.com>
|
||||
---
|
||||
riscv64.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 48 insertions(+)
|
||||
|
||||
diff --git a/riscv64.c b/riscv64.c
|
||||
index 02210267862f..4dcecc2f6b2c 100644
|
||||
--- a/riscv64.c
|
||||
+++ b/riscv64.c
|
||||
@@ -62,6 +62,7 @@ static void riscv64_set_process_stack(struct bt_info *);
|
||||
static void riscv64_set_irq_stack(struct bt_info *);
|
||||
static int riscv64_on_overflow_stack(int, ulong);
|
||||
static void riscv64_set_overflow_stack(struct bt_info *);
|
||||
+static int riscv64_get_kvaddr_ranges(struct vaddr_range *);
|
||||
|
||||
#define REG_FMT "%016lx"
|
||||
#define SZ_2G 0x80000000
|
||||
@@ -1757,6 +1758,7 @@ riscv64_init(int when)
|
||||
|
||||
if (machdep->machspec->vmemmap_vaddr)
|
||||
machdep->flags |= VMEMMAP;
|
||||
+ machdep->get_kvaddr_ranges = riscv64_get_kvaddr_ranges;
|
||||
break;
|
||||
|
||||
case POST_GDB:
|
||||
@@ -2018,6 +2020,52 @@ riscv64_eframe_search(struct bt_info *bt)
|
||||
return count;
|
||||
}
|
||||
|
||||
+static int
|
||||
+compare_kvaddr(const void *v1, const void *v2)
|
||||
+{
|
||||
+ struct vaddr_range *r1, *r2;
|
||||
+
|
||||
+ r1 = (struct vaddr_range *)v1;
|
||||
+ r2 = (struct vaddr_range *)v2;
|
||||
+
|
||||
+ return (r1->start < r2->start ? -1 :
|
||||
+ r1->start == r2->start ? 0 : 1);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+riscv64_get_kvaddr_ranges(struct vaddr_range *vrp)
|
||||
+{
|
||||
+ int cnt;
|
||||
+
|
||||
+ cnt = 0;
|
||||
+
|
||||
+ vrp[cnt].type = KVADDR_UNITY_MAP;
|
||||
+ vrp[cnt].start = machdep->machspec->page_offset;
|
||||
+ vrp[cnt++].end = vt->high_memory;
|
||||
+
|
||||
+ vrp[cnt].type = KVADDR_VMALLOC;
|
||||
+ vrp[cnt].start = machdep->machspec->vmalloc_start_addr;
|
||||
+ vrp[cnt++].end = last_vmalloc_address();
|
||||
+
|
||||
+ if (st->mods_installed) {
|
||||
+ vrp[cnt].type = KVADDR_MODULES;
|
||||
+ vrp[cnt].start = lowest_module_address();
|
||||
+ vrp[cnt++].end = roundup(highest_module_address(),
|
||||
+ PAGESIZE());
|
||||
+ }
|
||||
+
|
||||
+ if (machdep->flags & VMEMMAP) {
|
||||
+ vrp[cnt].type = KVADDR_VMEMMAP;
|
||||
+ vrp[cnt].start = machdep->machspec->vmemmap_vaddr;
|
||||
+ vrp[cnt++].end = vt->node_table[vt->numnodes-1].mem_map +
|
||||
+ (vt->node_table[vt->numnodes-1].size * SIZE(page));
|
||||
+ }
|
||||
+
|
||||
+ qsort(vrp, cnt, sizeof(struct vaddr_range), compare_kvaddr);
|
||||
+
|
||||
+ return cnt;
|
||||
+}
|
||||
+
|
||||
#else /* !RISCV64 */
|
||||
|
||||
void
|
||||
--
|
||||
2.54.0
|
||||
|
||||
184
0033-task-Introduce-I-option-to-ps-command-to-exclude-idl.patch
Normal file
184
0033-task-Introduce-I-option-to-ps-command-to-exclude-idl.patch
Normal file
@ -0,0 +1,184 @@
|
||||
From 610e52023a425436d91168744dbb2ae047b63837 Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Tomlin <atomlin@atomlin.com>
|
||||
Date: Sat, 4 Jul 2026 12:26:57 -0400
|
||||
Subject: [PATCH 33/39] task: Introduce -I option to ps command to exclude idle
|
||||
tasks
|
||||
|
||||
Adds a new option '-I' to the 'ps' command to filter out idle
|
||||
threads/tasks from the output. This filters out the idle tasks from the
|
||||
main ps list, CPU-specific block lists, and task time reports, while
|
||||
enforcing mutual exclusivity with the summary (-S) option.
|
||||
|
||||
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
|
||||
---
|
||||
defs.h | 1 +
|
||||
help.c | 3 ++-
|
||||
task.c | 32 ++++++++++++++++++++++++--------
|
||||
3 files changed, 27 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index bdb4eb3e0980..ed91a5bc8e91 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -5403,6 +5403,7 @@ extern long _ZOMBIE_;
|
||||
#define PS_SUMMARY (0x40000)
|
||||
#define PS_POLICY (0x80000)
|
||||
#define PS_ACTIVE (0x100000)
|
||||
+#define PS_EXCLUDE_IDLE (0x200000)
|
||||
|
||||
#define PS_EXCLUSIVE (PS_TGID_LIST|PS_ARGV_ENVP|PS_TIMES|PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN|PS_RLIMIT|PS_MSECS|PS_SUMMARY|PS_ACTIVE)
|
||||
|
||||
diff --git a/help.c b/help.c
|
||||
index 5cd5c30e99a3..c88797e8ae70 100644
|
||||
--- a/help.c
|
||||
+++ b/help.c
|
||||
@@ -1392,7 +1392,7 @@ NULL
|
||||
char *help_ps[] = {
|
||||
"ps",
|
||||
"display process status information",
|
||||
-"[-k|-u|-G|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S|-A|-H]\n [pid | task | command] ...",
|
||||
+"[-k|-u|-G|-I|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S|-A|-H]\n [pid | task | command] ...",
|
||||
" This command displays process status for selected, or all, processes" ,
|
||||
" in the system. If no arguments are entered, the process data is",
|
||||
" is displayed for all processes. Specific processes may be selected",
|
||||
@@ -1409,6 +1409,7 @@ char *help_ps[] = {
|
||||
" -k restrict the output to only kernel threads.",
|
||||
" -u restrict the output to only user tasks.",
|
||||
" -G display only the thread group leader in a thread group.",
|
||||
+" -I exclude idle threads/tasks from the output.",
|
||||
" -y policy restrict the output to tasks having a specified scheduling policy",
|
||||
" expressed by its integer value or by its (case-insensitive) name;",
|
||||
" multiple policies may be entered in a comma-separated list:",
|
||||
diff --git a/task.c b/task.c
|
||||
index d7f3c129a709..25b929d791b3 100644
|
||||
--- a/task.c
|
||||
+++ b/task.c
|
||||
@@ -107,8 +107,8 @@ static void foreach_cleanup(void *);
|
||||
static void ps_cleanup(void *);
|
||||
static char *task_pointer_string(struct task_context *, ulong, char *);
|
||||
static int panic_context_adjusted(struct task_context *tc);
|
||||
-static void show_last_run(struct task_context *, struct psinfo *);
|
||||
-static void show_milliseconds(struct task_context *, struct psinfo *);
|
||||
+static void show_last_run(ulong, struct task_context *, struct psinfo *);
|
||||
+static void show_milliseconds(ulong, struct task_context *, struct psinfo *);
|
||||
static char *translate_nanoseconds(ulonglong, char *);
|
||||
static int sort_by_last_run(const void *arg1, const void *arg2);
|
||||
static void sort_context_array_by_last_run(void);
|
||||
@@ -3534,7 +3534,7 @@ cmd_ps(void)
|
||||
cpuspec = NULL;
|
||||
flag = 0;
|
||||
|
||||
- while ((c = getopt(argcnt, args, "HASgstcpkuGlmarC:y:")) != EOF) {
|
||||
+ while ((c = getopt(argcnt, args, "HAISgstcpkuGlmarC:y:")) != EOF) {
|
||||
switch(c)
|
||||
{
|
||||
case 'k':
|
||||
@@ -3645,6 +3645,10 @@ cmd_ps(void)
|
||||
flag |= PS_ACTIVE;
|
||||
break;
|
||||
|
||||
+ case 'I':
|
||||
+ flag |= PS_EXCLUDE_IDLE;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
flag |= PS_NO_HEADER;
|
||||
break;
|
||||
@@ -3794,6 +3798,8 @@ show_ps_data(ulong flag, struct task_context *tc, struct psinfo *psi)
|
||||
return;
|
||||
if ((flag & PS_POLICY) && !has_sched_policy(tc->task, psi->policy))
|
||||
return;
|
||||
+ if (tc && (flag & PS_EXCLUDE_IDLE) && is_idle_thread(tc->task))
|
||||
+ return;
|
||||
if (flag & PS_GROUP) {
|
||||
if (flag & (PS_LAST_RUN|PS_MSECS))
|
||||
error(FATAL, "-G not supported with -%c option\n",
|
||||
@@ -3827,11 +3833,11 @@ show_ps_data(ulong flag, struct task_context *tc, struct psinfo *psi)
|
||||
return;
|
||||
}
|
||||
if (flag & (PS_LAST_RUN)) {
|
||||
- show_last_run(tc, psi);
|
||||
+ show_last_run(flag, tc, psi);
|
||||
return;
|
||||
}
|
||||
if (flag & (PS_MSECS)) {
|
||||
- show_milliseconds(tc, psi);
|
||||
+ show_milliseconds(flag, tc, psi);
|
||||
return;
|
||||
}
|
||||
if (flag & PS_ARGV_ENVP) {
|
||||
@@ -3988,7 +3994,7 @@ show_ps_summary(ulong flag)
|
||||
char string[3];
|
||||
} ps_state[MAX_STATES];
|
||||
|
||||
- if (flag & (PS_USER|PS_KERNEL|PS_GROUP))
|
||||
+ if (flag & (PS_USER|PS_KERNEL|PS_GROUP|PS_EXCLUDE_IDLE))
|
||||
error(FATAL, "-S option cannot be used with other options\n");
|
||||
|
||||
for (s = 0; s < MAX_STATES; s++)
|
||||
@@ -4023,7 +4029,7 @@ show_ps_summary(ulong flag)
|
||||
* current state.
|
||||
*/
|
||||
static void
|
||||
-show_last_run(struct task_context *tc, struct psinfo *psi)
|
||||
+show_last_run(ulong flag, struct task_context *tc, struct psinfo *psi)
|
||||
{
|
||||
int i, c, others;
|
||||
struct task_context *tcp;
|
||||
@@ -4053,6 +4059,8 @@ show_last_run(struct task_context *tc, struct psinfo *psi)
|
||||
for (i = 0; i < RUNNING_TASKS(); i++, tcp++) {
|
||||
if (tcp->processor != c)
|
||||
continue;
|
||||
+ if ((flag & PS_EXCLUDE_IDLE) && is_idle_thread(tcp->task))
|
||||
+ continue;
|
||||
fprintf(fp, format, task_last_run(tcp->task));
|
||||
fprintf(fp, "[%s] ",
|
||||
task_state_string(tcp->task, buf, !VERBOSE));
|
||||
@@ -4066,6 +4074,8 @@ show_last_run(struct task_context *tc, struct psinfo *psi)
|
||||
} else {
|
||||
tcp = FIRST_CONTEXT();
|
||||
for (i = 0; i < RUNNING_TASKS(); i++, tcp++) {
|
||||
+ if ((flag & PS_EXCLUDE_IDLE) && is_idle_thread(tcp->task))
|
||||
+ continue;
|
||||
fprintf(fp, format, task_last_run(tcp->task));
|
||||
fprintf(fp, "[%s] ", task_state_string(tcp->task, buf, !VERBOSE));
|
||||
print_task_header(fp, tcp, FALSE);
|
||||
@@ -4104,7 +4114,7 @@ translate_nanoseconds(ulonglong value, char *buf)
|
||||
* sched_info.last_arrival and its current state.
|
||||
*/
|
||||
static void
|
||||
-show_milliseconds(struct task_context *tc, struct psinfo *psi)
|
||||
+show_milliseconds(ulong flag, struct task_context *tc, struct psinfo *psi)
|
||||
{
|
||||
int i, c, others, days, max_days;
|
||||
struct task_context *tcp;
|
||||
@@ -4154,6 +4164,8 @@ show_milliseconds(struct task_context *tc, struct psinfo *psi)
|
||||
for (i = 0; i < RUNNING_TASKS(); i++, tcp++) {
|
||||
if (tcp->processor != c)
|
||||
continue;
|
||||
+ if ((flag & PS_EXCLUDE_IDLE) && is_idle_thread(tcp->task))
|
||||
+ continue;
|
||||
delta = rq_clock - task_last_run(tcp->task);
|
||||
if (delta < 0)
|
||||
delta = 0;
|
||||
@@ -4188,6 +4200,8 @@ show_milliseconds(struct task_context *tc, struct psinfo *psi)
|
||||
} else {
|
||||
tcp = FIRST_CONTEXT();
|
||||
for (i = 0; i < RUNNING_TASKS(); i++, tcp++) {
|
||||
+ if ((flag & PS_EXCLUDE_IDLE) && is_idle_thread(tcp->task))
|
||||
+ continue;
|
||||
if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF))
|
||||
runq = rq_sp->value +
|
||||
kt->__per_cpu_offset[tcp->processor];
|
||||
@@ -4562,6 +4576,8 @@ show_task_times(struct task_context *tcp, ulong flags)
|
||||
continue;
|
||||
if ((flags & PS_KERNEL) && !is_kernel_thread(tc->task))
|
||||
continue;
|
||||
+ if ((flags & PS_EXCLUDE_IDLE) && is_idle_thread(tc->task))
|
||||
+ continue;
|
||||
if (flags & PS_GROUP) {
|
||||
tgid = task_tgid(tc->task);
|
||||
if (tc->pid != tgid) {
|
||||
--
|
||||
2.54.0
|
||||
|
||||
175
0034-task-Introduce-Y-option-to-ps-command-to-display-sch.patch
Normal file
175
0034-task-Introduce-Y-option-to-ps-command-to-display-sch.patch
Normal file
@ -0,0 +1,175 @@
|
||||
From 97b7c0a6085212ccb2dcc5e1b302906db6080d51 Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Tomlin <atomlin@atomlin.com>
|
||||
Date: Sat, 4 Jul 2026 14:14:50 -0400
|
||||
Subject: [PATCH 34/39] task: Introduce -Y option to ps command to display
|
||||
scheduling policy and priority
|
||||
|
||||
Adds a new option '-Y' to the 'ps' command to print scheduling policy
|
||||
(e.g., NORMAL, FIFO, RR, etc.) and dynamic priority (prio) for each
|
||||
task.
|
||||
|
||||
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
|
||||
---
|
||||
defs.h | 3 ++-
|
||||
help.c | 3 ++-
|
||||
task.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
3 files changed, 68 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index ed91a5bc8e91..d7bcdd083671 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -5404,8 +5404,9 @@ extern long _ZOMBIE_;
|
||||
#define PS_POLICY (0x80000)
|
||||
#define PS_ACTIVE (0x100000)
|
||||
#define PS_EXCLUDE_IDLE (0x200000)
|
||||
+#define PS_POLICY_DATA (0x400000)
|
||||
|
||||
-#define PS_EXCLUSIVE (PS_TGID_LIST|PS_ARGV_ENVP|PS_TIMES|PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN|PS_RLIMIT|PS_MSECS|PS_SUMMARY|PS_ACTIVE)
|
||||
+#define PS_EXCLUSIVE (PS_TGID_LIST|PS_ARGV_ENVP|PS_TIMES|PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN|PS_RLIMIT|PS_MSECS|PS_SUMMARY|PS_ACTIVE|PS_POLICY_DATA)
|
||||
|
||||
#define MAX_PS_ARGS (100) /* maximum command-line specific requests */
|
||||
|
||||
diff --git a/help.c b/help.c
|
||||
index c88797e8ae70..79bfa5ba0844 100644
|
||||
--- a/help.c
|
||||
+++ b/help.c
|
||||
@@ -1392,7 +1392,7 @@ NULL
|
||||
char *help_ps[] = {
|
||||
"ps",
|
||||
"display process status information",
|
||||
-"[-k|-u|-G|-I|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S|-A|-H]\n [pid | task | command] ...",
|
||||
+"[-k|-u|-G|-I|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S|-A|-H|-Y]\n [pid | task | command] ...",
|
||||
" This command displays process status for selected, or all, processes" ,
|
||||
" in the system. If no arguments are entered, the process data is",
|
||||
" is displayed for all processes. Specific processes may be selected",
|
||||
@@ -1473,6 +1473,7 @@ char *help_ps[] = {
|
||||
" -S display a summary consisting of the number of tasks in a task state.",
|
||||
" -A display only the active task on each cpu.",
|
||||
" -H display no header line.",
|
||||
+" -Y display the task's scheduling policy and priority.",
|
||||
"\nEXAMPLES",
|
||||
" Show the process status of all current tasks:\n",
|
||||
" %s> ps",
|
||||
diff --git a/task.c b/task.c
|
||||
index 25b929d791b3..7dacb05b2406 100644
|
||||
--- a/task.c
|
||||
+++ b/task.c
|
||||
@@ -118,6 +118,8 @@ static void parse_task_thread(int argcnt, char *arglist[], struct task_context *
|
||||
static void stack_overflow_check_init(void);
|
||||
static int has_sched_policy(ulong, ulong);
|
||||
static ulong task_policy(ulong);
|
||||
+static const char *task_policy_name(ulong);
|
||||
+static int task_prio(ulong);
|
||||
static ulong sched_policy_bit_from_str(const char *);
|
||||
static ulong make_sched_policy(const char *);
|
||||
void crash_get_current_task_info(unsigned long *, char **);
|
||||
@@ -3534,7 +3536,7 @@ cmd_ps(void)
|
||||
cpuspec = NULL;
|
||||
flag = 0;
|
||||
|
||||
- while ((c = getopt(argcnt, args, "HAISgstcpkuGlmarC:y:")) != EOF) {
|
||||
+ while ((c = getopt(argcnt, args, "HAISgstcpkuGlmarC:y:Y")) != EOF) {
|
||||
switch(c)
|
||||
{
|
||||
case 'k':
|
||||
@@ -3649,6 +3651,11 @@ cmd_ps(void)
|
||||
flag |= PS_EXCLUDE_IDLE;
|
||||
break;
|
||||
|
||||
+ case 'Y':
|
||||
+ check_ps_exclusive(flag, PS_POLICY_DATA);
|
||||
+ flag |= PS_POLICY_DATA;
|
||||
+ break;
|
||||
+
|
||||
case 'H':
|
||||
flag |= PS_NO_HEADER;
|
||||
break;
|
||||
@@ -3822,6 +3829,31 @@ show_ps_data(ulong flag, struct task_context *tc, struct psinfo *psi)
|
||||
}
|
||||
}
|
||||
|
||||
+ if (flag & PS_POLICY_DATA) {
|
||||
+ task_active = is_task_active(tc->task);
|
||||
+
|
||||
+ if (task_active) {
|
||||
+ if (hide_offline_cpu(tc->processor))
|
||||
+ fprintf(fp, "- ");
|
||||
+ else
|
||||
+ fprintf(fp, "> ");
|
||||
+ } else
|
||||
+ fprintf(fp, " ");
|
||||
+
|
||||
+ fprintf(fp, "%7ld %7ld %3s %s %-12s %4d ",
|
||||
+ tc->pid, task_to_pid(tc->ptask),
|
||||
+ task_cpu(tc->processor, buf2, !VERBOSE),
|
||||
+ task_pointer_string(tc, flag & PS_KSTACKP, buf3),
|
||||
+ task_policy_name(tc->task),
|
||||
+ task_prio(tc->task));
|
||||
+
|
||||
+ if (is_kernel_thread(tc->task))
|
||||
+ fprintf(fp, "[%s]\n", tc->comm);
|
||||
+ else
|
||||
+ fprintf(fp, "%s\n", tc->comm);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (flag & PS_PPID_LIST) {
|
||||
parent_list(tc->task);
|
||||
fprintf(fp, "\n");
|
||||
@@ -3902,6 +3934,14 @@ show_ps(ulong flag, struct psinfo *psi)
|
||||
mkstring(buf, VADDR_PRLEN, CENTER|RJUST, "KSTACKP") :
|
||||
mkstring(buf, VADDR_PRLEN, CENTER, "TASK"));
|
||||
|
||||
+ if ((flag & PS_POLICY_DATA) && !(flag & PS_NO_HEADER)) {
|
||||
+ fprintf(fp,
|
||||
+ " PID PPID CPU %s POLICY PRIO COMM\n",
|
||||
+ flag & PS_KSTACKP ?
|
||||
+ mkstring(buf, VADDR_PRLEN, CENTER|RJUST, "KSTACKP") :
|
||||
+ mkstring(buf, VADDR_PRLEN, CENTER, "TASK"));
|
||||
+ }
|
||||
+
|
||||
if (flag & PS_SHOW_ALL) {
|
||||
|
||||
if (flag & PS_TIMES) {
|
||||
@@ -3994,7 +4034,7 @@ show_ps_summary(ulong flag)
|
||||
char string[3];
|
||||
} ps_state[MAX_STATES];
|
||||
|
||||
- if (flag & (PS_USER|PS_KERNEL|PS_GROUP|PS_EXCLUDE_IDLE))
|
||||
+ if (flag & (PS_USER|PS_KERNEL|PS_GROUP|PS_EXCLUDE_IDLE|PS_POLICY_DATA))
|
||||
error(FATAL, "-S option cannot be used with other options\n");
|
||||
|
||||
for (s = 0; s < MAX_STATES; s++)
|
||||
@@ -6050,6 +6090,28 @@ task_policy(ulong task)
|
||||
return policy;
|
||||
}
|
||||
|
||||
+static const char *
|
||||
+task_policy_name(ulong task)
|
||||
+{
|
||||
+ ulong policy_bit = task_policy(task);
|
||||
+ struct sched_policy_info *info;
|
||||
+
|
||||
+ for (info = sched_policy_info; info->name; info++) {
|
||||
+ if (policy_bit == (1UL << info->value))
|
||||
+ return info->name;
|
||||
+ }
|
||||
+ return "UNKNOWN";
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+task_prio(ulong task)
|
||||
+{
|
||||
+ fill_task_struct(task);
|
||||
+ if (!tt->last_task_read || INVALID_MEMBER(task_struct_prio))
|
||||
+ return 0;
|
||||
+ return INT(tt->task_struct + OFFSET(task_struct_prio));
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Return a task's tgid.
|
||||
*/
|
||||
--
|
||||
2.54.0
|
||||
|
||||
180
0035-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch
Normal file
180
0035-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch
Normal file
@ -0,0 +1,180 @@
|
||||
From 82039b0f21de4231d1fc03e8819c868a84b213f8 Mon Sep 17 00:00:00 2001
|
||||
From: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
Date: Wed, 8 Jul 2026 02:45:50 +0000
|
||||
Subject: [PATCH 35/39] Fix failure of "runq -g" option on Linux 7.2 and later
|
||||
kernels
|
||||
|
||||
Kernel commit b8fea7af0e40 ("sched/fair: Allocate cfs_tg_state with
|
||||
percpu allocator") changed task_group.cfs_rq from a pointer array to a
|
||||
per-cpu variable allocated by the per-cpu allocator.
|
||||
|
||||
Without the patch, the "runq -g" option fails with the following error
|
||||
on the first time, and with a segmentation fault on the second time.
|
||||
|
||||
crash> runq -g
|
||||
CPU 0
|
||||
CURRENT: PID: 5687 TASK: ffff8b0bc175a2c0 COMMAND: "bash"
|
||||
ROOT_TASK_GROUP: ffffffff93a55600 CFS_RQ: 0
|
||||
runq: invalid kernel virtual address: 58 type: "curr"
|
||||
crash> runq -g
|
||||
Segmentation fault (core dumped)
|
||||
|
||||
Since there is no way to determine whether it is a per-cpu variable,
|
||||
check wthether it is a pointer array or not.
|
||||
|
||||
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
---
|
||||
defs.h | 2 ++
|
||||
kernel.c | 14 ++++++++++++++
|
||||
symbols.c | 27 +++++++++++++++++++++++++++
|
||||
task.c | 30 ++++++++++++++++++++++--------
|
||||
4 files changed, 65 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/defs.h b/defs.h
|
||||
index d7bcdd083671..e3027e2b9141 100644
|
||||
--- a/defs.h
|
||||
+++ b/defs.h
|
||||
@@ -691,6 +691,7 @@ struct new_utsname {
|
||||
#define KMOD_PAX (0x100ULL)
|
||||
#define KMOD_MEMORY (0x200ULL)
|
||||
#define IRQ_DESC_TREE_MAPLE (0x400ULL)
|
||||
+#define PER_CPU_CFS_RQ (0x800ULL)
|
||||
|
||||
#define XEN() (kt->flags & ARCH_XEN)
|
||||
#define OPENVZ() (kt->flags & ARCH_OPENVZ)
|
||||
@@ -5886,6 +5887,7 @@ void parse_for_member_extended(struct datatype_member *, ulong);
|
||||
void add_to_downsized(char *);
|
||||
int is_downsized(char *);
|
||||
int is_string(char *, char *);
|
||||
+int is_ptrptr(char *, char *);
|
||||
struct syment *symbol_complete_match(const char *, struct syment *);
|
||||
|
||||
/*
|
||||
diff --git a/kernel.c b/kernel.c
|
||||
index eb9754c5e082..e53038d5d8db 100644
|
||||
--- a/kernel.c
|
||||
+++ b/kernel.c
|
||||
@@ -400,6 +400,18 @@ kernel_init()
|
||||
MEMBER_OFFSET_INIT(task_group_rt_rq, "task_group", "rt_rq");
|
||||
MEMBER_OFFSET_INIT(task_group_parent, "task_group", "parent");
|
||||
|
||||
+ /*
|
||||
+ * task_group.cfs_rq was changed from a pointer array to a per-cpu
|
||||
+ * variable at Linux 7.2 (b8fea7af0e40). Since there is no way to
|
||||
+ * determine it, we check whether it is a pointer array or not.
|
||||
+ * - struct cfs_rq **cfs_rq;
|
||||
+ * + struct cfs_rq __percpu *cfs_rq;
|
||||
+ */
|
||||
+ if (VALID_MEMBER(task_group_cfs_rq)) {
|
||||
+ if (!is_ptrptr("task_group", "cfs_rq"))
|
||||
+ kt->flags2 |= PER_CPU_CFS_RQ;
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* In 2.4, smp_send_stop() sets smp_num_cpus back to 1
|
||||
* in some, but not all, architectures. So if a count
|
||||
@@ -6362,6 +6374,8 @@ dump_kernel_table(int verbose)
|
||||
fprintf(fp, "%sKMOD_PAX", others++ ? "|" : "");
|
||||
if (kt->flags2 & KMOD_MEMORY)
|
||||
fprintf(fp, "%sKMOD_MEMORY", others++ ? "|" : "");
|
||||
+ if (kt->flags2 & PER_CPU_CFS_RQ)
|
||||
+ fprintf(fp, "%sPER_CPU_CFS_RQ", others++ ? "|" : "");
|
||||
fprintf(fp, ")\n");
|
||||
|
||||
fprintf(fp, " stext: %lx\n", kt->stext);
|
||||
diff --git a/symbols.c b/symbols.c
|
||||
index 78e400ba3756..03511c8cbe8c 100644
|
||||
--- a/symbols.c
|
||||
+++ b/symbols.c
|
||||
@@ -7933,6 +7933,33 @@ is_string(char *structure, char *member)
|
||||
return retval;
|
||||
}
|
||||
|
||||
+int
|
||||
+is_ptrptr(char *structure, char *member)
|
||||
+{
|
||||
+ int retval;
|
||||
+ char *t;
|
||||
+ char buf[BUFSIZE];
|
||||
+
|
||||
+ retval = FALSE;
|
||||
+ open_tmpfile();
|
||||
+ whatis_datatype(structure, STRUCT_REQUEST, pc->tmpfile);
|
||||
+ rewind(pc->tmpfile);
|
||||
+ while (fgets(buf, BUFSIZE, pc->tmpfile)) {
|
||||
+ if (!(t = strstr(buf, "**")))
|
||||
+ continue;
|
||||
+ t += 2;
|
||||
+ if (t != strstr(t, member))
|
||||
+ continue;
|
||||
+ t += strlen(member);
|
||||
+ if (*t == ';') {
|
||||
+ retval = TRUE;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ close_tmpfile();
|
||||
+
|
||||
+ return retval;
|
||||
+}
|
||||
|
||||
/*
|
||||
* Generic function for dumping data structure declarations, with a small
|
||||
diff --git a/task.c b/task.c
|
||||
index 7dacb05b2406..b95d3d7fb2af 100644
|
||||
--- a/task.c
|
||||
+++ b/task.c
|
||||
@@ -9542,8 +9542,12 @@ print_parent_task_group_fair(void *t, int cpu)
|
||||
readmem(tgi->task_group + OFFSET(task_group_cfs_rq),
|
||||
KVADDR, &cfs_rq_c, sizeof(ulong),
|
||||
"task_group cfs_rq", FAULT_ON_ERROR);
|
||||
- readmem(cfs_rq_c + cpu * sizeof(ulong), KVADDR, &cfs_rq_p,
|
||||
- sizeof(ulong), "task_group cfs_rq", FAULT_ON_ERROR);
|
||||
+
|
||||
+ if (kt->flags2 & PER_CPU_CFS_RQ)
|
||||
+ cfs_rq_p = cfs_rq_c + kt->__per_cpu_offset[cpu];
|
||||
+ else
|
||||
+ readmem(cfs_rq_c + cpu * sizeof(ulong), KVADDR, &cfs_rq_p,
|
||||
+ sizeof(ulong), "task_group cfs_rq", FAULT_ON_ERROR);
|
||||
|
||||
print_group_header_fair(tgi->depth, cfs_rq_p, tgi);
|
||||
tgi->use = 0;
|
||||
@@ -9569,8 +9573,13 @@ dump_tasks_in_lower_dequeued_cfs_rq(int depth, ulong cfs_rq, int cpu,
|
||||
readmem(tgi_array[i]->task_group + OFFSET(task_group_cfs_rq),
|
||||
KVADDR, &cfs_rq_c, sizeof(ulong), "task_group cfs_rq",
|
||||
FAULT_ON_ERROR);
|
||||
- readmem(cfs_rq_c + cpu * sizeof(ulong), KVADDR, &cfs_rq_p,
|
||||
- sizeof(ulong), "task_group cfs_rq", FAULT_ON_ERROR);
|
||||
+
|
||||
+ if (kt->flags2 & PER_CPU_CFS_RQ)
|
||||
+ cfs_rq_p = cfs_rq_c + kt->__per_cpu_offset[cpu];
|
||||
+ else
|
||||
+ readmem(cfs_rq_c + cpu * sizeof(ulong), KVADDR, &cfs_rq_p,
|
||||
+ sizeof(ulong), "task_group cfs_rq", FAULT_ON_ERROR);
|
||||
+
|
||||
if (cfs_rq == cfs_rq_p)
|
||||
continue;
|
||||
|
||||
@@ -10433,10 +10442,15 @@ dump_tasks_by_task_group(void)
|
||||
readmem(rt_rq + cpu * sizeof(ulong), KVADDR,
|
||||
&rt_rq_p, sizeof(ulong), "task_group rt_rq",
|
||||
FAULT_ON_ERROR);
|
||||
- if (cfs_rq)
|
||||
- readmem(cfs_rq + cpu * sizeof(ulong), KVADDR,
|
||||
- &cfs_rq_p, sizeof(ulong), "task_group cfs_rq",
|
||||
- FAULT_ON_ERROR);
|
||||
+ if (cfs_rq) {
|
||||
+ if (kt->flags2 & PER_CPU_CFS_RQ)
|
||||
+ cfs_rq_p = cfs_rq + kt->__per_cpu_offset[cpu];
|
||||
+ else
|
||||
+ readmem(cfs_rq + cpu * sizeof(ulong), KVADDR,
|
||||
+ &cfs_rq_p, sizeof(ulong),
|
||||
+ "task_group cfs_rq", FAULT_ON_ERROR);
|
||||
+ }
|
||||
+
|
||||
fprintf(fp, "%sCPU %d", displayed++ ? "\n" : "", cpu);
|
||||
|
||||
if (hide_offline_cpu(cpu)) {
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
From f336dfa79ed94895914e132c31f2db7e09bf4ab1 Mon Sep 17 00:00:00 2001
|
||||
From: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
Date: Wed, 8 Jul 2026 02:45:50 +0000
|
||||
Subject: [PATCH 36/39] Fix "runq -g" option to display task_group name on
|
||||
Linux 6.15 and later
|
||||
|
||||
Kernel commit 633488947ef66 ("kernfs: Use RCU to access
|
||||
kernfs_node::parent.") changed the "parent" member name in struct
|
||||
kernfs_node to "__parent".
|
||||
|
||||
Without the patch, the "rung -g" option cannot display task_group's
|
||||
name:
|
||||
crash> runq -g
|
||||
CPU 0
|
||||
CURRENT: PID: 5687 TASK: ffff8b0bc175a2c0 COMMAND: "bash"
|
||||
ROOT_TASK_GROUP: ffffffff93a55600 CFS_RQ: ffff8b0cf8232240
|
||||
TASK_GROUP: ffff8b0b942a1e00 CFS_RQ: fffff1b5ffc0d540
|
||||
TASK_GROUP: ffff8b0bc0f27900 CFS_RQ: fffff1b5ffc23f80
|
||||
TASK_GROUP: ffff8b0b862fcc00 CFS_RQ: fffff1b5ffc29f00
|
||||
[120] PID: 5687 TASK: ffff8b0bc175a2c0 COMMAND: "bash" [CURRENT]
|
||||
|
||||
With the patch:
|
||||
crash> runq -g
|
||||
CPU 0
|
||||
CURRENT: PID: 5687 TASK: ffff8b0bc175a2c0 COMMAND: "bash"
|
||||
ROOT_TASK_GROUP: ffffffff93a55600 CFS_RQ: ffff8b0cf8232240
|
||||
TASK_GROUP: ffff8b0b942a1e00 CFS_RQ: fffff1b5ffc0d540 <user.slice>
|
||||
TASK_GROUP: ffff8b0bc0f27900 CFS_RQ: fffff1b5ffc23f80 <user-0.slice>
|
||||
TASK_GROUP: ffff8b0b862fcc00 CFS_RQ: fffff1b5ffc29f00 <session-2.scope>
|
||||
[120] PID: 5687 TASK: ffff8b0bc175a2c0 COMMAND: "bash" [CURRENT]
|
||||
|
||||
Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
|
||||
---
|
||||
task.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/task.c b/task.c
|
||||
index b95d3d7fb2af..a4118766fb42 100644
|
||||
--- a/task.c
|
||||
+++ b/task.c
|
||||
@@ -9879,6 +9879,8 @@ task_group_offset_init(void)
|
||||
MEMBER_OFFSET_INIT(cgroup_kn, "cgroup", "kn");
|
||||
MEMBER_OFFSET_INIT(kernfs_node_name, "kernfs_node", "name");
|
||||
MEMBER_OFFSET_INIT(kernfs_node_parent, "kernfs_node", "parent");
|
||||
+ if (INVALID_MEMBER(kernfs_node_parent))
|
||||
+ MEMBER_OFFSET_INIT(kernfs_node_parent, "kernfs_node", "__parent");
|
||||
|
||||
MEMBER_OFFSET_INIT(task_group_siblings, "task_group", "siblings");
|
||||
MEMBER_OFFSET_INIT(task_group_children, "task_group", "children");
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
From bfce25840cffabf0574825e796b0284ed36276bb Mon Sep 17 00:00:00 2001
|
||||
From: Tao Liu <ltao@redhat.com>
|
||||
Date: Tue, 4 Aug 2026 15:20:33 +1200
|
||||
Subject: [PATCH 37/39] x86_64: Make ORC_REG_SP and ORC_REG_PREV_SP independent
|
||||
from kernel version
|
||||
|
||||
Previously ORC_REG_SP and ORC_REG_PREV_SP will depend on kernel version
|
||||
for their value, however this is fragile since distributions will
|
||||
backport the upstream patch to a lower kernel version, thus break the
|
||||
version assumption.
|
||||
|
||||
This patch fixes by checking the value of ORC_REG_PREV_SP, which can be
|
||||
get from orc_fp_entry. ORC_REG_PREV_SP's value can work as the indicator
|
||||
of whether the current kernel have applied the upstream patch 1735858caa4b
|
||||
("objtool/x86: Reorder ORC register numbering").
|
||||
|
||||
Fixes: d0ee428664f9 ("x86_64: Fix "bt" command to use correct ORC register
|
||||
values on Linux 7.1 and later")
|
||||
|
||||
Reviewed-by: HAGIO KAZUHITO <k-hagio-ab@nec.com>
|
||||
Reviewed-by: MUKESH KUMAR PILANIYA <mpilaniy@redhat.com>
|
||||
Reviewed-by: Dave Young <yangrr.2009@tsinghua.org.cn>
|
||||
Signed-off-by: Tao Liu <ltao@redhat.com>
|
||||
---
|
||||
x86_64.c | 29 ++++++++++++++++++++++-------
|
||||
1 file changed, 22 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/x86_64.c b/x86_64.c
|
||||
index 55648697baf3..62b27762a41f 100644
|
||||
--- a/x86_64.c
|
||||
+++ b/x86_64.c
|
||||
@@ -6736,13 +6736,28 @@ x86_64_ORC_init(void)
|
||||
if (orc->has_signal && !orc->has_end)
|
||||
machdep->flags |= ORC_6_4;
|
||||
|
||||
- /* See kernel commit 1735858caa4b */
|
||||
- if (THIS_KERNEL_VERSION >= LINUX(7,1,0)) {
|
||||
- ORC_REG_SP = 3;
|
||||
- ORC_REG_PREV_SP = 8;
|
||||
- } else {
|
||||
- ORC_REG_SP = 5;
|
||||
- ORC_REG_PREV_SP = 1;
|
||||
+ /* Try get ORC_REG_(PREV)_SP */
|
||||
+ ORC_REG_SP = 5;
|
||||
+ ORC_REG_PREV_SP = 1;
|
||||
+
|
||||
+ if (kernel_symbol_exists("orc_fp_entry")) {
|
||||
+ /*
|
||||
+ * kernel_orc_entry_6_4 & kernel_orc_entry have the same
|
||||
+ * offset of bp_reg.
|
||||
+ */
|
||||
+ kernel_orc_entry_6_4 entry = {0};
|
||||
+ if (try_get_symbol_data("orc_fp_entry", sizeof(entry), &entry)) {
|
||||
+ /*
|
||||
+ * orc_fp_entry.bp_reg = ORC_REG_PREV_SP
|
||||
+ * See kernel commit 1735858caa4b. Use ORC_REG_PREV_SP
|
||||
+ * as the indicator of the commit.
|
||||
+ */
|
||||
+ if (entry.bp_reg == 8) {
|
||||
+ ORC_REG_SP = 3;
|
||||
+ ORC_REG_PREV_SP = 8;
|
||||
+ }
|
||||
+ } else
|
||||
+ error(WARNING, "Cannot get orc_fp_entry.bp_reg info");
|
||||
}
|
||||
|
||||
machdep->flags |= ORC;
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
From 08e9d02d2c46011d1565a3bedf33c66f07cf8bde Mon Sep 17 00:00:00 2001
|
||||
From: Rui Qi <qirui.001@bytedance.com>
|
||||
Date: Mon, 10 Aug 2026 11:30:23 +0800
|
||||
Subject: [PATCH 38/39] symbols: optimize symval_hash_init with O(1) tail
|
||||
insertion
|
||||
|
||||
Replace the O(n) tail traversal with O(1) tail insertion using a
|
||||
dynamically-allocated per-bucket tail tracking array. The original code
|
||||
traversed the entire linked list on every insert to find the tail,
|
||||
resulting in O(n^2) complexity for hash table initialization.
|
||||
|
||||
This reduces hash table initialization from O(n^2) to O(n).
|
||||
|
||||
Benchmark on an x86_64 machine (kernel 5.10.135, ~112k symbols):
|
||||
|
||||
Before: 5.54 s (mean, n=6, sigma=0.12)
|
||||
After: 5.31 s (mean, n=6, sigma=0.12)
|
||||
Speedup: 1.04x (-4.1%)
|
||||
|
||||
Benchmark on an ARM64 Neoverse-N2 machine (kernel 5.15.152 arm64,
|
||||
~132k nm symbols):
|
||||
|
||||
Before: 3.4113 s (mean, n=48, sigma=0.0698)
|
||||
After: 2.5073 s (mean, n=48, sigma=0.0394)
|
||||
Speedup: 1.36x (-26.5%), with improved consistency.
|
||||
User CPU: 4.1706 s -> 3.2768 s (-21.4%).
|
||||
|
||||
Benchmark retest on a RISC-V machine (kernel
|
||||
6.12.13 riscv64, ~198k nm symbols):
|
||||
|
||||
$ printf 'q\n' | ./crash vmlinux /proc/kcore
|
||||
|
||||
Before: 11.934 s (mean, n=3, sigma=0.880; samples: 12.921, 11.231, 11.651)
|
||||
After: 10.255 s (mean, n=3, sigma=0.835; samples: 11.131, 9.467, 10.168)
|
||||
Speedup: 1.16x (-14.1%)
|
||||
|
||||
Signed-off-by: Rui Qi <qirui.001@bytedance.com>
|
||||
Reviewed-by: Dave Young <yangrr.2009@tsinghua.org.cn>
|
||||
---
|
||||
symbols.c | 19 ++++++++++---------
|
||||
1 file changed, 10 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/symbols.c b/symbols.c
|
||||
index 03511c8cbe8c..a7ccdb101033 100644
|
||||
--- a/symbols.c
|
||||
+++ b/symbols.c
|
||||
@@ -1085,12 +1085,16 @@ symbol_value_from_proc_kallsyms(char *symname)
|
||||
|
||||
/*
|
||||
* Install all static kernel symbol values into the symval_hash.
|
||||
+ * Uses a dynamically-allocated tails[] array for O(1) tail insertion.
|
||||
*/
|
||||
static void
|
||||
symval_hash_init(void)
|
||||
{
|
||||
int index;
|
||||
- struct syment *sp, *sph;
|
||||
+ struct syment *sp, **tails;
|
||||
+
|
||||
+ tails = (struct syment **)GETBUF(SYMVAL_HASH * sizeof(struct syment *));
|
||||
+ BZERO(tails, SYMVAL_HASH * sizeof(struct syment *));
|
||||
|
||||
for (sp = st->symtable; sp < st->symend; sp++) {
|
||||
index = SYMVAL_HASH_INDEX(sp->value);
|
||||
@@ -1098,15 +1102,12 @@ symval_hash_init(void)
|
||||
if (st->symval_hash[index].val_hash_head == NULL) {
|
||||
st->symval_hash[index].val_hash_head = sp;
|
||||
st->symval_hash[index].val_hash_last = sp;
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- sph = st->symval_hash[index].val_hash_head;
|
||||
- while (sph->val_hash_next)
|
||||
- sph = sph->val_hash_next;
|
||||
-
|
||||
- sph->val_hash_next = sp;
|
||||
+ } else
|
||||
+ tails[index]->val_hash_next = sp;
|
||||
+ tails[index] = sp;
|
||||
}
|
||||
+
|
||||
+ FREEBUF(tails);
|
||||
}
|
||||
|
||||
/*
|
||||
--
|
||||
2.54.0
|
||||
|
||||
74
0039-Prevent-out-of-bounds-access-of-note_buf.patch
Normal file
74
0039-Prevent-out-of-bounds-access-of-note_buf.patch
Normal file
@ -0,0 +1,74 @@
|
||||
From 6bee9c7021df3d1d610ad50a45ad803bbcb9a724 Mon Sep 17 00:00:00 2001
|
||||
From: Tao Liu <ltao@redhat.com>
|
||||
Date: Wed, 29 Jul 2026 22:42:42 +1200
|
||||
Subject: [PATCH 39/39] Prevent out-of-bounds access of note_buf
|
||||
|
||||
Add a boundary check for note_buf in case any protential
|
||||
data access outside of the buffer.
|
||||
|
||||
Signed-off-by: Tao Liu <ltao@redhat.com>
|
||||
---
|
||||
diskdump.c | 19 ++++++++++++++-----
|
||||
1 file changed, 14 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/diskdump.c b/diskdump.c
|
||||
index 20f8b19f1514..7263e2c3199c 100644
|
||||
--- a/diskdump.c
|
||||
+++ b/diskdump.c
|
||||
@@ -338,16 +338,20 @@ process_elf32_notes(void *note_buf, unsigned long size_note)
|
||||
int num = 0;
|
||||
int vmcoredd_num = 0;
|
||||
int qemu_num = 0;
|
||||
+ unsigned long left;
|
||||
|
||||
for (index = 0; index < size_note; index += len) {
|
||||
nt = note_buf + index;
|
||||
+ left = size_note - index;
|
||||
|
||||
- if (nt->n_type == NT_PRSTATUS) {
|
||||
+ if (nt->n_type == NT_PRSTATUS && num < NR_CPUS) {
|
||||
dd->nt_prstatus_percpu[num] = nt;
|
||||
num++;
|
||||
}
|
||||
len = sizeof(Elf32_Nhdr);
|
||||
- if (STRNEQ((char *)nt + len, "QEMU")) {
|
||||
+ if ((left >= sizeof(Elf32_Nhdr) + MAX(nt->n_namesz + sizeof(ulong), 4)) &&
|
||||
+ STRNEQ((char *)nt + len, "QEMU") &&
|
||||
+ qemu_num < NR_CPUS) {
|
||||
ulong *ptr =
|
||||
(ulong *)((char *)nt + sizeof(Elf32_Nhdr) + nt->n_namesz);
|
||||
dd->nt_qemucs_percpu[qemu_num] =
|
||||
@@ -395,22 +399,27 @@ process_elf64_notes(void *note_buf, unsigned long size_note)
|
||||
int num = 0;
|
||||
int vmcoredd_num = 0;
|
||||
int qemu_num = 0;
|
||||
+ unsigned long left;
|
||||
|
||||
for (index = 0; index < size_note; index += len) {
|
||||
nt = note_buf + index;
|
||||
+ left = size_note - index;
|
||||
|
||||
- if (nt->n_type == NT_PRSTATUS) {
|
||||
+ if (nt->n_type == NT_PRSTATUS && num < NR_CPUS) {
|
||||
dd->nt_prstatus_percpu[num] = nt;
|
||||
num++;
|
||||
}
|
||||
- if ((nt->n_type == NT_TASKSTRUCT) &&
|
||||
+ if ((nt->n_type == NT_TASKSTRUCT) &&
|
||||
+ (left >= sizeof(Elf64_Nhdr) + MAX(nt->n_namesz + sizeof(ulong), 4)) &&
|
||||
(STRNEQ((char *)nt + sizeof(Elf64_Nhdr), "SNAP"))) {
|
||||
pc->flags2 |= (LIVE_DUMP|SNAP);
|
||||
dd->snapshot_task =
|
||||
*((ulong *)((char *)nt + sizeof(Elf64_Nhdr) + nt->n_namesz));
|
||||
}
|
||||
len = sizeof(Elf64_Nhdr);
|
||||
- if (STRNEQ((char *)nt + len, "QEMU")) {
|
||||
+ if ((left >= sizeof(Elf64_Nhdr) + MAX(nt->n_namesz + sizeof(ulong), 4)) &&
|
||||
+ STRNEQ((char *)nt + len, "QEMU") &&
|
||||
+ qemu_num < NR_CPUS) {
|
||||
ulong *ptr =
|
||||
(ulong *)((char *)nt + sizeof(Elf64_Nhdr) + nt->n_namesz);
|
||||
dd->nt_qemucs_percpu[qemu_num] =
|
||||
--
|
||||
2.54.0
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
--- crash-9.0.1/Makefile.orig
|
||||
+++ crash-9.0.1/Makefile
|
||||
--- crash-9.0.2/Makefile.orig
|
||||
+++ crash-9.0.2/Makefile
|
||||
@@ -204,7 +204,7 @@ GDB_FLAGS=
|
||||
# TARGET_CFLAGS will be configured automatically by configure
|
||||
TARGET_CFLAGS=
|
||||
@ -18,8 +18,8 @@
|
||||
@echo "../../${PROGRAM} ../../${PROGRAM}lib.a" > ${GDB}/gdb/mergeobj
|
||||
@rm -f ${PROGRAM}
|
||||
@if [ ! -f ${GDB}/config.status ]; then \
|
||||
--- crash-9.0.1/configure.c.orig
|
||||
+++ crash-9.0.1/configure.c
|
||||
--- crash-9.0.2/configure.c.orig
|
||||
+++ crash-9.0.2/configure.c
|
||||
@@ -810,7 +810,8 @@ build_configure(struct supported_gdb_version *sp)
|
||||
fprintf(fp2, "%s\n", sp->GDB);
|
||||
sprintf(target_data.gdb_version, "%s", &sp->GDB[4]);
|
||||
|
||||
83
crash.spec
83
crash.spec
@ -3,7 +3,7 @@
|
||||
#
|
||||
Summary: Kernel analysis utility for live systems, netdump, diskdump, kdump, LKCD or mcore dumpfiles
|
||||
Name: crash
|
||||
Version: 9.0.1
|
||||
Version: 9.0.2
|
||||
Release: 1%{?dist}.alma.1
|
||||
License: GPL-3.0-only
|
||||
Source0: https://github.com/crash-utility/crash/archive/crash-%{version}.tar.gz
|
||||
@ -19,6 +19,44 @@ Provides: bundled(libiberty)
|
||||
Provides: bundled(gdb) = 16.2
|
||||
Patch0: lzo_snappy_zstd.patch
|
||||
Patch1: crash-9.0.0_build.patch
|
||||
Patch3: 0002-Mark-start-of-9.0.3-development-phase-with-version-9.patch
|
||||
Patch4: 0003-RISCV64-introduce-riscv64_VTOP-and-riscv64_PTOV.patch
|
||||
Patch5: 0004-Fix-wrong-detection-of-LIVEPATCH-on-old-kernels.patch
|
||||
Patch6: 0005-Fix-unwinding-with-32k-stacks-in-ppc64le.patch
|
||||
Patch7: 0006-arm64-fix-gdb-register-feeding-for-exception-frames-.patch
|
||||
Patch8: 0007-RISCV64-fix-pmd-address-calculation-in-riscv64_vtop_.patch
|
||||
Patch9: 0008-symbols-optimize-symname_hash-with-larger-table-and-.patch
|
||||
Patch10: 0009-RISCV64-add-mapping-symbol-filter-in-riscv64_verify_.patch
|
||||
Patch11: 0010-Fix-get_xtime-for-kernel-6.13-and-higher.patch
|
||||
Patch12: 0011-symbols-Add-support-for-mod-symtab-with-combined-GPL.patch
|
||||
Patch13: 0012-add-folio_order-function.patch
|
||||
Patch14: 0013-xarray-add-large-folio-support.patch
|
||||
Patch15: 0014-add-files-n-command-for-an-inode.patch
|
||||
Patch16: 0015-x86_64-Fix-bt-command-for-noreturn-functions.patch
|
||||
Patch17: 0016-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch
|
||||
Patch18: 0017-Fix-kmem-i-option-to-display-swap-usage-on-Linux-6.1.patch
|
||||
Patch19: 0018-Fix-swap-command-on-Linux-7.1-and-later.patch
|
||||
Patch20: 0019-LoongArch64-Fix-CPU-registers-reading-from-dump-note.patch
|
||||
Patch21: 0020-LoongArch64-Fix-pt_regs-initialization-for-active-ta.patch
|
||||
Patch22: 0021-LoongArch64-Support-backtracing-across-exception-bou.patch
|
||||
Patch23: 0022-LoongArch64-Fix-stack-frame-loop-bounds-for-exceptio.patch
|
||||
Patch24: 0023-LoongArch64-Add-dummy-eframe_search-to-avoid-bt-e-se.patch
|
||||
Patch25: 0024-LoongArch64-print-exception-return-address-as-ERA.patch
|
||||
Patch26: 0025-LoongArch64-resolve-relocated-exception-vector-addre.patch
|
||||
Patch27: 0026-LoongArch64-add-initial-ORC-unwinder-support.patch
|
||||
Patch28: 0027-LoongArch64-unwind-dumpfile-active-tasks-from-IRQ-st.patch
|
||||
Patch29: 0028-LoongArch64-avoid-replacing-a-valid-RA-with-stack-no.patch
|
||||
Patch30: 0029-LoongArch64-print-exception-registers-only-with-bt-f.patch
|
||||
Patch31: 0030-riscv64-Set-VMEMMAP-flag-to-fix-spurious-mem_map-war.patch
|
||||
Patch32: 0031-riscv64-Guard-verbose-output-in-vtop-page-table-walk.patch
|
||||
Patch33: 0032-riscv64-Add-get_kvaddr_ranges-callback-for-kernel-ad.patch
|
||||
Patch34: 0033-task-Introduce-I-option-to-ps-command-to-exclude-idl.patch
|
||||
Patch35: 0034-task-Introduce-Y-option-to-ps-command-to-display-sch.patch
|
||||
Patch36: 0035-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch
|
||||
Patch37: 0036-Fix-runq-g-option-to-display-task_group-name-on-Linu.patch
|
||||
Patch38: 0037-x86_64-Make-ORC_REG_SP-and-ORC_REG_PREV_SP-independe.patch
|
||||
Patch39: 0038-symbols-optimize-symval_hash_init-with-O-1-tail-inse.patch
|
||||
Patch40: 0039-Prevent-out-of-bounds-access-of-note_buf.patch
|
||||
|
||||
%description
|
||||
The core analysis suite is a self-contained tool that can be used to
|
||||
@ -40,6 +78,44 @@ offered by Mission Critical Linux, or the LKCD kernel patch.
|
||||
%setup -n %{name}-%{version} -q
|
||||
%patch -P 0 -p1 -b lzo_snappy_zstd.patch
|
||||
%patch -P 1 -p1
|
||||
%patch -P 3 -p1
|
||||
%patch -P 4 -p1
|
||||
%patch -P 5 -p1
|
||||
%patch -P 6 -p1
|
||||
%patch -P 7 -p1
|
||||
%patch -P 8 -p1
|
||||
%patch -P 9 -p1
|
||||
%patch -P 10 -p1
|
||||
%patch -P 11 -p1
|
||||
%patch -P 12 -p1
|
||||
%patch -P 13 -p1
|
||||
%patch -P 14 -p1
|
||||
%patch -P 15 -p1
|
||||
%patch -P 16 -p1
|
||||
%patch -P 17 -p1
|
||||
%patch -P 18 -p1
|
||||
%patch -P 19 -p1
|
||||
%patch -P 20 -p1
|
||||
%patch -P 21 -p1
|
||||
%patch -P 22 -p1
|
||||
%patch -P 23 -p1
|
||||
%patch -P 24 -p1
|
||||
%patch -P 25 -p1
|
||||
%patch -P 26 -p1
|
||||
%patch -P 27 -p1
|
||||
%patch -P 28 -p1
|
||||
%patch -P 29 -p1
|
||||
%patch -P 30 -p1
|
||||
%patch -P 31 -p1
|
||||
%patch -P 32 -p1
|
||||
%patch -P 33 -p1
|
||||
%patch -P 34 -p1
|
||||
%patch -P 35 -p1
|
||||
%patch -P 36 -p1
|
||||
%patch -P 37 -p1
|
||||
%patch -P 38 -p1
|
||||
%patch -P 39 -p1
|
||||
%patch -P 40 -p1
|
||||
|
||||
%build
|
||||
|
||||
@ -65,9 +141,12 @@ cp -p defs.h %{buildroot}%{_includedir}/crash
|
||||
%{_includedir}/*
|
||||
|
||||
%changelog
|
||||
* Tue Nov 25 2025 Eduard Abdullin <eabdullin@almalinux.org> - 9.0.1-1.alma.1
|
||||
* Wed Aug 12 2026 Eduard Abdullin <eabdullin@almalinux.org> - 9.0.2-1.alma.1
|
||||
- Debrand for AlmaLinux
|
||||
|
||||
* Tue Aug 11 2026 Tao Liu <ltao@redhat.com> - 9.0.1-2
|
||||
- Rebase to upstream crash 9.0.2
|
||||
|
||||
* Mon Nov 24 2025 Tao Liu <ltao@redhat.com> - 9.0.1-1
|
||||
- Rebase to upstream crash 9.0.1
|
||||
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
--- !Policy
|
||||
product_versions:
|
||||
- rhel-10
|
||||
decision_context: osci_compose_gate
|
||||
rules:
|
||||
- !PassingTestCaseRule {test_case_name: kernel-qe.kernel-ci.general-kdump.tier0.functional}
|
||||
@ -1,5 +1,5 @@
|
||||
--- crash-9.0.1/Makefile.orig
|
||||
+++ crash-9.0.1/Makefile
|
||||
--- crash-9.0.2/Makefile.orig
|
||||
+++ crash-9.0.2/Makefile
|
||||
@@ -256,7 +256,7 @@ all: make_configure
|
||||
gdb_merge: force
|
||||
@if [ ! -f ${GDB}/README ]; then \
|
||||
@ -9,8 +9,8 @@
|
||||
@echo "../../${PROGRAM} ../../${PROGRAM}lib.a" > ${GDB}/gdb/mergeobj
|
||||
@rm -f ${PROGRAM}
|
||||
@if [ ! -f ${GDB}/config.status ]; then \
|
||||
--- crash-9.0.1/diskdump.c.orig
|
||||
+++ crash-9.0.1/diskdump.c
|
||||
--- crash-9.0.2/diskdump.c.orig
|
||||
+++ crash-9.0.2/diskdump.c
|
||||
@@ -23,6 +23,9 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
14
plans/ci.fmf
Normal file
14
plans/ci.fmf
Normal file
@ -0,0 +1,14 @@
|
||||
plan:
|
||||
import:
|
||||
url: https://gitlab.cee.redhat.com/kernel-qe/test-plans.git
|
||||
|
||||
/RHEL8-KDUMP_T0:
|
||||
plan+:
|
||||
import+:
|
||||
name: /plans/kdump/T0/RHEL8-KDUMP_T0
|
||||
|
||||
/RHEL9-KDUMP_Crash_Plugins_T0:
|
||||
plan+:
|
||||
import+:
|
||||
name: /plans/kdump/T0/RHEL9-KDUMP_Crash_Plugins_T0
|
||||
|
||||
2
sources
2
sources
@ -1,2 +1,2 @@
|
||||
SHA512 (crash-9.0.1.tar.gz) = 3f49d9ce6ab82265f35e3ed539d0c310caa1fbfb68bd5edc84c033a2ccd5a48447eabd5663e5ea0a45100eee792f8867182ad4e4cae5ea4de3fc3abeda0e82b2
|
||||
SHA512 (gdb-16.2.tar.gz) = c44a6cf6cdd6e92f1f4dda7d888ce3e7fdde65ca8736092e2b0a4c369ea09b499824a1d078f668f276fa6d00d311e9ec485231cb7b841479a4fabbfd65778084
|
||||
SHA512 (crash-9.0.2.tar.gz) = c51164065ad7c65e8fda91c01b514b464e38197674e738f496e32669f749c8a34c60c1e65f435cfc23b7b035f5f8022c7a3ef39fb4de8cb42adb3f0537b1f72d
|
||||
|
||||
Loading…
Reference in New Issue
Block a user