Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package crash for openSUSE:Factory checked 
in at 2026-09-18 22:08:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/crash (Old)
 and      /work/SRC/openSUSE:Factory/.crash.new.383539 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "crash"

Fri Sep 18 22:08:11 2026 rev:200 rq:1378796 version:9.0.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/crash/crash.changes      2026-06-25 
10:54:57.240709436 +0200
+++ /work/SRC/openSUSE:Factory/.crash.new.383539/crash.changes  2026-09-18 
22:08:49.280333756 +0200
@@ -1,0 +2,21 @@
+Fri Aug 14 06:10:08 UTC 2026 - Jiri Slaby <[email protected]>
+
+- add crash-symbols-use-non-debug-BFD-to-retrieve-.rodata.patch
+
+-------------------------------------------------------------------
+Wed Aug 12 08:53:28 UTC 2026 - Jiri Slaby <[email protected]>
+
+- support kernel 7.1 + 7.2 -- add:
+  * crash-support-kernel-7.x-and-8.x.patch
+  * crash-Fix-compound_head-and-bt-F-option-on-Linux-7.1-and-l.patch
+  * crash-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch
+  * crash-Fix-kmem-i-option-to-display-swap-usage-on-Linux-6.1.patch
+  * crash-Fix-kmem-s-command-on-Linux-7.1-and-later.patch
+  * crash-Fix-runq-g-option-to-display-task_group-name-on-Linu.patch
+  * crash-Fix-swap-command-on-Linux-7.1-and-later.patch
+  * crash-symbols-Add-support-for-mod-symtab-with-combined-GPL.patch
+  * crash-x86_64-Fix-bt-command-for-noreturn-functions.patch
+  * crash-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch
+  * crash-x86_64-Make-ORC_REG_SP-and-ORC_REG_PREV_SP-independe.patch
+
+-------------------------------------------------------------------

New:
----
  crash-Fix-compound_head-and-bt-F-option-on-Linux-7.1-and-l.patch
  crash-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch
  crash-Fix-kmem-i-option-to-display-swap-usage-on-Linux-6.1.patch
  crash-Fix-kmem-s-command-on-Linux-7.1-and-later.patch
  crash-Fix-runq-g-option-to-display-task_group-name-on-Linu.patch
  crash-Fix-swap-command-on-Linux-7.1-and-later.patch
  crash-support-kernel-7.x-and-8.x.patch
  crash-symbols-Add-support-for-mod-symtab-with-combined-GPL.patch
  crash-symbols-use-non-debug-BFD-to-retrieve-.rodata.patch
  crash-x86_64-Fix-bt-command-for-noreturn-functions.patch
  crash-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch
  crash-x86_64-Make-ORC_REG_SP-and-ORC_REG_PREV_SP-independe.patch

----------(New B)----------
  New:  * crash-support-kernel-7.x-and-8.x.patch
  * crash-Fix-compound_head-and-bt-F-option-on-Linux-7.1-and-l.patch
  * crash-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch
  New:  * crash-Fix-compound_head-and-bt-F-option-on-Linux-7.1-and-l.patch
  * crash-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch
  * crash-Fix-kmem-i-option-to-display-swap-usage-on-Linux-6.1.patch
  New:  * crash-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch
  * crash-Fix-kmem-i-option-to-display-swap-usage-on-Linux-6.1.patch
  * crash-Fix-kmem-s-command-on-Linux-7.1-and-later.patch
  New:  * crash-Fix-kmem-i-option-to-display-swap-usage-on-Linux-6.1.patch
  * crash-Fix-kmem-s-command-on-Linux-7.1-and-later.patch
  * crash-Fix-runq-g-option-to-display-task_group-name-on-Linu.patch
  New:  * crash-Fix-kmem-s-command-on-Linux-7.1-and-later.patch
  * crash-Fix-runq-g-option-to-display-task_group-name-on-Linu.patch
  * crash-Fix-swap-command-on-Linux-7.1-and-later.patch
  New:  * crash-Fix-runq-g-option-to-display-task_group-name-on-Linu.patch
  * crash-Fix-swap-command-on-Linux-7.1-and-later.patch
  * crash-symbols-Add-support-for-mod-symtab-with-combined-GPL.patch
  New:- support kernel 7.1 + 7.2 -- add:
  * crash-support-kernel-7.x-and-8.x.patch
  * crash-Fix-compound_head-and-bt-F-option-on-Linux-7.1-and-l.patch
  New:  * crash-Fix-swap-command-on-Linux-7.1-and-later.patch
  * crash-symbols-Add-support-for-mod-symtab-with-combined-GPL.patch
  * crash-x86_64-Fix-bt-command-for-noreturn-functions.patch
  New:
- add crash-symbols-use-non-debug-BFD-to-retrieve-.rodata.patch
  New:  * crash-symbols-Add-support-for-mod-symtab-with-combined-GPL.patch
  * crash-x86_64-Fix-bt-command-for-noreturn-functions.patch
  * crash-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch
  New:  * crash-x86_64-Fix-bt-command-for-noreturn-functions.patch
  * crash-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch
  * crash-x86_64-Make-ORC_REG_SP-and-ORC_REG_PREV_SP-independe.patch
  New:  * crash-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch
  * crash-x86_64-Make-ORC_REG_SP-and-ORC_REG_PREV_SP-independe.patch
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ crash.spec ++++++
--- /var/tmp/diff_new_pack.7K3olc/_old  2026-09-18 22:08:51.902443649 +0200
+++ /var/tmp/diff_new_pack.7K3olc/_new  2026-09-18 22:08:51.903443690 +0200
@@ -79,9 +79,14 @@
 Source99:       crash-rpmlintrc
 Source100:      %{name}-gdb-10.2.series
 Source101:      %{name}-gdb-gnulib-define-warndecl.patch
+Patch0:         
%{name}-symbols-Add-support-for-mod-symtab-with-combined-GPL.patch
 Patch1:         %{name}-make-emacs-default.diff
 Patch2:         %{name}-sles9-quirk.patch
+Patch3:         %{name}-symbols-use-non-debug-BFD-to-retrieve-.rodata.patch
 Patch4:         %{name}-sles9-time.patch
+Patch5:         %{name}-support-kernel-7.x-and-8.x.patch
+Patch6:         
%{name}-Fix-compound_head-and-bt-F-option-on-Linux-7.1-and-l.patch
+Patch7:         %{name}-Fix-kmem-s-command-on-Linux-7.1-and-later.patch
 Patch9:         %{name}-debuginfo-compressed.patch
 Patch10:        %{name}_enable_lzo_support.patch
 Patch11:        %{name}-compressed-booted-kernel.patch
@@ -93,6 +98,13 @@
 Patch24:        
%{name}-SLE15-SP1-Fix-for-PPC64-kernel-virtual-address-translation-in.patch
 Patch30:        %{name}-enable-zstd-support.patch
 Patch32:        %{name}-extensions-rule-for-defs.patch
+Patch33:        %{name}-x86_64-Fix-bt-command-for-noreturn-functions.patch
+Patch34:        
%{name}-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch
+Patch35:        
%{name}-Fix-kmem-i-option-to-display-swap-usage-on-Linux-6.1.patch
+Patch36:        %{name}-Fix-swap-command-on-Linux-7.1-and-later.patch
+Patch37:        
%{name}-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch
+Patch38:        
%{name}-Fix-runq-g-option-to-display-task_group-name-on-Linu.patch
+Patch39:        
%{name}-x86_64-Make-ORC_REG_SP-and-ORC_REG_PREV_SP-independe.patch
 Patch90:        %{name}-sial-ps-2.6.29.diff
 Patch99:        %{name}-usrmerge.patch
 Patch100:       gcore-fix-use-of-set_context.patch
@@ -237,15 +249,27 @@
 %prep
 %setup -q -a 2 -a 4
 ln -s %{SOURCE1} .
+%patch -P 0 -p1
 %patch -P 1 -p1
 %patch -P 2 -p1
+%patch -P 3 -p1
 %patch -P 4 -p1
+%patch -P 5 -p1
+%patch -P 6 -p1
+%patch -P 7 -p1
 %patch -P 9 -p1
 %patch -P 10 -p1
 %patch -P 11 -p1
 %patch -P 13 -p1
 %patch -P 18 -p1
 %patch -P 21 -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
 # Patches for SLE 15 SP1 potentially break support for SLE15 and SLE 12 SP4
 # Don't apply on these (and earlier) versions - see bsc#1148197
 %if 0%{?sle_version} > 120400 && 0%{?sle_version} != 150000

++++++ _scmsync.obsinfo ++++++
--- /var/tmp/diff_new_pack.7K3olc/_old  2026-09-18 22:08:52.069450648 +0200
+++ /var/tmp/diff_new_pack.7K3olc/_new  2026-09-18 22:08:52.076450941 +0200
@@ -1,6 +1,6 @@
-mtime: 1782137279
-commit: 7b166c900f7fa8084fef466c1483d00c55710aba7a771e34f5b98b473a9d4fa4
+mtime: 1788772306
+commit: 07270857be0dbd49b66b738d9204c75e879d4d455573c27ac13f06c78d9f95e8
 url: https://src.opensuse.org/kernel-kdump/crash
-revision: 7b166c900f7fa8084fef466c1483d00c55710aba7a771e34f5b98b473a9d4fa4
+revision: 07270857be0dbd49b66b738d9204c75e879d4d455573c27ac13f06c78d9f95e8
 projectscmsync: https://src.opensuse.org/kernel-kdump/_ObsPrj
 

++++++ build.specials.obscpio ++++++

++++++ build.specials.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2026-09-07 11:11:46.000000000 +0200
@@ -0,0 +1 @@
+.osc

++++++ crash-Fix-compound_head-and-bt-F-option-on-Linux-7.1-and-l.patch ++++++
From: Kazuhito Hagio <[email protected]>
Date: Thu, 23 Jul 2026 05:09:48 +0000
Subject: Fix compound_head() and "bt -F" option on Linux 7.1 and later
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: fa55e121672c5e1a974ebc4af3789b7f25f2269b
Patch-mainline: yes

Kernel commit d50569612c29 ("mm: rename the 'compound_head' field in the
'struct page' to 'compound_info'") and related patches [1] changed the
field name and its value.

Without the patch, crash prints the following warning during startup,

  WARNING: SLUB: cannot determine how compound pages are linked

and "bt -F" option fails with the following error.

  crash> bt -F

  bt: invalid structure member offset: page_first_page
      FILE: memory.c  LINE: 20238  FUNCTION: compound_head()

[1] https://lore.kernel.org/all/[email protected]/

Signed-off-by: Kazuhito Hagio <[email protected]>
Acked-by: Tao Liu <[email protected]>
Acked-by: Dave Young <[email protected]>
Signed-off-by: Dave Young <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 defs.h    |  1 +
 memory.c  | 44 ++++++++++++++++++++++++++++++++++++--------
 symbols.c |  1 +
 3 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/defs.h b/defs.h
index e3027e2b9141..88b7bbeb2372 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 page_compound_info;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
diff --git a/memory.c b/memory.c
index 3f3aa274ab5a..5163ee663641 100644
--- a/memory.c
+++ b/memory.c
@@ -410,6 +410,7 @@ mem_init(void)
         DISPLAY_DEFAULT = (sizeof(long) == 8) ? DISPLAY_64 : DISPLAY_32;
 }
 
+static int compound_info_has_mask = FALSE;
 
 /*
  *  Stash a few popular offsets and some basic kernel virtual memory
@@ -547,6 +548,7 @@ vm_init(void)
         MEMBER_OFFSET_INIT(page_compound_head, "page", "compound_head");
        if (INVALID_MEMBER(page_compound_head))
                ANON_MEMBER_OFFSET_INIT(page_compound_head, "page", 
"compound_head");
+       MEMBER_OFFSET_INIT(page_compound_info, "page", "compound_info");
        MEMBER_OFFSET_INIT(page_private, "page", "private");
        MEMBER_OFFSET_INIT(page_freelist, "page", "freelist");
        MEMBER_OFFSET_INIT(page_page_type, "page", "page_type");
@@ -1352,6 +1354,17 @@ vm_init(void)
         } else if (CRASHDEBUG(1))
                error(NOTE, "page_hash_table does not exist in this kernel\n");
 
+       /*
+        * on Linux 7.1 and later, zone.vmemmap_tails is defined only when
+        * CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP is enabled.
+        */
+#define is_power_of_2(n) ((n) > 0 && ((n) & ((n) - 1)) == 0)
+       if (VALID_MEMBER(page_compound_info) &&
+           is_power_of_2(SIZE(page)) && MEMBER_EXISTS("zone", "vmemmap_tails"))
+               compound_info_has_mask = TRUE;
+       if (CRASHDEBUG(1))
+               error(NOTE, "compound_info_has_mask = %d\n", 
compound_info_has_mask);
+
        kmem_cache_init();
 
        page_flags_init();
@@ -5642,10 +5655,11 @@ PG_slab_flag_init(void)
                }
        }
 
-       if (VALID_MEMBER(page_compound_head)) {
+       if (VALID_MEMBER(page_compound_head) || 
VALID_MEMBER(page_compound_info)) {
                if (CRASHDEBUG(2))
                        fprintf(fp, 
-                           "PG_head_tail_mask: (UNUSED): page.compound_head 
exists!\n");
+                           "PG_head_tail_mask: (UNUSED): page.compound_head or 
"
+                           "page.compound_info exists!\n");
        } else if (vt->flags & KMALLOC_SLUB) {
                /* 
                 *  PG_slab and the following are hardwired for 
@@ -9858,7 +9872,8 @@ vaddr_to_kmem_cache(ulong vaddr, char *buf, int verbose)
                        &page_flags, sizeof(ulong), "page.flags",
                        FAULT_ON_ERROR);
                if (!page_slab(page, page_flags)) {
-                       if (((vt->flags & KMALLOC_SLUB) || 
VALID_MEMBER(page_compound_head)) ||
+                       if (((vt->flags & KMALLOC_SLUB) || 
VALID_MEMBER(page_compound_head) ||
+                           VALID_MEMBER(page_compound_info)) ||
                            ((vt->flags & KMALLOC_COMMON) &&
                            VALID_MEMBER(page_slab) && 
VALID_MEMBER(page_first_page))) {
                                readmem(compound_head(page)+OFFSET(page_flags), 
KVADDR,
@@ -9873,7 +9888,8 @@ vaddr_to_kmem_cache(ulong vaddr, char *buf, int verbose)
 
        if ((vt->flags & KMALLOC_SLUB) ||
            ((vt->flags & KMALLOC_COMMON) && VALID_MEMBER(page_slab) && 
-           (VALID_MEMBER(page_compound_head) || 
VALID_MEMBER(page_first_page)))) {
+           (VALID_MEMBER(page_compound_head) || 
VALID_MEMBER(page_compound_info) ||
+            VALID_MEMBER(page_first_page)))) {
                 readmem(compound_head(page)+OFFSET(page_slab),
                         KVADDR, &cache, sizeof(void *),
                         "page.slab", FAULT_ON_ERROR);
@@ -9904,7 +9920,8 @@ is_slab_overload_page(ulong vaddr, ulong *page_head, char 
*buf)
 
         if ((vt->flags & SLAB_OVERLOAD_PAGE) &&
            is_page_ptr(vaddr, NULL) && VALID_MEMBER(page_slab) && 
-           (VALID_MEMBER(page_compound_head) || 
VALID_MEMBER(page_first_page))) {
+           (VALID_MEMBER(page_compound_head) || 
VALID_MEMBER(page_compound_info) ||
+            VALID_MEMBER(page_first_page))) {
                 readmem(compound_head(vaddr)+OFFSET(page_slab),
                         KVADDR, &cache, sizeof(void *),
                         "page.slab", FAULT_ON_ERROR);
@@ -9944,7 +9961,8 @@ vaddr_to_slab(ulong vaddr)
 
        slab = 0;
 
-        if ((vt->flags & KMALLOC_SLUB) || VALID_MEMBER(page_compound_head))
+       if ((vt->flags & KMALLOC_SLUB) || VALID_MEMBER(page_compound_head) ||
+           VALID_MEMBER(page_compound_info))
                slab = compound_head(page);
        else if (vt->flags & SLAB_OVERLOAD_PAGE)
                slab = compound_head(page);
@@ -20222,11 +20240,21 @@ get_kmem_cache_child_list(ulong **cache_buf, ulong 
root)
 static ulong
 compound_head(ulong page)
 {
-       ulong flags, first_page, compound_head;
+       ulong flags, first_page, compound_head, info, mask;
 
        first_page = page;
 
-       if (VALID_MEMBER(page_compound_head)) {
+       if (VALID_MEMBER(page_compound_info)) {
+               if (readmem(page + OFFSET(page_compound_info), KVADDR, &info,
+                   sizeof(ulong), "page.compound_info", RETURN_ON_ERROR)) {
+                       if (compound_info_has_mask) {
+                               mask = (info & 1) - 1;
+                               mask |= info;
+                               first_page = page & mask;
+                       } else if (info & 1)
+                               first_page = info - 1;
+               }
+       } else if (VALID_MEMBER(page_compound_head)) {
                if (readmem(page+OFFSET(page_compound_head), KVADDR, 
&compound_head, 
                    sizeof(ulong), "page.compound_head", RETURN_ON_ERROR)) {
                        if (compound_head & 1)
diff --git a/symbols.c b/symbols.c
index a7ccdb101033..1b734d775361 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10505,6 +10505,7 @@ dump_offset_table(char *spec, ulong makestruct)
                 OFFSET(page_active));
         fprintf(fp, "            page_compound_head: %ld\n",
                 OFFSET(page_compound_head));
+       fprintf(fp, "            page_compound_info: %ld\n", 
OFFSET(page_compound_info));
         fprintf(fp, "                  page_private: %ld\n", 
OFFSET(page_private));
        fprintf(fp, "                page_page_type: %ld\n",
                OFFSET(page_page_type));
-- 
2.55.0


++++++ crash-Fix-failure-of-runq-g-option-on-Linux-7.2-and-later-.patch ++++++
From: Kazuhito Hagio <[email protected]>
Date: Wed, 8 Jul 2026 02:45:50 +0000
Subject: Fix failure of "runq -g" option on Linux 7.2 and later kernels
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: 82039b0f21de4231d1fc03e8819c868a84b213f8
Patch-mainline: yes

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 <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 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.55.0


++++++ crash-Fix-kmem-i-option-to-display-swap-usage-on-Linux-6.1.patch ++++++
From: Kazuhito Hagio <[email protected]>
Date: Wed, 3 Jun 2026 07:12:57 +0000
Subject: Fix "kmem -i" option to display swap usage on Linux 6.18 and later
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: c894f05d3cdc5d3e61775c3f67bd6a0a24362a92
Patch-mainline: yes

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 <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 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.55.0


++++++ crash-Fix-kmem-s-command-on-Linux-7.1-and-later.patch ++++++
From: Kazuhito Hagio <[email protected]>
Date: Fri, 24 Jul 2026 01:27:22 +0000
Subject: Fix "kmem [-s]" command on Linux 7.1 and later
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: bb9a3fa67a79309fac6c805584c5b092c480c09a
Patch-mainline: yes

Kernel commit 5ba6bc27b1f9 ("slab: decouple pointer to barn from
kmem_cache_node") changed kmem_cache.node array into struct
kmem_cache_per_node_ptrs kmem_cache.per_node array.

Without the patch, "kmem <slab address>" and "kmem -s" option fail with
the following error.

  crash> kmem -s

  kmem: invalid structure member offset: kmem_cache_local_node
        FILE: memory.c  LINE: 19563  FUNCTION: get_kmem_cache_slub_data()

Signed-off-by: Kazuhito Hagio <[email protected]>
Acked-by: Tao Liu <[email protected]>
Acked-by: Dave Young <[email protected]>
Signed-off-by: Dave Young <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 defs.h    |  3 +++
 memory.c  | 19 +++++++++++++++----
 symbols.c |  4 ++++
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/defs.h b/defs.h
index 88b7bbeb2372..ef34db90113f 100644
--- a/defs.h
+++ b/defs.h
@@ -2291,6 +2291,8 @@ struct offset_table {                    /* stash of 
commonly-used offsets */
        long hrtimer_clock_base_index;
        long klp_patch_list;
        long page_compound_info;
+       long kmem_cache_per_node;
+       long kmem_cache_per_node_ptrs_node;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
@@ -2470,6 +2472,8 @@ 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 kmem_cache_per_node_ptrs;
 };
 
 struct array_table {
diff --git a/memory.c b/memory.c
index 5163ee663641..f2304f3ffe2f 100644
--- a/memory.c
+++ b/memory.c
@@ -871,6 +871,8 @@ vm_init(void)
                MEMBER_OFFSET_INIT(kmem_cache_inuse, "kmem_cache", "inuse");
                MEMBER_OFFSET_INIT(kmem_cache_align, "kmem_cache", "align");
                MEMBER_OFFSET_INIT(kmem_cache_node, "kmem_cache", "node");
+               if (INVALID_MEMBER(kmem_cache_node))
+                       MEMBER_OFFSET_INIT(kmem_cache_per_node, "kmem_cache", 
"per_node");
                MEMBER_OFFSET_INIT(kmem_cache_cpu_slab, "kmem_cache", 
"cpu_slab");
                MEMBER_OFFSET_INIT(kmem_cache_list, "kmem_cache", "list");
                MEMBER_OFFSET_INIT(kmem_cache_red_left_pad, "kmem_cache", 
"red_left_pad");
@@ -922,7 +924,12 @@ vm_init(void)
                        if (INVALID_MEMBER(page_objects))
                                ANON_MEMBER_OFFSET_INIT(page_objects, "slab", 
"objects");
                }
-               if (VALID_MEMBER(kmem_cache_node)) {
+               if (VALID_MEMBER(kmem_cache_per_node)) { /* Linux 7.1 and later 
*/
+                       MEMBER_OFFSET_INIT(kmem_cache_per_node_ptrs_node,
+                                       "kmem_cache_per_node_ptrs", "node");
+                       STRUCT_SIZE_INIT(kmem_cache_per_node_ptrs, 
"kmem_cache_per_node_ptrs");
+                       vt->flags |= CONFIG_NUMA;
+               } else if (VALID_MEMBER(kmem_cache_node)) {
                        ARRAY_LENGTH_INIT(len, NULL, "kmem_cache.node", NULL, 
0);
                        vt->flags |= CONFIG_NUMA;
                }
@@ -19555,9 +19562,13 @@ get_kmem_cache_slub_data(long cmd, struct meminfo *si)
        for (n = 0; n < vt->numnodes; n++) {
                if (vt->flags & CONFIG_NUMA) {
                        nt = &vt->node_table[n];
-                       node_ptr = ULONG(si->cache_buf +
-                               OFFSET(kmem_cache_node) +
-                               (sizeof(void *) * nt->node_id));
+                       if (VALID_MEMBER(kmem_cache_per_node)) /* Linux 7.1 and 
later */
+                               node_ptr = ULONG(si->cache_buf + 
OFFSET(kmem_cache_per_node) +
+                                               (SIZE(kmem_cache_per_node_ptrs) 
* nt->node_id) +
+                                               
OFFSET(kmem_cache_per_node_ptrs_node));
+                       else
+                               node_ptr = ULONG(si->cache_buf + 
OFFSET(kmem_cache_node) +
+                                               (sizeof(void *) * nt->node_id));
                } else
                        node_ptr = si->cache + 
                                OFFSET(kmem_cache_local_node);
diff --git a/symbols.c b/symbols.c
index 1b734d775361..1515385d5724 100644
--- a/symbols.c
+++ b/symbols.c
@@ -10933,6 +10933,9 @@ dump_offset_table(char *spec, ulong makestruct)
                 OFFSET(kmem_cache_oo));
         fprintf(fp, "             kmem_cache_random: %ld\n",
                 OFFSET(kmem_cache_random));
+       fprintf(fp, "           kmem_cache_per_node: %ld\n", 
OFFSET(kmem_cache_per_node));
+
+       fprintf(fp, " kmem_cache_per_node_ptrs_node: %ld\n", 
OFFSET(kmem_cache_per_node_ptrs_node));
 
         fprintf(fp, "    kmem_cache_node_nr_partial: %ld\n",
                 OFFSET(kmem_cache_node_nr_partial));
@@ -12044,6 +12047,7 @@ dump_offset_table(char *spec, ulong makestruct)
         fprintf(fp, "                    kmem_cache: %ld\n", SIZE(kmem_cache));
         fprintf(fp, "               kmem_cache_node: %ld\n", 
SIZE(kmem_cache_node));
         fprintf(fp, "                kmem_cache_cpu: %ld\n", 
SIZE(kmem_cache_cpu));
+       fprintf(fp, "      kmem_cache_per_node_ptrs: %ld\n", 
SIZE(kmem_cache_per_node_ptrs));
 
         fprintf(fp, "              swap_info_struct: %ld\n", 
                SIZE(swap_info_struct));
-- 
2.55.0


++++++ crash-Fix-runq-g-option-to-display-task_group-name-on-Linu.patch ++++++
From: Kazuhito Hagio <[email protected]>
Date: Wed, 8 Jul 2026 02:45:50 +0000
Subject: Fix "runq -g" option to display task_group name on Linux 6.15 and
 later
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: f336dfa79ed94895914e132c31f2db7e09bf4ab1
Patch-mainline: yes

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 <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 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.55.0


++++++ crash-Fix-swap-command-on-Linux-7.1-and-later.patch ++++++
From: Kazuhito Hagio <[email protected]>
Date: Wed, 3 Jun 2026 07:12:58 +0000
Subject: Fix "swap" command on Linux 7.1 and later
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: fdb94ed20ac85e8354224b0d691af342f4b63922
Patch-mainline: yes

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 <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 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.55.0


++++++ crash-support-kernel-7.x-and-8.x.patch ++++++
From: Ruirui Yang <[email protected]>
Date: Fri, 14 Aug 2026 11:44:03 +0800
Subject: Refactor kernel version checking code
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: 9550178eca33de9533e920e96cd8c05ecf465323
Patch-mainline: yes

In case linux banner can not be found in vmlinux for some reason.
The fallback checking of "Linux version" failed for kernel 7.x with
below error msg:

WARNING: kernel version inconsistency between vmlinux and dumpfile
crash: incompatible arguments:  vmlinux is not SMP -- vmcore is SMP

Jiri's case is OpenSUSE uses separate vmlinux.debug file, details see
https://github.com/crash-utility/crash/issues/232

But update the kernel version number in kernel sanity checking code
does workaround the issue.  Let's fix this separately.

A few improvements to the sanity checking including:
- Replace hardcoded version checks (2.x through 6.x) with a unified
  kernel_version_str_sanity_check() function
- Extend kernel version sanity checking to Linux 7.x kernels
- Add proper bounds checking and null pointer validation
- Ensure minor version number is numeric for stricter validation
- Reduce code duplication in verify_namelist() and debug_kernel_version()

Reported-by: Jiri Slaby <[email protected]>
Signed-off-by: Dave Young <[email protected]>
Reviewed-by: Mukesh Pilaniya <[email protected]>
Acked-by: Tao Liu <[email protected]>
Signed-off-by: Dave Young <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 kernel.c | 39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/kernel.c b/kernel.c
index e53038d5d8db..cf5e5bcfe785 100644
--- a/kernel.c
+++ b/kernel.c
@@ -29,6 +29,9 @@
 #endif
 #include "bfd.h"
 
+#define KERNEL_VERSION_MIN '2'
+#define KERNEL_VERSION_MAX '7'  /* latest linux mainline kernel major number */
+
 static void do_module_cmd(ulong, char *, ulong, char *, char *);
 static void show_module_taint(void);
 static char *find_module_objfile(char *, char *, char *);
@@ -104,6 +107,30 @@ static void check_vmcoreinfo(void);
 static int is_pvops_xen(void);
 static int get_linux_banner_from_vmlinux(char *, size_t);
 
+static bool kernel_version_str_sanity_check(char *buf)
+{
+       int n;
+       char *p;
+
+       if (!buf)
+               return FALSE;
+
+       p = strstr(buf, "Linux version ");
+       if (!p)
+               return FALSE;
+
+       n = strlen(p);
+
+       if (n < 17) /* "Linux version " (14) + "x.y" (3) = 17 */
+               return FALSE;
+
+       if (p[14] >= KERNEL_VERSION_MIN && p[14] <= KERNEL_VERSION_MAX
+                       && p[15] == '.' && p[16] >= '0' && p[16] <= '9')
+               return TRUE;
+
+       return FALSE;
+}
+
 /*
  * popuplate the global kernel table (kt) with kernel version
  * information parsed from UTSNAME/OSRELEASE string
@@ -1396,11 +1423,7 @@ verify_namelist()
        found = FALSE;
        sprintf(buffer3, "(unknown)");
         while (fgets(buffer, (BUFSIZE/2)-1, pipe)) {
-               if (!strstr(buffer, "Linux version 2.") &&
-                   !strstr(buffer, "Linux version 3.") &&
-                   !strstr(buffer, "Linux version 4.") &&
-                   !strstr(buffer, "Linux version 5.") &&
-                   !strstr(buffer, "Linux version 6."))
+               if (!kernel_version_str_sanity_check(buffer))
                        continue;
 
                 if (strstr(buffer, kt->proc_version)) {
@@ -5987,11 +6010,7 @@ debug_kernel_version(char *namelist)
 
        argc = 0;
         while (fgets(buf, BUFSIZE-1, pipe)) {
-                if (!strstr(buf, "Linux version 2.") &&
-                   !strstr(buf, "Linux version 3.") &&
-                   !strstr(buf, "Linux version 4.") &&
-                   !strstr(buf, "Linux version 5.") &&
-                   !strstr(buf, "Linux version 6."))
+               if (!kernel_version_str_sanity_check(buf))
                         continue;
 
                argc = parse_line(buf, arglist); 
-- 
2.55.0


++++++ crash-symbols-Add-support-for-mod-symtab-with-combined-GPL.patch ++++++
From: Alexander Egorenkov <[email protected]>
Date: Tue, 28 Apr 2026 12:16:37 +0200
Subject: symbols: Add support for mod symtab with combined GPL and non-GPL
 symbols
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: 3a415c07a18a465df2580365b43b4d8f8a5d815b
Patch-mainline: yes

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

Signed-off-by: Alexander Egorenkov <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 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.55.0


++++++ crash-symbols-use-non-debug-BFD-to-retrieve-.rodata.patch ++++++
From: Jiri Slaby <[email protected]>
Date: Fri, 14 Aug 2026 08:06:26 +0200
Subject: symbols: use non-debug BFD to retrieve .rodata
References: https://github.com/crash-utility/crash/issues/232
Git-repo: https://github.com/crash-utility/crash
Git-commit: abcb45e7d443e693a59a759ca2862530e917c891
Patch-mainline: yes

When running crash on openSUSE, get_linux_banner_from_vmlinux() returns
success but fill the target buffer with all zero bytes (`\0`).

This happens because `st->bfd` is initially opened for the main binary
(`vmlinux`), but is later overwritten with the debuginfo file
(`vmlinux.debug`) in `check_gnu_debuglink()`. In separate debug files,
`.rodata` has no content, so is marked only as `ALLOC` without
`SEC_HAS_CONTENTS`.

When `bfd_get_section_contents()` is called on a section without
`SEC_HAS_CONTENTS`, BFD clears the buffer to zeros and returns TRUE. As
a result, `get_linux_banner_from_vmlinux()` thinks it successfully read
the banner, while it actually received zeroed bytes.

Fix this by caching the original main executable's BFD (into
`st->bfd_orig`) before `st->bfd` gets swapped for the debuginfo file.

`get_linux_banner_from_vmlinux()` will then fall back to `st->bfd_orig`
if present, ensuring `.rodata` contents are read from the binary that
actually contains the raw section data.

Fixes #232.

Signed-off-by: Jiri Slaby <[email protected]>
Cc: Dave Young <[email protected]>
Cc: <[email protected]>
Cc: <[email protected]>
Reviewed-by: Dave Young <[email protected]>
Signed-off-by: Dave Young <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 defs.h    | 1 +
 kernel.c  | 5 +++--
 symbols.c | 1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/defs.h b/defs.h
index ef34db90113f..134e7597e966 100644
--- a/defs.h
+++ b/defs.h
@@ -2924,6 +2924,7 @@ struct symbol_table_data {
 #ifdef GDB_5_3
        struct _bfd *bfd;
 #else
+       struct bfd *bfd_orig;
        struct bfd *bfd;
 #endif
        struct sec *sections;
diff --git a/kernel.c b/kernel.c
index cf5e5bcfe785..723b88e90cb4 100644
--- a/kernel.c
+++ b/kernel.c
@@ -12164,6 +12164,7 @@ check_vmcoreinfo(void)
 static
 int get_linux_banner_from_vmlinux(char *buf, size_t size)
 {
+       struct bfd *bfd = st->bfd_orig ? : st->bfd;
        struct bfd_section *sect;
        long offset;
        ulong start_rodata;
@@ -12175,7 +12176,7 @@ int get_linux_banner_from_vmlinux(char *buf, size_t 
size)
        else
                return FALSE;
 
-       sect = bfd_get_section_by_name(st->bfd, ".rodata");
+       sect = bfd_get_section_by_name(bfd, ".rodata");
        if (!sect)
                return FALSE;
 
@@ -12187,7 +12188,7 @@ int get_linux_banner_from_vmlinux(char *buf, size_t 
size)
         */
        offset = symbol_value("linux_banner") - start_rodata;
 
-       if (!bfd_get_section_contents(st->bfd,
+       if (!bfd_get_section_contents(bfd,
                                      sect,
                                      buf,
                                      offset,
diff --git a/symbols.c b/symbols.c
index 1515385d5724..270e14e26d28 100644
--- a/symbols.c
+++ b/symbols.c
@@ -444,6 +444,7 @@ check_gnu_debuglink(bfd *bfd)
        return FALSE;
 
 reset_bfd:
+       st->bfd_orig = st->bfd;
 
         if ((st->bfd = bfd_openr(pc->debuginfo_file, NULL)) == NULL)
                 error(FATAL, "cannot open object file: %s\n", 
-- 
2.55.0


++++++ crash-x86_64-Fix-bt-command-for-noreturn-functions.patch ++++++
From: Kazuhito Hagio <[email protected]>
Date: Fri, 29 May 2026 05:00:03 +0000
Subject: x86_64: Fix "bt" command for noreturn functions
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: 7b3f6e0f60be1dd2d4c1b20175be96137cf61438
Patch-mainline: yes

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 <[email protected]>
Signed-off-by: Kazuhito Hagio <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 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.55.0


++++++ crash-x86_64-Fix-bt-command-to-use-correct-ORC-register-va.patch ++++++
From: Kazuhito Hagio <[email protected]>
Date: Mon, 1 Jun 2026 05:38:11 +0000
Subject: x86_64: Fix "bt" command to use correct ORC register values on Linux
 7.1 and later
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: d0ee428664f90beaf498fa0edc129cdead204abc
Patch-mainline: yes

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 <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 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.55.0


++++++ crash-x86_64-Make-ORC_REG_SP-and-ORC_REG_PREV_SP-independe.patch ++++++
From: Tao Liu <[email protected]>
Date: Tue, 4 Aug 2026 15:20:33 +1200
Subject: x86_64: Make ORC_REG_SP and ORC_REG_PREV_SP independent from kernel
 version
References: kernel 7.1
Git-repo: https://github.com/crash-utility/crash
Git-commit: bfce25840cffabf0574825e796b0284ed36276bb
Patch-mainline: yes

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 <[email protected]>
Reviewed-by: MUKESH KUMAR PILANIYA <[email protected]>
Reviewed-by: Dave Young <[email protected]>
Signed-off-by: Tao Liu <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 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.55.0

Reply via email to