diff -Nru crash-8.0.2/debian/changelog crash-8.0.2/debian/changelog --- crash-8.0.2/debian/changelog 2023-07-06 14:49:16.000000000 +0000 +++ crash-8.0.2/debian/changelog 2023-10-03 09:24:54.000000000 +0000 @@ -1,3 +1,17 @@ +crash (8.0.2-1ubuntu2) mantic; urgency=medium + + * d/p/lp2038249-SLUB-Fix-for-offset-change-of-struct-slab-members-on.patch + d/p/lp2038249-x86_64-Fix-for-move-of-per-cpu-variables-into-struct.patch + d/p/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.1-and-later.patch + d/p/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.2-rc1-and-l.patch + d/p/lp2038249-Support-module-memory-layout-change-on-Linux-6.4.patch + d/p/lp2038249-Fix-failure-of-gathering-task-table-on-Linux-6.5-rc1.patch + d/p/lp2038249-Fix-compilation-error-due-to-new-strlcpy-function-th.patch + Fix the dump file parsing issue arises from structural changes in Linux + kernel 6.5 (LP: #2038249) + + -- Chengen Du Tue, 03 Oct 2023 09:24:54 +0000 + crash (8.0.2-1ubuntu1) mantic; urgency=medium * Merge with Debian; remaining changes: diff -Nru crash-8.0.2/debian/patches/lp2038249-Fix-compilation-error-due-to-new-strlcpy-function-th.patch crash-8.0.2/debian/patches/lp2038249-Fix-compilation-error-due-to-new-strlcpy-function-th.patch --- crash-8.0.2/debian/patches/lp2038249-Fix-compilation-error-due-to-new-strlcpy-function-th.patch 1970-01-01 00:00:00.000000000 +0000 +++ crash-8.0.2/debian/patches/lp2038249-Fix-compilation-error-due-to-new-strlcpy-function-th.patch 2023-10-03 09:23:17.000000000 +0000 @@ -0,0 +1,55 @@ +From: Lianbo Jiang +Date: Wed Jul 5 10:02:59 2023 +0800 +Subject: Fix compilation error due to new strlcpy function that glibc added + +The crash-utility has its own strlcpy(), but recently the latest glibc +has also implemented the strlcpy function, which is derived from +OpenBSD. Eventually this caused the following compilation error: + + # make -j8 lzo + ... + In file included from global_data.c:18: + defs.h:5556:8: error: conflicting types for ‘strlcpy’; have ‘size_t(char *, char *, size_t)’ {aka ‘long unsigned int(char *, char *, long unsigned int)’} + 5556 | size_t strlcpy(char *, char *, size_t); + | ^~~~~~~ + In file included from memory.c:19: + defs.h:5556:8: error: conflicting types for ‘strlcpy’; have ‘size_t(char *, char *, size_t)’ {aka ‘long unsigned int(char *, char *, long unsigned int)’} + 5556 | size_t strlcpy(char *, char *, size_t); + | ^~~~~~~ + ... + +To fix the issue, let's declare the strlcpy() as a weak function and +keep the same parameter types as the glibc function has. + +Related glibc commits: +454a20c8756c ("Implement strlcpy and strlcat [BZ #178]") +d2fda60e7c40 ("manual: Manual update for strlcat, strlcpy, wcslcat, wclscpy") +388ae538ddcb ("hurd: Add strlcpy, strlcat, wcslcpy, wcslcat to libc.abilist") + +Signed-off-by: Lianbo Jiang + +Bug-Ubuntu: https://launchpad.net/bugs/2038249 +Origin: upstream, https://github.com/crash-utility/crash/commit/4ee56105881d7bb1da1e668ac5bb47a4e0846676 + +--- crash-8.0.2.orig/defs.h ++++ crash-8.0.2/defs.h +@@ -5333,7 +5333,7 @@ uint32_t swap32(uint32_t, int); + uint64_t swap64(uint64_t, int); + ulong *get_cpumask_buf(void); + int make_cpumask(char *, ulong *, int, int *); +-size_t strlcpy(char *, char *, size_t); ++size_t strlcpy(char *, const char *, size_t) __attribute__ ((__weak__)); + struct rb_node *rb_first(struct rb_root *); + struct rb_node *rb_parent(struct rb_node *, struct rb_node *); + struct rb_node *rb_right(struct rb_node *, struct rb_node *); +--- crash-8.0.2.orig/tools.c ++++ crash-8.0.2/tools.c +@@ -6762,7 +6762,7 @@ make_cpumask_error: + * always be NULL-terminated. + */ + size_t +-strlcpy(char *dest, char *src, size_t size) ++strlcpy(char *dest, const char *src, size_t size) + { + size_t ret = strlen(src); + diff -Nru crash-8.0.2/debian/patches/lp2038249-Fix-failure-of-gathering-task-table-on-Linux-6.5-rc1.patch crash-8.0.2/debian/patches/lp2038249-Fix-failure-of-gathering-task-table-on-Linux-6.5-rc1.patch --- crash-8.0.2/debian/patches/lp2038249-Fix-failure-of-gathering-task-table-on-Linux-6.5-rc1.patch 1970-01-01 00:00:00.000000000 +0000 +++ crash-8.0.2/debian/patches/lp2038249-Fix-failure-of-gathering-task-table-on-Linux-6.5-rc1.patch 2023-10-03 09:19:29.000000000 +0000 @@ -0,0 +1,105 @@ +From: Kazuhito Hagio +Date: Fri Jun 23 16:34:35 2023 +0900 +Subject: Fix failure of gathering task table on Linux 6.5-rc1 and later + +Kernel commit b69f0aeb0689 ("pid: Replace struct pid 1-element array +with flex-array") changed pid.numbers[1] to pid.numbers[]. With this, +the size of struct pid does not contain the size of struct upid: + + (gdb) ptype /o struct pid + /* offset | size */ type = struct pid { + /* 0 | 4 */ refcount_t count; + ... + /* 96 | 0 */ struct upid numbers[]; + ^^^^ ^^^ + /* total size (bytes): 96 */ + } ^^^^ + +As a result, in refresh_xarray_task_table(), crash does not read the +data of pid.numbers[0].ns and cannot gather the task table correctly. + + $ crash vmlinux vmcore + ... + WARNING: active task ffff936992ad0000 on cpu 1 not found in PID hash + ... + crash> ps -S + RU: 9 + crash> + +Increase the size of reading struct pid by SIZE(upid) in this case. + +Signed-off-by: Kazuhito Hagio + +Bug-Ubuntu: https://launchpad.net/bugs/2038249 +Origin: upstream, https://github.com/crash-utility/crash/commit/88580068b7dd96bf679c82bdc05e146968ade10c + +--- crash-8.0.2.orig/defs.h ++++ crash-8.0.2/defs.h +@@ -2392,6 +2392,7 @@ struct array_table { + int task_struct_rlim; + int signal_struct_rlim; + int vm_numa_stat; ++ int pid_numbers; + }; + + /* +--- crash-8.0.2.orig/symbols.c ++++ crash-8.0.2/symbols.c +@@ -9695,6 +9695,8 @@ builtin_array_length(char *s, int len, i + lenptr = &array_table.signal_struct_rlim; + else if (STREQ(s, "vm_numa_stat")) + lenptr = &array_table.vm_numa_stat; ++ else if (STREQ(s, "pid.numbers")) ++ lenptr = &array_table.pid_numbers; + + if (!lenptr) /* not stored */ + return(len); +@@ -12065,6 +12067,7 @@ dump_offset_table(char *spec, ulong make + ARRAY_LENGTH(signal_struct_rlim)); + fprintf(fp, " vm_numa_stat: %d\n", + ARRAY_LENGTH(vm_numa_stat)); ++ fprintf(fp, " pid_numbers: %d\n", ARRAY_LENGTH(pid_numbers)); + + if (spec) { + int in_size_table, in_array_table, arrays, offsets, sizes; +--- crash-8.0.2.orig/task.c ++++ crash-8.0.2/task.c +@@ -352,6 +352,7 @@ task_init(void) + MEMBER_OFFSET_INIT(upid_ns, "upid", "ns"); + MEMBER_OFFSET_INIT(upid_pid_chain, "upid", "pid_chain"); + MEMBER_OFFSET_INIT(pid_numbers, "pid", "numbers"); ++ ARRAY_LENGTH_INIT(len, pid_numbers, "pid.numbers", NULL, 0); + MEMBER_OFFSET_INIT(pid_tasks, "pid", "tasks"); + tt->init_pid_ns = symbol_value("init_pid_ns"); + } +@@ -2571,6 +2572,7 @@ refresh_xarray_task_table(void) + char *tp; + struct list_pair xp; + char *pidbuf; ++ long pid_size = SIZE(pid); + + if (DUMPFILE() && (tt->flags & TASK_INIT_DONE)) /* impossible */ + return; +@@ -2600,8 +2602,12 @@ refresh_xarray_task_table(void) + if (CRASHDEBUG(1)) + console("xarray: count: %ld\n", count); + ++ /* 6.5: b69f0aeb0689 changed pid.numbers[1] to numbers[] */ ++ if (ARRAY_LENGTH(pid_numbers) == 0) ++ pid_size += SIZE(upid); ++ + retries = 0; +- pidbuf = GETBUF(SIZE(pid)); ++ pidbuf = GETBUF(pid_size); + + retry_xarray: + if (retries && DUMPFILE()) +@@ -2669,7 +2675,7 @@ retry_xarray: + * - get task from address of task->pids[0] + */ + if (!readmem(next, KVADDR, pidbuf, +- SIZE(pid), "pid", RETURN_ON_ERROR|QUIET)) { ++ pid_size, "pid", RETURN_ON_ERROR|QUIET)) { + error(INFO, "\ncannot read pid struct from xarray\n"); + if (DUMPFILE()) + continue; diff -Nru crash-8.0.2/debian/patches/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.1-and-later.patch crash-8.0.2/debian/patches/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.1-and-later.patch --- crash-8.0.2/debian/patches/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.1-and-later.patch 1970-01-01 00:00:00.000000000 +0000 +++ crash-8.0.2/debian/patches/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.1-and-later.patch 2023-10-03 08:58:29.000000000 +0000 @@ -0,0 +1,38 @@ +From: Kazuhito Hagio +Date: Thu Jan 5 17:18:51 2023 +0900 +Subject: SLAB: Fix for "kmem -s|-S" options on Linux 6.1 and later + +Kernel commit e36ce448a08d ("mm/slab: use kmalloc_node() for off slab +freelist_idx_t array allocation"), which is contained in Linux 6.1 and +later kernels, removed kmem_cache.freelist_cache member on kernels +configured with CONFIG_SLAB=y. + +Without the patch, crash does not set SLAB_OVERLOAD_PAGE and +"kmem -s|-S" options fail with the following error: + + kmem: invalid structure member offset: slab_list + FILE: memory.c LINE: 12156 FUNCTION: verify_slab_v2() + +Use kmem_cache.freelist_size instead, which was introduced together +with kmem_cache.freelist_cache by kernel commit 8456a648cf44. + +Signed-off-by: Kazuhito Hagio + +Bug-Ubuntu: https://launchpad.net/bugs/2038249 +Origin: upstream, https://github.com/crash-utility/crash/commit/120d6e89fc14eb7f1c9a3106305c7066730f36b8 + +--- crash-8.0.2.orig/memory.c ++++ crash-8.0.2/memory.c +@@ -535,8 +535,11 @@ vm_init(void) + /* + * slab: overload struct slab over struct page + * https://lkml.org/lkml/2013/10/16/155 ++ * ++ * commit e36ce448a08d removed kmem_cache.freelist_cache in 6.1, ++ * so use freelist_size instead. + */ +- if (MEMBER_EXISTS("kmem_cache", "freelist_cache")) { ++ if (MEMBER_EXISTS("kmem_cache", "freelist_size")) { + vt->flags |= SLAB_OVERLOAD_PAGE; + ANON_MEMBER_OFFSET_INIT(page_s_mem, "page", "s_mem"); + ANON_MEMBER_OFFSET_INIT(page_freelist, "page", "freelist"); diff -Nru crash-8.0.2/debian/patches/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.2-rc1-and-l.patch crash-8.0.2/debian/patches/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.2-rc1-and-l.patch --- crash-8.0.2/debian/patches/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.2-rc1-and-l.patch 1970-01-01 00:00:00.000000000 +0000 +++ crash-8.0.2/debian/patches/lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.2-rc1-and-l.patch 2023-10-03 09:00:56.000000000 +0000 @@ -0,0 +1,225 @@ +From: Kazuhito Hagio +Date: Thu Jan 5 17:36:42 2023 +0900 +Subject: SLAB: Fix for "kmem -s|-S" options on Linux 6.2-rc1 and later + +Kernel commit 130d4df57390 ("mm/sl[au]b: rearrange struct slab fields to +allow larger rcu_head"), which is contained in Linux 6.2-rc1 and later +kernels, changed the offset of slab.slab_list and now it's not equal to +the offset of page.lru. + +Without the patch, "kmem -s|-S" options print errors and zeros for slab +counters like this for kernels configured with CONFIG_SLAB=y. + + crash> kmem -s + CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME + kmem: rpc_inode_cache: partial list: page/slab: fffff31ac4125190 bad active counter: 99476865 + kmem: rpc_inode_cache: partial list: page/slab: fffff31ac4125190 bad s_mem pointer: 100000003 + kmem: rpc_inode_cache: full list: page/slab: fffff31ac4125150 bad active counter: 99476225 + kmem: rpc_inode_cache: full list: page/slab: fffff31ac4125150 bad active counter: 99476225 + kmem: rpc_inode_cache: full list: page/slab: fffff31ac4125150 bad s_mem pointer: 100000005 + ffff930202adfb40 704 0 0 0 4k rpc_inode_cache + ... + +Signed-off-by: Kazuhito Hagio + +Bug-Ubuntu: https://launchpad.net/bugs/2038249 +Origin: upstream, https://github.com/crash-utility/crash/commit/ac96e17d1de51016ee1a983e68c7e840ff55ab8d + +--- crash-8.0.2.orig/memory.c ++++ crash-8.0.2/memory.c +@@ -78,6 +78,7 @@ struct meminfo { /* general pu + int *freelist; + int freelist_index_size; + ulong random; ++ ulong list_offset; + }; + + /* +@@ -553,6 +554,8 @@ vm_init(void) + MEMBER_OFFSET_INIT(page_freelist, "slab", "freelist"); + if (INVALID_MEMBER(page_active)) + MEMBER_OFFSET_INIT(page_active, "slab", "active"); ++ ++ MEMBER_OFFSET_INIT(slab_slab_list, "slab", "slab_list"); + } + + if (!VALID_STRUCT(kmem_slab_s) && VALID_STRUCT(slab_s)) { +@@ -10750,6 +10753,8 @@ dump_kmem_cache_percpu_v2(struct meminfo + if (vt->flags & SLAB_OVERLOAD_PAGE) { + si->freelist = si->kmem_bufctl; + si->freelist_index_size = slab_freelist_index_size(); ++ si->list_offset = VALID_MEMBER(slab_slab_list) ? ++ OFFSET(slab_slab_list) : OFFSET(page_lru); + } + for (i = 0; i < vt->kmem_max_cpus; i++) + si->cpudata[i] = (ulong *) +@@ -11966,7 +11971,7 @@ do_slab_chain_slab_overload_page(long cm + } + last = si->slab; + +- readmem(si->slab - OFFSET(page_lru), KVADDR, page_buf, ++ readmem(si->slab - si->list_offset, KVADDR, page_buf, + SIZE(page), "page (slab) buffer", + FAULT_ON_ERROR); + +@@ -11979,8 +11984,7 @@ do_slab_chain_slab_overload_page(long cm + + si->num_slabs++; + +- si->slab = ULONG(page_buf + +- OFFSET(page_lru)); ++ si->slab = ULONG(page_buf + si->list_offset); + + /* + * Check for slab transition. (Tony Dziedzic) +@@ -12007,11 +12011,11 @@ do_slab_chain_slab_overload_page(long cm + case SLAB_WALKTHROUGH: + if (si->flags & SLAB_OVERLOAD_PAGE_PTR) { + specified_slab = si->spec_addr; +- si->slab = si->spec_addr + OFFSET(page_lru); ++ si->slab = si->spec_addr + si->list_offset; + } else { + specified_slab = si->slab; + if (si->slab) +- si->slab += OFFSET(page_lru); ++ si->slab += si->list_offset; + } + si->flags |= (SLAB_WALKTHROUGH|SLAB_FIRST_NODE); + si->flags &= ~SLAB_GET_COUNTS; +@@ -12065,7 +12069,7 @@ do_slab_chain_slab_overload_page(long cm + if (si->slab == slab_chains[s]) + continue; + +- readmem(si->slab - OFFSET(page_lru), KVADDR, page_buf, ++ readmem(si->slab - si->list_offset, KVADDR, page_buf, + SIZE(page), "page (slab) buffer", + FAULT_ON_ERROR); + +@@ -12225,7 +12229,7 @@ verify_slab_overload_page(struct meminfo + + errcnt = 0; + +- if (!readmem(si->slab - OFFSET(page_lru), KVADDR, page_buf, ++ if (!readmem(si->slab - si->list_offset, KVADDR, page_buf, + SIZE(page), "page (slab) buffer", QUIET|RETURN_ON_ERROR)) { + error(INFO, "%s: %s list: bad slab pointer: %lx\n", + si->curname, list, si->slab); +@@ -12233,7 +12237,7 @@ verify_slab_overload_page(struct meminfo + return FALSE; + } + +- list_head = (struct kernel_list_head *)(page_buf + OFFSET(page_lru)); ++ list_head = (struct kernel_list_head *)(page_buf + si->list_offset); + if (!IS_KVADDR((ulong)list_head->next) || + !accessible((ulong)list_head->next)) { + error(INFO, "%s: %s list: page/slab: %lx bad next pointer: %lx\n", +@@ -12552,7 +12556,7 @@ dump_slab_overload_page(struct meminfo * + int tmp; + ulong slab_overload_page, freelist; + +- slab_overload_page = si->slab - OFFSET(page_lru); ++ slab_overload_page = si->slab - si->list_offset; + + readmem(slab_overload_page + OFFSET(page_s_mem), + KVADDR, &si->s_mem, sizeof(ulong), +@@ -12779,12 +12783,12 @@ gather_slab_free_list_slab_overload_page + + if (CRASHDEBUG(1)) + fprintf(fp, "slab page: %lx active: %ld si->c_num: %ld\n", +- si->slab - OFFSET(page_lru), si->s_inuse, si->c_num); ++ si->slab - si->list_offset, si->s_inuse, si->c_num); + + if (si->s_inuse == si->c_num ) + return; + +- slab_overload_page = si->slab - OFFSET(page_lru); ++ slab_overload_page = si->slab - si->list_offset; + readmem(slab_overload_page + OFFSET(page_freelist), + KVADDR, &freelist, sizeof(void *), "page freelist", + FAULT_ON_ERROR); +@@ -13082,7 +13086,7 @@ dump_slab_objects_percpu(struct meminfo + + if ((si->flags & ADDRESS_SPECIFIED) && + (vt->flags & SLAB_OVERLOAD_PAGE)) { +- readmem(si->slab - OFFSET(page_lru) + OFFSET(page_freelist), ++ readmem(si->slab - si->list_offset + OFFSET(page_freelist), + KVADDR, &freelist, sizeof(ulong), "page.freelist", + FAULT_ON_ERROR); + +@@ -18696,6 +18700,9 @@ dump_kmem_cache_slub(struct meminfo *si) + + si->cache_buf = GETBUF(SIZE(kmem_cache)); + ++ si->list_offset = VALID_MEMBER(slab_slab_list) ? ++ OFFSET(slab_slab_list) : OFFSET(page_lru); ++ + if (VALID_MEMBER(page_objects) && + OFFSET(page_objects) == OFFSET(page_inuse)) + si->flags |= SLAB_BITFIELD; +@@ -19467,7 +19474,6 @@ do_node_lists_slub(struct meminfo *si, u + { + ulong next, last, list_head, flags; + int first; +- long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru); + + if (!node_ptr) + return; +@@ -19481,7 +19487,7 @@ do_node_lists_slub(struct meminfo *si, u + next == list_head ? " (empty)\n" : ""); + first = 0; + while (next != list_head) { +- si->slab = last = next - list_off; ++ si->slab = last = next - si->list_offset; + if (first++ == 0) + fprintf(fp, " %s", slab_hdr); + +@@ -19504,7 +19510,7 @@ do_node_lists_slub(struct meminfo *si, u + + if (!IS_KVADDR(next) || + ((next != list_head) && +- !is_page_ptr(next - list_off, NULL))) { ++ !is_page_ptr(next - si->list_offset, NULL))) { + error(INFO, + "%s: partial list slab: %lx invalid page.lru.next: %lx\n", + si->curname, last, next); +@@ -19531,7 +19537,7 @@ do_node_lists_slub(struct meminfo *si, u + next == list_head ? " (empty)\n" : ""); + first = 0; + while (next != list_head) { +- si->slab = next - list_off; ++ si->slab = next - si->list_offset; + if (first++ == 0) + fprintf(fp, " %s", slab_hdr); + +@@ -19748,7 +19754,6 @@ count_partial(ulong node, struct meminfo + short inuse, objects; + ulong total_inuse; + ulong count = 0; +- long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru); + + count = 0; + total_inuse = 0; +@@ -19760,12 +19765,12 @@ count_partial(ulong node, struct meminfo + hq_open(); + + while (next != list_head) { +- if (!readmem(next - list_off + OFFSET(page_inuse), ++ if (!readmem(next - si->list_offset + OFFSET(page_inuse), + KVADDR, &inuse, sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) { + hq_close(); + return -1; + } +- last = next - list_off; ++ last = next - si->list_offset; + + if (inuse == -1) { + error(INFO, +@@ -19791,7 +19796,7 @@ count_partial(ulong node, struct meminfo + } + if (!IS_KVADDR(next) || + ((next != list_head) && +- !is_page_ptr(next - list_off, NULL))) { ++ !is_page_ptr(next - si->list_offset, NULL))) { + error(INFO, "%s: partial list slab: %lx invalid page.lru.next: %lx\n", + si->curname, last, next); + break; diff -Nru crash-8.0.2/debian/patches/lp2038249-SLUB-Fix-for-offset-change-of-struct-slab-members-on.patch crash-8.0.2/debian/patches/lp2038249-SLUB-Fix-for-offset-change-of-struct-slab-members-on.patch --- crash-8.0.2/debian/patches/lp2038249-SLUB-Fix-for-offset-change-of-struct-slab-members-on.patch 1970-01-01 00:00:00.000000000 +0000 +++ crash-8.0.2/debian/patches/lp2038249-SLUB-Fix-for-offset-change-of-struct-slab-members-on.patch 2023-10-03 08:54:44.000000000 +0000 @@ -0,0 +1,136 @@ +From: Kazuhito Hagio +Date: Fri Dec 16 14:03:46 2022 +0900 +Subject: SLUB: Fix for offset change of struct slab members on Linux 6.2-rc1 + +The following kernel commits split slab info from struct page into +struct slab in Linux 5.17. + + d122019bf061 ("mm: Split slab into its own type") + 07f910f9b729 ("mm: Remove slab from struct page") + +Crash commit 5f390ed811b0 followed the change for SLUB, but crash still +uses the offset of page.lru inappropriately. Luckily, it could work +because it was the same value as the offset of slab.slab_list until +Linux 6.1. + +However, kernel commit 130d4df57390 ("mm/sl[au]b: rearrange struct slab +fields to allow larger rcu_head") in Linux 6.2-rc1 changed the offset of +slab.slab_list. As a result, without the patch, "kmem -s|-S" options +print the following errors and fail to print values correctly for +kernels configured with CONFIG_SLUB. + + crash> kmem -S filp + CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME + kmem: filp: partial list slab: ffffcc650405ab88 invalid page.inuse: -1 + ffff8fa0401eca00 232 1267 1792 56 8k filp + ... + KMEM_CACHE_NODE NODE SLABS PARTIAL PER-CPU + ffff8fa0401cb8c0 0 56 24 8 + NODE 0 PARTIAL: + SLAB MEMORY NODE TOTAL ALLOCATED FREE + kmem: filp: invalid partial list slab pointer: ffffcc650405ab88 + +Signed-off-by: Kazuhito Hagio + +Bug-Ubuntu: https://launchpad.net/bugs/2038249 +Origin: backport, https://github.com/crash-utility/crash/commit/d83df2fb66cd77877d365fda32cd45c531796599 +[chengen - modify defs.h context] + +--- crash-8.0.2.orig/defs.h ++++ crash-8.0.2/defs.h +@@ -2181,6 +2181,7 @@ struct offset_table { + long blk_mq_tags_nr_reserved_tags; + long blk_mq_tags_rqs; + long request_queue_hctx_table; ++ long slab_slab_list; + }; + + struct size_table { /* stash of commonly-used sizes */ +--- crash-8.0.2.orig/memory.c ++++ crash-8.0.2/memory.c +@@ -781,6 +781,8 @@ vm_init(void) + if (INVALID_MEMBER(page_slab)) + MEMBER_OFFSET_INIT(page_slab, "slab", "slab_cache"); + ++ MEMBER_OFFSET_INIT(slab_slab_list, "slab", "slab_list"); ++ + MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page"); + if (INVALID_MEMBER(page_slab_page)) + ANON_MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page"); +@@ -19462,6 +19464,7 @@ do_node_lists_slub(struct meminfo *si, u + { + ulong next, last, list_head, flags; + int first; ++ long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru); + + if (!node_ptr) + return; +@@ -19475,7 +19478,7 @@ do_node_lists_slub(struct meminfo *si, u + next == list_head ? " (empty)\n" : ""); + first = 0; + while (next != list_head) { +- si->slab = last = next - OFFSET(page_lru); ++ si->slab = last = next - list_off; + if (first++ == 0) + fprintf(fp, " %s", slab_hdr); + +@@ -19498,7 +19501,7 @@ do_node_lists_slub(struct meminfo *si, u + + if (!IS_KVADDR(next) || + ((next != list_head) && +- !is_page_ptr(next - OFFSET(page_lru), NULL))) { ++ !is_page_ptr(next - list_off, NULL))) { + error(INFO, + "%s: partial list slab: %lx invalid page.lru.next: %lx\n", + si->curname, last, next); +@@ -19525,7 +19528,7 @@ do_node_lists_slub(struct meminfo *si, u + next == list_head ? " (empty)\n" : ""); + first = 0; + while (next != list_head) { +- si->slab = next - OFFSET(page_lru); ++ si->slab = next - list_off; + if (first++ == 0) + fprintf(fp, " %s", slab_hdr); + +@@ -19742,6 +19745,7 @@ count_partial(ulong node, struct meminfo + short inuse, objects; + ulong total_inuse; + ulong count = 0; ++ long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru); + + count = 0; + total_inuse = 0; +@@ -19753,12 +19757,12 @@ count_partial(ulong node, struct meminfo + hq_open(); + + while (next != list_head) { +- if (!readmem(next - OFFSET(page_lru) + OFFSET(page_inuse), ++ if (!readmem(next - list_off + OFFSET(page_inuse), + KVADDR, &inuse, sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) { + hq_close(); + return -1; + } +- last = next - OFFSET(page_lru); ++ last = next - list_off; + + if (inuse == -1) { + error(INFO, +@@ -19784,7 +19788,7 @@ count_partial(ulong node, struct meminfo + } + if (!IS_KVADDR(next) || + ((next != list_head) && +- !is_page_ptr(next - OFFSET(page_lru), NULL))) { ++ !is_page_ptr(next - list_off, NULL))) { + error(INFO, "%s: partial list slab: %lx invalid page.lru.next: %lx\n", + si->curname, last, next); + break; +--- crash-8.0.2.orig/symbols.c ++++ crash-8.0.2/symbols.c +@@ -9700,6 +9700,7 @@ dump_offset_table(char *spec, ulong make + OFFSET(slab_inuse)); + fprintf(fp, " slab_free: %ld\n", + OFFSET(slab_free)); ++ fprintf(fp, " slab_slab_list: %ld\n", OFFSET(slab_slab_list)); + + fprintf(fp, " kmem_cache_size: %ld\n", + OFFSET(kmem_cache_size)); diff -Nru crash-8.0.2/debian/patches/lp2038249-Support-module-memory-layout-change-on-Linux-6.4.patch crash-8.0.2/debian/patches/lp2038249-Support-module-memory-layout-change-on-Linux-6.4.patch --- crash-8.0.2/debian/patches/lp2038249-Support-module-memory-layout-change-on-Linux-6.4.patch 1970-01-01 00:00:00.000000000 +0000 +++ crash-8.0.2/debian/patches/lp2038249-Support-module-memory-layout-change-on-Linux-6.4.patch 2023-10-03 09:15:12.000000000 +0000 @@ -0,0 +1,2366 @@ +From: Kazuhito Hagio +Date: Thu Jun 22 16:09:07 2023 +0900 +Subject: Support module memory layout change on Linux 6.4 + +Support module memory layout change on Linux 6.4 by kernel commit +ac3b43283923 ("module: replace module_layout with module_memory") [1]. +Without the patch, crash cannot even start a session with an error +message like this: + + crash: invalid structure member offset: module_core_size + FILE: kernel.c LINE: 3787 FUNCTION: module_init() + +[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ac3b43283923 + +Signed-off-by: Kazuhito Hagio + +Bug-Ubuntu: https://launchpad.net/bugs/2038249 +Origin: backport, https://github.com/crash-utility/crash/commit/7750e61fdb2a083f26156a5338aa2ebe26447f3f +[chengen - modify defs.h/gdb-10.2.patch context] + +--- crash-8.0.2.orig/defs.h ++++ crash-8.0.2/defs.h +@@ -669,6 +669,7 @@ struct new_utsname { + #define IRQ_DESC_TREE_RADIX (0x40ULL) + #define IRQ_DESC_TREE_XARRAY (0x80ULL) + #define KMOD_PAX (0x100ULL) ++#define KMOD_MEMORY (0x200ULL) + + #define XEN() (kt->flags & ARCH_XEN) + #define OPENVZ() (kt->flags & ARCH_OPENVZ) +@@ -676,6 +677,7 @@ struct new_utsname { + #define PVOPS_XEN() (kt->flags & ARCH_PVOPS_XEN) + + #define PAX_MODULE_SPLIT() (kt->flags2 & KMOD_PAX) ++#define MODULE_MEMORY() (kt->flags2 & KMOD_MEMORY) + + #define XEN_MACHINE_TO_MFN(m) ((ulonglong)(m) >> PAGESHIFT()) + #define XEN_PFN_TO_PSEUDO(p) ((ulonglong)(p) << PAGESHIFT()) +@@ -2182,6 +2184,9 @@ struct offset_table { + long blk_mq_tags_rqs; + long request_queue_hctx_table; + long slab_slab_list; ++ long module_mem; ++ long module_memory_base; ++ long module_memory_size; + }; + + struct size_table { /* stash of commonly-used sizes */ +@@ -2352,6 +2357,7 @@ struct size_table { /* stash of + long sbitmap_queue; + long sbq_wait_state; + long blk_mq_tags; ++ long module_memory; + }; + + struct array_table { +@@ -2880,6 +2886,23 @@ struct mod_section_data { + ulong size; + int priority; + int flags; ++ ulong addr; ++}; ++ ++/* Emulate enum mod_mem_type in include/linux/module.h */ ++#define MOD_TEXT (0) ++#define MOD_DATA (1) ++#define MOD_RODATA (2) ++#define MOD_RO_AFTER_INIT (3) ++#define MOD_INIT_TEXT (4) ++#define MOD_INIT_DATA (5) ++#define MOD_INIT_RODATA (6) ++#define MOD_MEM_NUM_TYPES (7) ++#define MOD_INVALID (-1) ++ ++struct module_memory { ++ ulong base; ++ uint size; + }; + + struct load_module { +@@ -2915,19 +2938,29 @@ struct load_module { + ulong mod_percpu; + ulong mod_percpu_size; + struct objfile *loaded_objfile; +-}; + +-#define IN_MODULE(A,L) \ +- (((ulong)(A) >= (L)->mod_base) && ((ulong)(A) < ((L)->mod_base+(L)->mod_size))) +- +-#define IN_MODULE_INIT(A,L) \ +- (((ulong)(A) >= (L)->mod_init_module_ptr) && ((ulong)(A) < ((L)->mod_init_module_ptr+(L)->mod_init_size))) ++ /* For 6.4 module_memory */ ++ struct module_memory mem[MOD_MEM_NUM_TYPES]; ++ struct syment **symtable; ++ struct syment **symend; ++ struct syment *ext_symtable[MOD_MEM_NUM_TYPES]; ++ struct syment *ext_symend[MOD_MEM_NUM_TYPES]; ++ struct syment *load_symtable[MOD_MEM_NUM_TYPES]; ++ struct syment *load_symend[MOD_MEM_NUM_TYPES]; ++}; + ++#define IN_MODULE(A,L) (in_module_range(A, L, MOD_TEXT, MOD_RO_AFTER_INIT) != MOD_INVALID) ++#define IN_MODULE_INIT(A,L) (in_module_range(A, L, MOD_INIT_TEXT, MOD_INIT_RODATA) != MOD_INVALID) ++#define IN_MODULE_TEXT(A,L) (in_module_range(A, L, MOD_TEXT, MOD_TEXT) == MOD_TEXT || \ ++ in_module_range(A, L, MOD_INIT_TEXT, MOD_INIT_TEXT) == MOD_INIT_TEXT) + #define IN_MODULE_PERCPU(A,L) \ + (((ulong)(A) >= (L)->mod_percpu) && ((ulong)(A) < ((L)->mod_percpu+(L)->mod_percpu_size))) + + #define MODULE_PERCPU_SYMS_LOADED(L) ((L)->mod_percpu && (L)->mod_percpu_size) + ++#define for_each_mod_mem_type(type) \ ++ for ((type) = MOD_TEXT; (type) < MOD_MEM_NUM_TYPES; (type)++) ++ + #ifndef GDB_COMMON + + #define KVADDR (0x1) +@@ -5366,6 +5399,7 @@ void dump_struct_member(char *, ulong, u + void dump_union(char *, ulong, unsigned); + void store_module_symbols_v1(ulong, int); + void store_module_symbols_v2(ulong, int); ++void store_module_symbols_6_4(ulong, int); + int is_datatype_command(void); + int is_typedef(char *); + int arg_to_datatype(char *, struct datatype_member *, ulong); +--- crash-8.0.2.orig/gdb-10.2.patch ++++ crash-8.0.2/gdb-10.2.patch +@@ -1737,3 +1737,29 @@ exit 0 + struct field *nextfield; + short nfields; + struct type *typedef_type, *target_type; ++ ++--- gdb-10.2/gdb/symtab.c.orig +++++ gdb-10.2/gdb/symtab.c ++@@ -7476,7 +7476,7 @@ gdb_add_symbol_file(struct gnu_request * ++ int i; ++ int allsect = 0; ++ char *secname; ++- char buf[80]; +++ char buf[96]; ++ ++ gdb_current_load_module = lm = (struct load_module *)req->addr; ++ ++@@ -7515,8 +7515,11 @@ gdb_add_symbol_file(struct gnu_request * ++ secname = lm->mod_section_data[i].name; ++ if ((lm->mod_section_data[i].flags & SEC_FOUND) && ++ !STREQ(secname, ".text")) { ++- sprintf(buf, " -s %s 0x%lx", secname, ++- lm->mod_section_data[i].offset + lm->mod_base); +++ if (lm->mod_section_data[i].addr) +++ sprintf(buf, " -s %s 0x%lx", secname, lm->mod_section_data[i].addr); +++ else +++ sprintf(buf, " -s %s 0x%lx", secname, +++ lm->mod_section_data[i].offset + lm->mod_base); ++ strcat(req->buf, buf); ++ } ++ } +--- crash-8.0.2.orig/kernel.c ++++ crash-8.0.2/kernel.c +@@ -3565,7 +3565,21 @@ module_init(void) + MEMBER_OFFSET_INIT(module_num_gpl_syms, "module", + "num_gpl_syms"); + +- if (MEMBER_EXISTS("module", "module_core")) { ++ if (MEMBER_EXISTS("module", "mem")) { /* 6.4 and later */ ++ kt->flags2 |= KMOD_MEMORY; /* MODULE_MEMORY() can be used. */ ++ ++ MEMBER_OFFSET_INIT(module_mem, "module", "mem"); ++ MEMBER_OFFSET_INIT(module_memory_base, "module_memory", "base"); ++ MEMBER_OFFSET_INIT(module_memory_size, "module_memory", "size"); ++ STRUCT_SIZE_INIT(module_memory, "module_memory"); ++ ++ if (CRASHDEBUG(1)) ++ error(INFO, "struct module_memory detected.\n"); ++ ++ if (get_array_length("module.mem", NULL, 0) != MOD_MEM_NUM_TYPES) ++ error(WARNING, "module memory types have changed!\n"); ++ ++ } else if (MEMBER_EXISTS("module", "module_core")) { + MEMBER_OFFSET_INIT(module_core_size, "module", + "core_size"); + MEMBER_OFFSET_INIT(module_init_size, "module", +@@ -3751,6 +3765,8 @@ module_init(void) + total += nsyms; + total += 2; /* store the module's start/ending addresses */ + total += 2; /* and the init start/ending addresses */ ++ if (MODULE_MEMORY()) /* 7 regions at most -> 14, so needs +10 */ ++ total += 10; + + /* + * If the module has kallsyms, set up to grab them as well. +@@ -3778,7 +3794,11 @@ module_init(void) + case KALLSYMS_V2: + if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) { + numksyms = UINT(modbuf + OFFSET(module_num_symtab)); +- size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx)); ++ if (MODULE_MEMORY()) ++ /* check mem[MOD_TEXT].size only */ ++ size = UINT(modbuf + OFFSET(module_mem) + OFFSET(module_memory_size)); ++ else ++ size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx)); + } else { + numksyms = ULONG(modbuf + OFFSET(module_num_symtab)); + size = ULONG(modbuf + MODULE_OFFSET2(module_core_size, rx)); +@@ -3816,7 +3836,10 @@ module_init(void) + store_module_symbols_v1(total, kt->mods_installed); + break; + case KMOD_V2: +- store_module_symbols_v2(total, kt->mods_installed); ++ if (MODULE_MEMORY()) ++ store_module_symbols_6_4(total, kt->mods_installed); ++ else ++ store_module_symbols_v2(total, kt->mods_installed); + break; + } + +@@ -3830,7 +3853,7 @@ module_init(void) + static int + verify_modules(void) + { +- int i; ++ int i, t; + int found, irregularities; + ulong mod, mod_next, mod_base; + long mod_size; +@@ -3887,8 +3910,13 @@ verify_modules(void) + mod_base = mod; + break; + case KMOD_V2: +- mod_base = ULONG(modbuf + +- MODULE_OFFSET2(module_module_core, rx)); ++ if (MODULE_MEMORY()) ++ /* mem[MOD_TEXT].base */ ++ mod_base = ULONG(modbuf + OFFSET(module_mem) + ++ OFFSET(module_memory_base)); ++ else ++ mod_base = ULONG(modbuf + ++ MODULE_OFFSET2(module_module_core, rx)); + break; + } + +@@ -3910,7 +3938,17 @@ verify_modules(void) + case KMOD_V2: + module_name = modbuf + + OFFSET(module_name); +- if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) ++ if (MODULE_MEMORY()) { ++ mod_size = 0; ++ for_each_mod_mem_type(t) { ++ if (t == MOD_INIT_TEXT) ++ break; ++ ++ mod_size += UINT(modbuf + OFFSET(module_mem) + ++ SIZE(module_memory) * t + ++ OFFSET(module_memory_size)); ++ } ++ } else if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) + mod_size = UINT(modbuf + + MODULE_OFFSET2(module_core_size, rx)); + else +@@ -4530,7 +4568,7 @@ do_module_cmd(ulong flag, char *modref, + "MODULE"), + mkstring(buf2, maxnamelen, LJUST, "NAME"), + mkstring(buf4, VADDR_PRLEN, CENTER|LJUST, +- "BASE"), ++ MODULE_MEMORY() ? "TEXT_BASE" : "BASE"), + mkstring(buf3, maxsizelen, RJUST, "SIZE")); + } + +@@ -6138,6 +6176,8 @@ dump_kernel_table(int verbose) + fprintf(fp, "%sIRQ_DESC_TREE_XARRAY", others++ ? "|" : ""); + if (kt->flags2 & KMOD_PAX) + fprintf(fp, "%sKMOD_PAX", others++ ? "|" : ""); ++ if (kt->flags2 & KMOD_MEMORY) ++ fprintf(fp, "%sKMOD_MEMORY", others++ ? "|" : ""); + fprintf(fp, ")\n"); + + fprintf(fp, " stext: %lx\n", kt->stext); +--- crash-8.0.2.orig/memory.c ++++ crash-8.0.2/memory.c +@@ -15554,10 +15554,44 @@ in_vmlist_segment(ulong vaddr) + static int + next_module_vaddr(ulong vaddr, ulong *nextvaddr) + { +- int i; +- ulong start, end; ++ int i, t; ++ ulong start, end, min = (ulong)-1; + struct load_module *lm; + ++ if (!MODULE_MEMORY()) ++ goto old_module; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->mem[t].size) ++ continue; ++ ++ start = lm->mem[t].base; ++ end = start + lm->mem[t].size; ++ ++ if (vaddr >= end) ++ continue; ++ ++ if (vaddr < start) { ++ if (start < min) /* replace candidate */ ++ min = start; ++ continue; ++ } ++ ++ *nextvaddr = vaddr; ++ return TRUE; ++ } ++ } ++ ++ if (min != (ulong)-1) { ++ *nextvaddr = min; ++ return TRUE; ++ } ++ return FALSE; ++ ++old_module: + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + start = lm->mod_base; +--- crash-8.0.2.orig/symbols.c ++++ crash-8.0.2/symbols.c +@@ -48,8 +48,8 @@ static int load_module_index(struct syme + static void section_header_info(bfd *, asection *, void *); + static void store_section_data(struct load_module *, bfd *, asection *); + static void calculate_load_order_v1(struct load_module *, bfd *); +-static void calculate_load_order_v2(struct load_module *, bfd *, int, +- void *, long, unsigned int); ++static void calculate_load_order_v2(struct load_module *, bfd *, int, void *, long, unsigned int); ++static void calculate_load_order_6_4(struct load_module *, bfd *, int, void *, long, unsigned int); + static void check_insmod_builtin(struct load_module *, int, ulong *); + static int is_insmod_builtin(struct load_module *, struct syment *); + struct load_module; +@@ -104,6 +104,42 @@ static unsigned char is_right_brace(cons + static struct struct_elem *find_node(struct struct_elem *, char *); + static void dump_node(struct struct_elem *, char *, unsigned char, unsigned char); + ++static int module_mem_type(ulong, struct load_module *); ++static ulong module_mem_end(ulong, struct load_module *); ++static int in_module_range(ulong, struct load_module *, int, int); ++static struct syment *value_search_module_6_4(ulong, ulong *); ++static struct syment *next_symbol_by_symname(char *); ++static struct syment *prev_symbol_by_symname(char *); ++static struct syment *next_module_symbol_by_value(ulong); ++static struct syment *prev_module_symbol_by_value(ulong); ++static struct syment *next_module_symbol_by_syment(struct syment *); ++static struct syment *prev_module_symbol_by_syment(struct syment *); ++ ++struct module_tag { ++ char *start; ++ char *end; ++ char *start_str; ++ char *end_str; ++}; ++ ++#define MODULE_TAG(type, suffix) ("_MODULE_" #type "_" #suffix "_") ++#define MODULE_STR(type, suffix) ( "MODULE " #type " " #suffix) ++#define MODULE_TAGS(type) { \ ++ .start = MODULE_TAG(type, START), \ ++ .end = MODULE_TAG(type, END), \ ++ .start_str = MODULE_STR(type, START), \ ++ .end_str = MODULE_STR(type, END) \ ++} ++ ++static const struct module_tag module_tag[] = { ++ MODULE_TAGS(TEXT), ++ MODULE_TAGS(DATA), ++ MODULE_TAGS(RODATA), ++ MODULE_TAGS(RO_AFTER_INIT), ++ MODULE_TAGS(INIT_TEXT), ++ MODULE_TAGS(INIT_DATA), ++ MODULE_TAGS(INIT_RODATA), ++}; + + /* + * structure/union printing stuff +@@ -1268,10 +1304,7 @@ symname_hash_search(struct syment *table + * Output for sym -[lL] command. + */ + +-#define MODULE_PSEUDO_SYMBOL(sp) \ +- ((STRNEQ((sp)->name, "_MODULE_START_") || STRNEQ((sp)->name, "_MODULE_END_")) || \ +- (STRNEQ((sp)->name, "_MODULE_INIT_START_") || STRNEQ((sp)->name, "_MODULE_INIT_END_")) || \ +- (STRNEQ((sp)->name, "_MODULE_SECTION_"))) ++#define MODULE_PSEUDO_SYMBOL(sp) (STRNEQ((sp)->name, "_MODULE_")) + + #define MODULE_START(sp) (STRNEQ((sp)->name, "_MODULE_START_")) + #define MODULE_END(sp) (STRNEQ((sp)->name, "_MODULE_END_")) +@@ -1280,6 +1313,76 @@ symname_hash_search(struct syment *table + #define MODULE_SECTION_START(sp) (STRNEQ((sp)->name, "_MODULE_SECTION_START")) + #define MODULE_SECTION_END(sp) (STRNEQ((sp)->name, "_MODULE_SECTION_END")) + ++#define MODULE_MEM_START(sp,t) (STRNEQ((sp)->name, module_tag[t].start)) ++#define MODULE_MEM_END(sp,t) (STRNEQ((sp)->name, module_tag[t].end)) ++ ++/* For 6.4 and later */ ++static void ++module_symbol_dump(char *module) ++{ ++ int i, t; ++ struct syment *sp, *sp_end; ++ struct load_module *lm; ++ const char *p1, *p2; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ ++ lm = &st->load_modules[i]; ++ if (module && !STREQ(module, lm->mod_name)) ++ continue; ++ ++ if (received_SIGINT() || output_closed()) ++ return; ++ ++ /* ++ * module percpu symbols are within the .data..percpu section, ++ * not in any module memory regions. ++ */ ++ if (MODULE_PERCPU_SYMS_LOADED(lm)) { ++ p1 = "MODULE PERCPU START"; ++ p2 = lm->mod_name; ++ fprintf(fp, "%lx %s: %s\n", lm->mod_percpu, p1, p2); ++ ++ dump_percpu_symbols(lm); ++ ++ p1 = "MODULE PERCPU END"; ++ fprintf(fp, "%lx %s: %s\n", lm->mod_percpu + lm->mod_percpu_size, p1, p2); ++ } ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ ++ sp = lm->symtable[t]; ++ sp_end = lm->symend[t]; ++ ++ for ( ; sp <= sp_end; sp++) { ++ if (MODULE_PSEUDO_SYMBOL(sp)) { ++ if (MODULE_MEM_START(sp, t)) { ++ p1 = module_tag[t].start_str; ++ p2 = sp->name + strlen(module_tag[t].start); ++ } else if (MODULE_MEM_END(sp, t)) { ++ p1 = module_tag[t].end_str; ++ p2 = sp->name + strlen(module_tag[t].end); ++ } else if (MODULE_SECTION_START(sp)) { ++ p1 = sp->name + strlen("_MODULE_SECTION_START "); ++ p2 = "section start"; ++ } else if (MODULE_SECTION_END(sp)) { ++ p1 = sp->name + strlen("_MODULE_SECTION_END "); ++ p2 = "section end"; ++ } else { ++ p1 = "unknown tag"; ++ p2 = sp->name; ++ } ++ ++ fprintf(fp, "%lx %s: %s\n", sp->value, p1, p2); ++ } else ++ show_symbol(sp, 0, SHOW_RADIX()); ++ } ++ } ++ } ++} ++ + static void + symbol_dump(ulong flags, char *module) + { +@@ -1302,6 +1405,11 @@ symbol_dump(ulong flags, char *module) + if (!(flags & MODULE_SYMS)) + return; + ++ if (MODULE_MEMORY()) { ++ module_symbol_dump(module); ++ return; ++ } ++ + for (i = 0; i < st->mods_installed; i++) { + + lm = &st->load_modules[i]; +@@ -1389,8 +1497,14 @@ dump_percpu_symbols(struct load_module * + struct syment *sp, *sp_end; + + if (MODULE_PERCPU_SYMS_LOADED(lm)) { +- sp = lm->mod_symtable; +- sp_end = lm->mod_symend; ++ if (MODULE_MEMORY()) { ++ /* The lm should have mod_load_symtable. */ ++ sp = lm->mod_load_symtable; ++ sp_end = lm->mod_load_symend; ++ } else { ++ sp = lm->mod_symtable; ++ sp_end = lm->mod_symend; ++ } + for ( ; sp <= sp_end; sp++) { + if (IN_MODULE_PERCPU(sp->value, lm)) + show_symbol(sp, 0, SHOW_RADIX()); +@@ -1425,8 +1539,13 @@ check_for_dups(struct load_module *lm) + { + struct syment *sp, *sp_end; + +- sp = lm->mod_symtable; +- sp_end = lm->mod_symend; ++ if (MODULE_MEMORY()) { ++ sp = lm->mod_load_symtable; ++ sp_end = lm->mod_load_symend; ++ } else { ++ sp = lm->mod_symtable; ++ sp_end = lm->mod_symend; ++ } + + for ( ; sp <= sp_end; sp++) { + if (symbol_name_count(sp->name) > 1) +@@ -1788,6 +1907,362 @@ modsym_value(ulong syms, union kernel_sy + return 0; + } + ++/* ++ * Linux 6.4 introduced module.mem memory layout ++ */ ++void ++store_module_symbols_6_4(ulong total, int mods_installed) ++{ ++ int i, m, t; ++ ulong mod, mod_next; ++ char *mod_name; ++ uint nsyms, ngplsyms; ++ ulong syms, gpl_syms; ++ ulong nksyms; ++ long strbuflen; ++ ulong size; ++ int mcnt, lm_mcnt; ++ union kernel_symbol *modsym; ++ size_t kernel_symbol_size; ++ struct load_module *lm; ++ char buf1[BUFSIZE]; ++ char buf2[BUFSIZE]; ++ char *strbuf = NULL, *modbuf, *modsymbuf; ++ struct syment *sp; ++ ulong first, last; ++ ++ st->mods_installed = mods_installed; ++ ++ if (!st->mods_installed) { ++ st->flags &= ~MODULE_SYMS; ++ return; ++ } ++ ++ /* ++ * If we've been here before, free up everything and start over. ++ */ ++ if (st->flags & MODULE_SYMS) ++ error(FATAL, "re-initialization of module symbols not implemented yet!\n"); ++ ++ kernel_symbol_size = kernel_symbol_type_init(); ++ ++ if ((st->ext_module_symtable = (struct syment *) ++ calloc(total, sizeof(struct syment))) == NULL) ++ error(FATAL, "module syment space malloc (%ld symbols): %s\n", ++ total, strerror(errno)); ++ ++ if (!namespace_ctl(NAMESPACE_INIT, &st->ext_module_namespace, ++ (void *)total, NULL)) ++ error(FATAL, "module namespace malloc: %s\n", strerror(errno)); ++ ++ if ((st->load_modules = (struct load_module *)calloc ++ (st->mods_installed, sizeof(struct load_module))) == NULL) ++ error(FATAL, "load_module array malloc: %s\n", strerror(errno)); ++ ++ modbuf = GETBUF(SIZE(module)); ++ modsymbuf = NULL; ++ m = mcnt = mod_next = 0; ++ ++ for (mod = kt->module_list; mod != kt->kernel_module; mod = mod_next) { ++ ++ readmem(mod, KVADDR, modbuf, SIZE(module), ++ "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)); ++ ++ nksyms = UINT(modbuf + OFFSET(module_num_symtab)); ++ ++ mod_name = modbuf + OFFSET(module_name); ++ ++ lm = &st->load_modules[m++]; ++ BZERO(lm, sizeof(struct load_module)); ++ ++ size = 0; ++ for_each_mod_mem_type(t) { ++ lm->mem[t].base = ULONG(modbuf + OFFSET(module_mem) + ++ SIZE(module_memory) * t + OFFSET(module_memory_base)); ++ lm->mem[t].size = UINT(modbuf + OFFSET(module_mem) + ++ SIZE(module_memory) * t + OFFSET(module_memory_size)); ++ if (t < MOD_INIT_TEXT) ++ size += lm->mem[t].size; ++ } ++ lm->mod_base = lm->mem[MOD_TEXT].base; ++ /* module core size, init not included */ ++ lm->mod_size = size; ++ lm->module_struct = mod; ++ ++ if (strlen(mod_name) < MAX_MOD_NAME) ++ strcpy(lm->mod_name, mod_name); ++ else { ++ error(INFO, "module name greater than MAX_MOD_NAME: %s\n", mod_name); ++ strncpy(lm->mod_name, mod_name, MAX_MOD_NAME-1); ++ } ++ if (CRASHDEBUG(3)) ++ fprintf(fp, "%lx (%lx): %s syms: %d gplsyms: %d ksyms: %ld\n", ++ mod, lm->mod_base, lm->mod_name, nsyms, ngplsyms, nksyms); ++ ++ lm->mod_flags = MOD_EXT_SYMS; ++ lm->mod_ext_symcnt = mcnt; ++ lm->mod_text_start = lm->mod_base; ++ lm->mod_init_module_ptr = lm->mem[MOD_INIT_TEXT].base; ++ lm->mod_init_size = lm->mem[MOD_INIT_TEXT].size; ++ lm->mod_init_text_size = lm->mem[MOD_INIT_TEXT].size; ++ ++ if (VALID_MEMBER(module_percpu)) ++ lm->mod_percpu = ULONG(modbuf + OFFSET(module_percpu)); ++ ++ lm_mcnt = mcnt; ++ for_each_mod_mem_type(t) { ++ if (!lm->mem[t].size) ++ continue; ++ ++ st->ext_module_symtable[mcnt].value = lm->mem[t].base; ++ st->ext_module_symtable[mcnt].type = 'm'; ++ st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; ++ sprintf(buf2, "%s%s", module_tag[t].start, mod_name); ++ namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, ++ &st->ext_module_symtable[mcnt], buf2); ++ lm_mcnt = mcnt; ++ mcnt++; ++ ++ if (t >= MOD_INIT_TEXT) ++ lm->mod_flags |= MOD_INIT; ++ } ++ ++ if (nsyms && !IN_MODULE(syms, lm)) { ++ error(WARNING, ++ "[%s] module.syms outside of module " "address space (%lx)\n\n", ++ lm->mod_name, syms); ++ nsyms = 0; ++ } ++ ++ if (nsyms) { ++ modsymbuf = GETBUF(kernel_symbol_size*nsyms); ++ readmem((ulong)syms, KVADDR, modsymbuf, ++ nsyms * kernel_symbol_size, ++ "module symbols", FAULT_ON_ERROR); ++ } ++ ++ for (i = first = last = 0; i < nsyms; i++) { ++ modsym = (union kernel_symbol *) ++ (modsymbuf + (i * kernel_symbol_size)); ++ if (!first ++ || first > modsym_name(syms, modsym, i)) ++ first = modsym_name(syms, modsym, i); ++ if (modsym_name(syms, modsym, i) > last) ++ last = modsym_name(syms, modsym, i); ++ } ++ ++ if (last > first) { ++ /* The buffer should not go over the block. */ ++ ulong end = module_mem_end(first, lm); ++ ++ strbuflen = (last-first) + BUFSIZE; ++ if ((first + strbuflen) >= end) { ++ strbuflen = end - first; ++ ++ } ++ strbuf = GETBUF(strbuflen); ++ ++ if (!readmem(first, KVADDR, strbuf, strbuflen, ++ "module symbol strings", RETURN_ON_ERROR)) { ++ FREEBUF(strbuf); ++ strbuf = NULL; ++ } ++ } ++ ++ ++ for (i = 0; i < nsyms; i++) { ++ modsym = (union kernel_symbol *)(modsymbuf + (i * kernel_symbol_size)); ++ ++ BZERO(buf1, BUFSIZE); ++ ++ if (strbuf) ++ strcpy(buf1, &strbuf[modsym_name(syms, modsym, i) - first]); ++ else ++ read_string(modsym_name(syms, modsym, i), buf1, BUFSIZE-1); ++ ++ if (strlen(buf1)) { ++ st->ext_module_symtable[mcnt].value = ++ modsym_value(syms, modsym, i); ++ st->ext_module_symtable[mcnt].type = '?'; ++ st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; ++ strip_module_symbol_end(buf1); ++ strip_symbol_end(buf1, NULL); ++ namespace_ctl(NAMESPACE_INSTALL, ++ &st->ext_module_namespace, ++ &st->ext_module_symtable[mcnt], buf1); ++ ++ mcnt++; ++ } ++ } ++ ++ if (modsymbuf) { ++ FREEBUF(modsymbuf); ++ modsymbuf = NULL; ++ } ++ ++ if (strbuf) ++ FREEBUF(strbuf); ++ ++ if (ngplsyms) { ++ modsymbuf = GETBUF(kernel_symbol_size * ngplsyms); ++ readmem((ulong)gpl_syms, KVADDR, modsymbuf, ++ ngplsyms * kernel_symbol_size, ++ "module gpl symbols", FAULT_ON_ERROR); ++ } ++ ++ for (i = first = last = 0; i < ngplsyms; i++) { ++ modsym = (union kernel_symbol *) ++ (modsymbuf + (i * kernel_symbol_size)); ++ if (!first ++ || first > modsym_name(gpl_syms, modsym, i)) ++ first = modsym_name(gpl_syms, modsym, i); ++ if (modsym_name(gpl_syms, modsym, i) > last) ++ last = modsym_name(gpl_syms, modsym, i); ++ } ++ ++ if (last > first) { ++ ulong end = module_mem_end(first, lm); ++ ++ strbuflen = (last-first) + BUFSIZE; ++ if ((first + strbuflen) >= end) { ++ strbuflen = end - first; ++ ++ } ++ strbuf = GETBUF(strbuflen); ++ ++ if (!readmem(first, KVADDR, strbuf, strbuflen, ++ "module gpl symbol strings", RETURN_ON_ERROR)) { ++ FREEBUF(strbuf); ++ strbuf = NULL; ++ } ++ } else ++ strbuf = NULL; ++ ++ for (i = 0; i < ngplsyms; i++) { ++ modsym = (union kernel_symbol *) (modsymbuf + (i * kernel_symbol_size)); ++ ++ BZERO(buf1, BUFSIZE); ++ ++ if (strbuf) ++ strcpy(buf1, &strbuf[modsym_name(gpl_syms, modsym, i) - first]); ++ else ++ read_string(modsym_name(gpl_syms, modsym, i), buf1, BUFSIZE-1); ++ ++ if (strlen(buf1)) { ++ st->ext_module_symtable[mcnt].value = ++ modsym_value(gpl_syms, modsym, i); ++ st->ext_module_symtable[mcnt].type = '?'; ++ st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; ++ strip_module_symbol_end(buf1); ++ strip_symbol_end(buf1, NULL); ++ namespace_ctl(NAMESPACE_INSTALL, ++ &st->ext_module_namespace, ++ &st->ext_module_symtable[mcnt], buf1); ++ ++ mcnt++; ++ } ++ } ++ ++ if (modsymbuf) { ++ FREEBUF(modsymbuf); ++ modsymbuf = NULL; ++ } ++ ++ if (strbuf) ++ FREEBUF(strbuf); ++ ++ /* ++ * If the module was compiled with kallsyms, add them in. ++ */ ++ switch (kt->flags & (KALLSYMS_V1|KALLSYMS_V2)) ++ { ++ case KALLSYMS_V1: /* impossible, I hope... */ ++ mcnt += store_module_kallsyms_v1(lm, lm_mcnt, mcnt, modbuf); ++ break; ++ case KALLSYMS_V2: ++ mcnt += store_module_kallsyms_v2(lm, lm_mcnt, mcnt, modbuf); ++ break; ++ } ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->mem[t].size) ++ continue; ++ ++ st->ext_module_symtable[mcnt].value = lm->mem[t].base + lm->mem[t].size; ++ st->ext_module_symtable[mcnt].type = 'm'; ++ st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; ++ sprintf(buf2, "%s%s", module_tag[t].end, mod_name); ++ namespace_ctl(NAMESPACE_INSTALL, ++ &st->ext_module_namespace, ++ &st->ext_module_symtable[mcnt], buf2); ++ mcnt++; ++ } ++ ++ lm->mod_ext_symcnt = mcnt - lm->mod_ext_symcnt; ++ ++ NEXT_MODULE(mod_next, modbuf); ++ } ++ ++ FREEBUF(modbuf); ++ ++ st->ext_module_symcnt = mcnt; ++ st->ext_module_symend = &st->ext_module_symtable[mcnt]; ++ ++ namespace_ctl(NAMESPACE_COMPLETE, &st->ext_module_namespace, ++ st->ext_module_symtable, st->ext_module_symend); ++ ++ qsort(st->ext_module_symtable, mcnt, sizeof(struct syment), ++ compare_syms); ++ ++ /* sort by text base address */ ++ qsort(st->load_modules, m, sizeof(struct load_module), compare_mods); ++ ++ for (m = 0; m < st->mods_installed; m++) { ++ lm = &st->load_modules[m]; ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->mem[t].size) ++ continue; ++ ++ sprintf(buf1, "%s%s", module_tag[t].start, lm->mod_name); ++ sprintf(buf2, "%s%s", module_tag[t].end, lm->mod_name); ++ ++ for (sp = st->ext_module_symtable; sp < st->ext_module_symend; sp++) { ++ if (STREQ(sp->name, buf1)) { ++ lm->ext_symtable[t] = sp; ++ break; ++ } ++ } ++ for ( ; sp < st->ext_module_symend; sp++) { ++ if (STREQ(sp->name, buf2)) { ++ lm->ext_symend[t] = sp; ++ break; ++ } ++ } ++ ++ if (lm->ext_symtable[t] && lm->ext_symend[t]) ++ mod_symtable_hash_install_range(lm->ext_symtable[t], lm->ext_symend[t]); ++ } ++ lm->symtable = lm->ext_symtable; ++ lm->symend = lm->ext_symend; ++ } ++ ++ st->flags |= MODULE_SYMS; ++ ++ if (CRASHDEBUG(2)) { ++ for (sp = st->ext_module_symtable; sp < st->ext_module_symend; sp++) ++ fprintf(fp, "%16lx %s\n", sp->value, sp->name); ++ } ++ ++ if (mcnt > total) ++ error(FATAL, "store_module_symbols_6_4: total: %ld mcnt: %d\n", total, mcnt); ++} ++ + void + store_module_symbols_v2(ulong total, int mods_installed) + { +@@ -2384,6 +2859,7 @@ store_module_kallsyms_v2(struct load_mod + int mcnt; + int mcnt_idx; + char *module_buf_init = NULL; ++ ulong base, base_init, size, size_init; + + if (!(kt->flags & KALLSYMS_V2)) + return 0; +@@ -2394,9 +2870,22 @@ store_module_kallsyms_v2(struct load_mod + ns = &st->ext_module_namespace; + ec = &elf_common; + +- module_buf = GETBUF(lm->mod_size); ++ /* kallsyms data looks to be in MOD_DATA region. */ ++ if (MODULE_MEMORY()) { ++ base = lm->mem[MOD_DATA].base; ++ size = lm->mem[MOD_DATA].size; ++ base_init = lm->mem[MOD_INIT_DATA].base; ++ size_init = lm->mem[MOD_INIT_DATA].size; ++ } else { ++ base = lm->mod_base; ++ size = lm->mod_size; ++ base_init = lm->mod_init_module_ptr; ++ size_init = lm->mod_init_size; ++ } ++ ++ module_buf = GETBUF(size); + +- if (!readmem(lm->mod_base, KVADDR, module_buf, lm->mod_size, ++ if (!readmem(base, KVADDR, module_buf, size, + "module (kallsyms)", RETURN_ON_ERROR|QUIET)) { + error(WARNING,"cannot access module kallsyms\n"); + FREEBUF(module_buf); +@@ -2404,10 +2893,10 @@ store_module_kallsyms_v2(struct load_mod + } + + if (lm->mod_init_size > 0) { +- module_buf_init = GETBUF(lm->mod_init_size); ++ module_buf_init = GETBUF(size_init); + +- if (!readmem(lm->mod_init_module_ptr, KVADDR, module_buf_init, lm->mod_init_size, +- "module init (kallsyms)", RETURN_ON_ERROR|QUIET)) { ++ if (!readmem(base_init, KVADDR, module_buf_init, size_init, ++ "module init (kallsyms)", RETURN_ON_ERROR|QUIET)) { + error(WARNING,"cannot access module init kallsyms\n"); + FREEBUF(module_buf_init); + } +@@ -2429,9 +2918,9 @@ store_module_kallsyms_v2(struct load_mod + return 0; + } + if (IN_MODULE(ksymtab, lm)) +- locsymtab = module_buf + (ksymtab - lm->mod_base); ++ locsymtab = module_buf + (ksymtab - base); + else +- locsymtab = module_buf_init + (ksymtab - lm->mod_init_module_ptr); ++ locsymtab = module_buf_init + (ksymtab - base_init); + + kstrtab = ULONG(modbuf + OFFSET(module_strtab)); + if (!IN_MODULE(kstrtab, lm) && !IN_MODULE_INIT(kstrtab, lm)) { +@@ -2444,9 +2933,9 @@ store_module_kallsyms_v2(struct load_mod + return 0; + } + if (IN_MODULE(kstrtab, lm)) +- locstrtab = module_buf + (kstrtab - lm->mod_base); ++ locstrtab = module_buf + (kstrtab - base); + else +- locstrtab = module_buf_init + (kstrtab - lm->mod_init_module_ptr); ++ locstrtab = module_buf_init + (kstrtab - base_init); + + for (i = 1; i < nksyms; i++) { /* ELF starts real symbols at 1 */ + switch (BITS()) +@@ -2461,11 +2950,8 @@ store_module_kallsyms_v2(struct load_mod + break; + } + +- if (((ec->st_value < lm->mod_base) || +- (ec->st_value > (lm->mod_base + lm->mod_size))) && +- ((ec->st_value < lm->mod_init_module_ptr) || +- (ec->st_value > (lm->mod_init_module_ptr + lm->mod_init_size)))) +- continue; ++ if (!IN_MODULE(ec->st_value, lm) && !IN_MODULE_INIT(ec->st_value, lm)) ++ continue; + + if (ec->st_shndx == SHN_UNDEF) + continue; +@@ -2572,7 +3058,7 @@ strip_module_symbol_end(char *buf) + ulong + lowest_module_address(void) + { +- int i; ++ int i, t; + struct load_module *lm; + ulong low, lowest; + +@@ -2582,9 +3068,20 @@ lowest_module_address(void) + lowest = (ulong)(-1); + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; +- low = lm->mod_base; +- if (low < lowest) +- lowest = low; ++ if (MODULE_MEMORY()) ++ for_each_mod_mem_type(t) { ++ if (!lm->mem[t].size) ++ continue; ++ ++ low = lm->mem[t].base; ++ if (low < lowest) ++ lowest = low; ++ } ++ else { ++ low = lm->mod_base; ++ if (low < lowest) ++ lowest = low; ++ } + } + + return lowest; +@@ -2593,16 +3090,27 @@ lowest_module_address(void) + ulong + highest_module_address(void) + { +- int i; ++ int i, t; + struct load_module *lm; + ulong high, highest; + + highest = 0; + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; +- high = lm->mod_base + lm->mod_size; +- if (high > highest) +- highest = high; ++ if (MODULE_MEMORY()) { ++ for_each_mod_mem_type(t) { ++ if (!lm->mem[t].size) ++ continue; ++ ++ high = lm->mem[t].base + lm->mem[t].size; ++ if (high > highest) ++ highest = high; ++ } ++ } else { ++ high = lm->mod_base + lm->mod_size; ++ if (high > highest) ++ highest = high; ++ } + } + + return highest; +@@ -2853,7 +3361,8 @@ compare_syms(const void *v1, const void + return -1; + if (STRNEQ(s2->name, "__insmod")) + return 1; +- if (STRNEQ(s2->name, "_MODULE_START_")) ++ if (MODULE_MEM_START(s2, MOD_TEXT) || ++ STRNEQ(s2->name, "_MODULE_START_")) + return 1; + /* Get pseudo section name. */ + if (MODULE_SECTION_START(s1)) +@@ -2986,13 +3495,19 @@ is_kernel_text(ulong value) + if (!(lm->mod_section_data[s].flags & SEC_CODE)) + continue; + +- start = lm->mod_base + +- lm->mod_section_data[s].offset; ++ if (MODULE_MEMORY()) ++ start = lm->mod_section_data[s].addr; ++ else ++ start = lm->mod_base + lm->mod_section_data[s].offset; ++ + end = start + lm->mod_section_data[s].size; + + if ((value >= start) && (value < end)) + return TRUE; + } ++ } else if (MODULE_MEMORY()) { ++ if (IN_MODULE_TEXT(value, lm)) ++ return TRUE; + } else { + switch (kt->flags & (KMOD_V1|KMOD_V2)) + { +@@ -3531,22 +4046,42 @@ dump_symbol_table(void) + (ulong)lm->mod_section_data, + lm->mod_section_data ? "" : "(not allocated)"); + ++ if (MODULE_MEMORY()) { ++ int t; ++ for_each_mod_mem_type(t) { ++ fprintf(fp, " mem[%d]: %lx (%x)\n", ++ t, lm->mem[t].base, lm->mem[t].size); ++ } ++ fprintf(fp, " symtable: %lx\n", (ulong)lm->symtable); ++ fprintf(fp, " ext_symtable: %lx\n", (ulong)lm->ext_symtable); ++ for_each_mod_mem_type(t) { ++ fprintf(fp, " ext_symtable[%d]: %lx - %lx\n", ++ t, (ulong)lm->ext_symtable[t], (ulong)lm->ext_symend[t]); ++ } ++ fprintf(fp, " load_symtable: %lx\n", (ulong)lm->load_symtable); ++ for_each_mod_mem_type(t) { ++ fprintf(fp, " load_symtable[%d]: %lx - %lx\n", ++ t, (ulong)lm->load_symtable[t], (ulong)lm->load_symend[t]); ++ } ++ } + + for (s = 0; s < lm->mod_sections; s++) { + fprintf(fp, +- " %12s prio: %x flags: %05x offset: %-8lx size: %lx\n", ++ " %20s prio: %x flags: %08x %s: %-16lx size: %lx\n", + lm->mod_section_data[s].name, + lm->mod_section_data[s].priority, + lm->mod_section_data[s].flags, +- lm->mod_section_data[s].offset, ++ MODULE_MEMORY() ? "addr" : "offset", ++ MODULE_MEMORY() ? lm->mod_section_data[s].addr : ++ lm->mod_section_data[s].offset, + lm->mod_section_data[s].size); + } + + fprintf(fp, " loaded_objfile: %lx\n", (ulong)lm->loaded_objfile); + +- if (CRASHDEBUG(1)) { ++ if (CRASHDEBUG(1) && lm->mod_load_symtable) { + for (sp = lm->mod_load_symtable; +- sp < lm->mod_load_symend; sp++) { ++ sp <= lm->mod_load_symend; sp++) { + fprintf(fp, " %lx %s\n", + sp->value, sp->name); + } +@@ -4448,8 +4983,11 @@ get_section(ulong vaddr, char *buf) + if (module_symbol(vaddr, NULL, &lm, NULL, *gdb_output_radix)) { + if (lm->mod_flags & MOD_LOAD_SYMS) { + for (i = (lm->mod_sections-1); i >= 0; i--) { +- start = lm->mod_base + +- lm->mod_section_data[i].offset; ++ if (MODULE_MEMORY()) ++ start = lm->mod_section_data[i].addr; ++ else ++ start = lm->mod_base + ++ lm->mod_section_data[i].offset; + end = start + lm->mod_section_data[i].size; + + if ((vaddr >= start) && (vaddr < end)) { +@@ -4504,7 +5042,7 @@ get_build_directory(char *buf) + int + symbol_query(char *s, char *print_pad, struct syment **spp) + { +- int i; ++ int i, t; + struct syment *sp, *sp_end; + struct load_module *lm; + int cnt, search_init; +@@ -4524,6 +5062,60 @@ symbol_query(char *s, char *print_pad, s + } + } + ++ if (!MODULE_MEMORY()) ++ goto old_module; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ if (lm->mod_flags & MOD_LOAD_SYMS) { ++ sp = lm->mod_load_symtable; ++ sp_end = lm->mod_load_symend; ++ ++ for (; sp < sp_end; sp++) { ++ if (MODULE_PSEUDO_SYMBOL(sp)) ++ continue; ++ ++ if (strstr(sp->name, s)) { ++ if (print_pad) { ++ if (strlen(print_pad)) ++ fprintf(fp, "%s", print_pad); ++ show_symbol(sp, 0, SHOW_RADIX()|SHOW_MODULE); ++ } ++ if (spp) ++ *spp = sp; ++ cnt++; ++ } ++ } ++ } else { ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ ++ sp = lm->symtable[t]; ++ sp_end = lm->symend[t]; ++ ++ for (; sp < sp_end; sp++) { ++ if (MODULE_PSEUDO_SYMBOL(sp)) ++ continue; ++ ++ if (strstr(sp->name, s)) { ++ if (print_pad) { ++ if (strlen(print_pad)) ++ fprintf(fp, "%s", print_pad); ++ show_symbol(sp, 0, SHOW_RADIX()|SHOW_MODULE); ++ } ++ if (spp) ++ *spp = sp; ++ cnt++; ++ } ++ } ++ } ++ } ++ } ++ return cnt; ++ ++old_module: + search_init = FALSE; + + for (i = 0; i < st->mods_installed; i++) { +@@ -4629,7 +5221,7 @@ symbol_search(char *s) + int + symbol_name_count(char *s) + { +- int i; ++ int i, t; + struct syment *sp, *sp_end; + struct load_module *lm; + int count, pseudos, search_init; +@@ -4643,6 +5235,37 @@ symbol_name_count(char *s) + } + } + ++ if (!MODULE_MEMORY()) ++ goto old_module; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ if (lm->mod_flags & MOD_LOAD_SYMS) { ++ sp = lm->mod_load_symtable; ++ sp_end = lm->mod_load_symend; ++ ++ for (; sp < sp_end; sp++) { ++ if (STREQ(s, sp->name)) ++ count++; ++ } ++ } else { ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ ++ sp = lm->symtable[t]; ++ sp_end = lm->symend[t]; ++ for (; sp < sp_end; sp++) { ++ if (STREQ(s, sp->name)) ++ count++; ++ } ++ } ++ } ++ } ++ return count++; ++ ++old_module: + pseudos = (strstr(s, "_MODULE_START_") || strstr(s, "_MODULE_END_")); + search_init = FALSE; + +@@ -4692,7 +5315,7 @@ symbol_name_count(char *s) + struct syment * + symbol_search_next(char *s, struct syment *spstart) + { +- int i; ++ int i, t; + struct syment *sp, *sp_end; + struct load_module *lm; + int found_start; +@@ -4712,6 +5335,38 @@ symbol_search_next(char *s, struct symen + } + } + ++ if (!MODULE_MEMORY()) ++ goto old_module; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ ++ sp = lm->symtable[t]; ++ sp_end = lm->symend[t]; ++ ++ if (!found_start && (spstart < sp || spstart > sp_end)) ++ continue; ++ ++ for ( ; sp < sp_end; sp++) { ++ if (sp == spstart) { ++ found_start = TRUE; ++ continue; ++ } else if (!found_start) ++ continue; ++ ++ if (STREQ(s, sp->name)) ++ return sp; ++ } ++ } ++ } ++ ++ return NULL; ++ ++old_module: + pseudos = (strstr(s, "_MODULE_START_") || strstr(s, "_MODULE_END_")); + search_init = FALSE; + +@@ -4821,17 +5476,29 @@ module_symbol(ulong value, + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + +- if (IN_MODULE(value, lm)) { +- base = lm->mod_base; +- end = lm->mod_base + lm->mod_size; +- } else if (IN_MODULE_INIT(value, lm)) { +- base = lm->mod_init_module_ptr; +- end = lm->mod_init_module_ptr + lm->mod_init_size; +- } else if (IN_MODULE_PERCPU(value, lm)) { +- base = lm->mod_percpu; +- end = lm->mod_percpu + lm->mod_percpu_size; +- } else +- continue; ++ if (MODULE_MEMORY()) { ++ if (IN_MODULE(value, lm) || IN_MODULE_INIT(value, lm)) { ++ int type = module_mem_type(value, lm); ++ base = lm->mem[type].base; ++ end = base + lm->mem[type].size; ++ } else if (IN_MODULE_PERCPU(value, lm)) { ++ base = lm->mod_percpu; ++ end = lm->mod_percpu + lm->mod_percpu_size; ++ } else ++ continue; ++ } else { ++ if (IN_MODULE(value, lm)) { ++ base = lm->mod_base; ++ end = lm->mod_base + lm->mod_size; ++ } else if (IN_MODULE_INIT(value, lm)) { ++ base = lm->mod_init_module_ptr; ++ end = lm->mod_init_module_ptr + lm->mod_init_size; ++ } else if (IN_MODULE_PERCPU(value, lm)) { ++ base = lm->mod_percpu; ++ end = lm->mod_percpu + lm->mod_percpu_size; ++ } else ++ continue; ++ } + + if ((value >= base) && (value < end)) { + if (lmp) +@@ -4867,6 +5534,71 @@ module_symbol(ulong value, + return FALSE; + } + ++static struct syment * ++value_search_module_6_4(ulong value, ulong *offset) ++{ ++ int i, t; ++ struct syment *sp, *sp_end, *spnext, *splast; ++ struct load_module *lm; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ if (!IN_MODULE(value, lm) && !IN_MODULE_INIT(value, lm)) ++ continue; ++ ++ for_each_mod_mem_type(t) { ++ sp = lm->symtable[t]; ++ sp_end = lm->symend[t]; ++ ++ if (value < sp->value) ++ continue; ++ ++ splast = NULL; ++ for ( ; sp <= sp_end; sp++) { ++ if (machine_type("ARM64") && ++ IN_MODULE_PERCPU(sp->value, lm) && ++ !IN_MODULE_PERCPU(value, lm)) ++ continue; ++ ++ if (value == sp->value) { ++ if (MODULE_MEM_END(sp, t)) ++ break; ++ ++ if (MODULE_PSEUDO_SYMBOL(sp)) { ++ spnext = sp + 1; ++ if (MODULE_PSEUDO_SYMBOL(spnext)) ++ continue; ++ if (spnext->value == value) ++ sp = spnext; ++ } ++ if (sp->name[0] == '.') { ++ spnext = sp+1; ++ if (spnext->value == value) ++ sp = spnext; ++ } ++ if (offset) ++ *offset = 0; ++ return sp; ++ } ++ ++ if (sp->value > value) { ++ sp = splast ? splast : sp - 1; ++ if (offset) ++ *offset = value - sp->value; ++ return sp; ++ } ++ ++ if (!MODULE_PSEUDO_SYMBOL(sp)) { ++ splast = sp; ++ } ++ } ++ } ++ } ++ ++ return NULL; ++} ++ + struct syment * + value_search_module(ulong value, ulong *offset) + { +@@ -4875,6 +5607,9 @@ value_search_module(ulong value, ulong * + struct load_module *lm; + int search_init_sections, search_init; + ++ if (MODULE_MEMORY()) ++ return value_search_module_6_4(value, offset); ++ + search_init = FALSE; + search_init_sections = 0; + +@@ -5193,6 +5928,99 @@ closest_symbol_value(ulong value) + return(0); + } + ++/* Only for 6.4 and later */ ++static struct syment * ++next_symbol_by_symname(char *symbol) ++{ ++ struct syment *sp; ++ ++ if ((sp = symbol_search(symbol))) { ++ sp++; ++ if (MODULE_PSEUDO_SYMBOL(sp) && strstr(sp->name, "_END")) ++ return next_module_symbol_by_value(sp->value); ++ ++ return sp; ++ } ++ ++ return NULL; ++} ++ ++/* val_in should be a pseudo module end symbol. */ ++static struct syment * ++next_module_symbol_by_value(ulong val_in) ++{ ++ struct load_module *lm; ++ struct syment *sp, *sp_end; ++ ulong start, min; ++ int i, t; ++ ++retry: ++ sp = sp_end = NULL; ++ min = (ulong)-1; ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ /* Search for the next lowest symtable. */ ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ ++ start = lm->symtable[t]->value; ++ if (start > val_in && start < min) { ++ min = start; ++ sp = lm->symtable[t]; ++ sp_end = lm->symend[t]; ++ } ++ } ++ } ++ ++ if (!sp) ++ return NULL; ++ ++ for ( ; sp < sp_end; sp++) { ++ if (MODULE_PSEUDO_SYMBOL(sp)) ++ continue; ++ if (sp->value > val_in) ++ return sp; ++ } ++ ++ /* Found a table that has only pseudo symbols. */ ++ val_in = sp_end->value; ++ goto retry; ++} ++ ++/* Only for 6.4 and later */ ++static struct syment * ++next_module_symbol_by_syment(struct syment *sp_in) ++{ ++ struct load_module *lm; ++ struct syment *sp; ++ int i, t; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ ++ if (sp_in < lm->symtable[t] || sp_in > lm->symend[t]) ++ continue; ++ ++ if (sp_in == lm->symend[t]) ++ return next_module_symbol_by_value(sp_in->value); ++ ++ sp = sp_in + 1; ++ if (MODULE_PSEUDO_SYMBOL(sp)) ++ return next_module_symbol_by_value(sp->value); ++ ++ return sp; ++ } ++ } ++ ++ return NULL; ++} ++ + /* + * For a given symbol, return a pointer to the next (higher) symbol's syment. + * Either a symbol name or syment pointer may be passed as an argument. +@@ -5220,6 +6048,9 @@ next_symbol(char *symbol, struct syment + } + } + ++ if (MODULE_MEMORY()) ++ return next_module_symbol_by_syment(sp_in); ++ + search_init = FALSE; + + for (i = 0; i < st->mods_installed; i++) { +@@ -5263,6 +6094,8 @@ next_symbol(char *symbol, struct syment + return NULL; + } + ++ if (MODULE_MEMORY()) ++ return next_symbol_by_symname(symbol); + + /* + * Deal with a few special cases... +@@ -5302,6 +6135,106 @@ next_symbol(char *symbol, struct syment + return NULL; + } + ++/* Only for 6.4 and later */ ++static struct syment * ++prev_symbol_by_symname(char *symbol) ++{ ++ struct syment *sp; ++ ++ if ((sp = symbol_search(symbol))) { ++ if (sp == st->symtable) ++ return NULL; ++ ++ if (module_symbol(sp->value, NULL, NULL, NULL, 0)) { ++ if (MODULE_PSEUDO_SYMBOL(sp) && strstr(sp->name, "_START")) ++ return prev_module_symbol_by_value(sp->value); ++ else ++ sp--; ++ } else ++ sp--; ++ ++ return sp; ++ } ++ ++ return NULL; ++} ++ ++/* val_in should be a pseudo module start symbol. */ ++static struct syment * ++prev_module_symbol_by_value(ulong val_in) ++{ ++ struct load_module *lm; ++ struct syment *sp, *sp_end; ++ ulong end, max; ++ int i, t; ++ ++retry: ++ sp = sp_end = NULL; ++ max = 0; ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ /* Search for the previous highest table. */ ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ ++ end = lm->symend[t]->value; ++ if (end < val_in && end > max) { ++ max = end; ++ sp = lm->symtable[t]; ++ sp_end = lm->symend[t]; ++ } ++ } ++ } ++ ++ if (!sp) ++ return NULL; ++ ++ for ( ; sp_end > sp; sp_end--) { ++ if (MODULE_PSEUDO_SYMBOL(sp_end)) ++ continue; ++ if (sp_end->value < val_in) ++ return sp_end; ++ } ++ ++ /* Found a table that has only pseudo symbols. */ ++ val_in = sp->value; ++ goto retry; ++} ++ ++/* Only for 6.4 and later */ ++static struct syment * ++prev_module_symbol_by_syment(struct syment *sp_in) ++{ ++ struct load_module *lm; ++ struct syment *sp; ++ int i, t; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ ++ if (sp_in < lm->symtable[t] || sp_in > lm->symend[t]) ++ continue; ++ ++ if (sp_in == lm->symtable[t]) ++ return prev_module_symbol_by_value(sp_in->value); ++ ++ sp = sp_in - 1; ++ if (MODULE_PSEUDO_SYMBOL(sp)) ++ return prev_module_symbol_by_value(sp->value); ++ ++ return sp; ++ } ++ } ++ ++ return NULL; ++} ++ + /* + * For a given symbol, return a pointer to the previous (lower) symbol's syment. + * Either a symbol name or syment pointer may be passed as an argument. +@@ -5325,6 +6258,9 @@ prev_symbol(char *symbol, struct syment + sp_prev = sp; + } + ++ if (MODULE_MEMORY()) ++ return prev_module_symbol_by_syment(sp_in); ++ + search_init = FALSE; + + for (i = 0; i < st->mods_installed; i++) { +@@ -5368,6 +6304,9 @@ prev_symbol(char *symbol, struct syment + return NULL; + } + ++ if (MODULE_MEMORY()) ++ return prev_symbol_by_symname(symbol); ++ + if (strstr(symbol, " module)")) { + sprintf(buf, "_MODULE_START_"); + strcat(buf, &symbol[1]); +@@ -5590,7 +6529,7 @@ kernel_symbol_search(char *symbol) + int + get_syment_array(char *symbol, struct syment **sp_array, int max) + { +- int i, cnt; ++ int i, cnt, t; + struct syment *sp, *sp_end; + struct load_module *lm; + +@@ -5615,6 +6554,31 @@ get_syment_array(char *symbol, struct sy + } + } + ++ if (!MODULE_MEMORY()) ++ goto old_module; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ ++ sp = lm->symtable[t]; ++ sp_end = lm->symend[t]; ++ for (; sp < sp_end; sp++) { ++ if (STREQ(symbol, sp->name)) { ++ if (max && (cnt < max)) ++ sp_array[cnt] = sp; ++ cnt++; ++ } ++ } ++ } ++ } ++ ++ return cnt; ++ ++old_module: + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + sp = lm->mod_symtable; +@@ -9217,6 +10181,9 @@ dump_offset_table(char *spec, ulong make + OFFSET(module_strtab)); + fprintf(fp, " module_percpu: %ld\n", + OFFSET(module_percpu)); ++ fprintf(fp, " module_mem: %ld\n", OFFSET(module_mem)); ++ fprintf(fp, " module_memory_base: %ld\n", OFFSET(module_memory_base)); ++ fprintf(fp, " module_memory_size: %ld\n", OFFSET(module_memory_size)); + + fprintf(fp, " module_sect_attrs: %ld\n", + OFFSET(module_sect_attrs)); +@@ -10814,6 +11781,7 @@ dump_offset_table(char *spec, ulong make + SIZE(super_block)); + fprintf(fp, " irqdesc: %ld\n", SIZE(irqdesc)); + fprintf(fp, " module: %ld\n", SIZE(module)); ++ fprintf(fp, " module_memory: %ld\n", SIZE(module_memory)); + fprintf(fp, " module_sect_attr: %ld\n", SIZE(module_sect_attr)); + fprintf(fp, " list_head: %ld\n", SIZE(list_head)); + fprintf(fp, " hlist_head: %ld\n", SIZE(hlist_head)); +@@ -11425,6 +12393,13 @@ store_section_data(struct load_module *l + lm->mod_section_data[i].section = section; + lm->mod_section_data[i].priority = prio; + lm->mod_section_data[i].flags = section->flags & ~SEC_FOUND; ++ lm->mod_section_data[i].size = bfd_section_size(section); ++ lm->mod_section_data[i].offset = 0; ++ lm->mod_section_data[i].addr = 0; ++ if (strlen(name) < MAX_MOD_SEC_NAME) ++ strcpy(lm->mod_section_data[i].name, name); ++ else ++ strncpy(lm->mod_section_data[i].name, name, MAX_MOD_SEC_NAME-1); + /* + * The percpu section isn't included in kallsyms or module_core area. + */ +@@ -11432,13 +12407,8 @@ store_section_data(struct load_module *l + (STREQ(name,".data.percpu") || STREQ(name, ".data..percpu"))) { + lm->mod_percpu_size = bfd_section_size(section); + lm->mod_section_data[i].flags |= SEC_FOUND; ++ lm->mod_section_data[i].addr = lm->mod_percpu; + } +- lm->mod_section_data[i].size = bfd_section_size(section); +- lm->mod_section_data[i].offset = 0; +- if (strlen(name) < MAX_MOD_SEC_NAME) +- strcpy(lm->mod_section_data[i].name, name); +- else +- strncpy(lm->mod_section_data[i].name, name, MAX_MOD_SEC_NAME-1); + lm->mod_sections += 1; + } + +@@ -11680,6 +12650,124 @@ calculate_load_order_v2(struct load_modu + } + } + ++/* Linux 6.4 and later */ ++static void ++calculate_load_order_6_4(struct load_module *lm, bfd *bfd, int dynamic, ++ void *minisyms, long symcount, unsigned int size) ++{ ++ struct syment *s1, *s2; ++ ulong sec_start; ++ bfd_byte *from, *fromend; ++ asymbol *store; ++ asymbol *sym; ++ symbol_info syminfo; ++ char *secname; ++ int i, t; ++ ++ if ((store = bfd_make_empty_symbol(bfd)) == NULL) ++ error(FATAL, "bfd_make_empty_symbol() failed\n"); ++ ++ for_each_mod_mem_type(t) { ++ s1 = lm->symtable[t]; ++ s2 = lm->symend[t]; ++ while (s1 < s2) { ++ ++ if (MODULE_PSEUDO_SYMBOL(s1)) { ++ s1++; ++ continue; ++ } ++ ++ /* Skip over symbols whose sections have been identified. */ ++ for (i = 0; i < lm->mod_sections; i++) { ++ if ((lm->mod_section_data[i].flags & SEC_FOUND) == 0) ++ continue; ++ ++ if (s1->value >= lm->mod_section_data[i].addr && ++ s1->value < lm->mod_section_data[i].addr ++ + lm->mod_section_data[i].size) ++ break; ++ } ++ ++ /* Matched one of the sections. Skip symbol. */ ++ if (i < lm->mod_sections) { ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "skip %lx %s %s\n", s1->value, s1->name, ++ lm->mod_section_data[i].name); ++ s1++; ++ continue; ++ } ++ ++ /* Find the symbol in the object file. */ ++ from = (bfd_byte *) minisyms; ++ fromend = from + symcount * size; ++ secname = NULL; ++ for (; from < fromend; from += size) { ++ if (!(sym = bfd_minisymbol_to_symbol(bfd, dynamic, from, store))) ++ error(FATAL, "bfd_minisymbol_to_symbol() failed\n"); ++ ++ bfd_get_symbol_info(bfd, sym, &syminfo); ++ if (CRASHDEBUG(3)) { ++ fprintf(fp,"matching sym %s %lx against bfd %s %lx\n", ++ s1->name, (long) s1->value, syminfo.name, ++ (long) syminfo.value); ++ } ++ if (strcmp(syminfo.name, s1->name) == 0) { ++ secname = (char *)bfd_section_name(sym->section); ++ break; ++ } ++ ++ } ++ if (secname == NULL) { ++ if (CRASHDEBUG(1)) ++ fprintf(fp, "symbol %s not found in module\n", s1->name); ++ s1++; ++ continue; ++ } ++ ++ /* Match the section it came in. */ ++ for (i = 0; i < lm->mod_sections; i++) { ++ if (STREQ(lm->mod_section_data[i].name, secname)) ++ break; ++ } ++ ++ if (i == lm->mod_sections) { ++ fprintf(fp, "?? Section %s not found for symbol %s\n", ++ secname, s1->name); ++ s1++; ++ continue; ++ } ++ ++ if (lm->mod_section_data[i].flags & SEC_FOUND) { ++ s1++; ++ continue; ++ } ++ ++ /* Update the offset information for the section */ ++ sec_start = s1->value - syminfo.value; ++ /* keep the address instead of offset */ ++ lm->mod_section_data[i].addr = sec_start; ++ lm->mod_section_data[i].flags |= SEC_FOUND; ++ ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "update sec offset sym %s @ %lx val %lx section %s\n", ++ s1->name, s1->value, (ulong)syminfo.value, secname); ++ ++ if (strcmp(secname, ".text") == 0) ++ lm->mod_text_start = sec_start; ++ ++ if (strcmp(secname, ".bss") == 0) ++ lm->mod_bss_start = sec_start; ++ ++ if (strcmp(secname, ".data") == 0) ++ lm->mod_data_start = sec_start; ++ ++ if (strcmp(secname, ".rodata") == 0) ++ lm->mod_rodata_start = sec_start; ++ s1++; ++ } ++ } ++} ++ + /* + * Later versons of insmod store basic address information of each + * module in a format that looks like the following example of the +@@ -11885,8 +12973,11 @@ add_symbol_file(struct load_module *lm) + (!STREQ(secname, ".text") && + !STREQ(secname, ".data.percpu") && + !STREQ(secname, ".data..percpu"))) { +- sprintf(buf, " -s %s 0x%lx", secname, +- lm->mod_section_data[i].offset + lm->mod_base); ++ if (MODULE_MEMORY()) ++ sprintf(buf, " -s %s 0x%lx", secname, lm->mod_section_data[i].addr); ++ else ++ sprintf(buf, " -s %s 0x%lx", secname, ++ lm->mod_section_data[i].offset + lm->mod_base); + len += strlen(buf); + } + } +@@ -12227,24 +13318,43 @@ static struct syment * + kallsyms_module_symbol(struct load_module *lm, symbol_info *syminfo) + { + struct syment *sp, *spx; +- int cnt; ++ int cnt, t; + + if (!(lm->mod_flags & MOD_KALLSYMS)) + return NULL; + + sp = NULL; + cnt = 0; +- for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) { +- if (!STREQ(spx->name, syminfo->name)) +- continue; +- if (spx->cnt) { +- cnt++; +- continue; +- } ++ if (MODULE_MEMORY()) { ++ for_each_mod_mem_type(t) { ++ if (!lm->ext_symtable[t]) ++ continue; ++ for (spx = lm->ext_symtable[t]; spx <= lm->ext_symend[t]; spx++) { ++ if (!STREQ(spx->name, syminfo->name)) ++ continue; ++ if (spx->cnt) { ++ cnt++; ++ continue; ++ } + +- spx->cnt++; +- sp = spx; +- break; ++ spx->cnt++; ++ sp = spx; ++ break; ++ } ++ } ++ } else { ++ for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) { ++ if (!STREQ(spx->name, syminfo->name)) ++ continue; ++ if (spx->cnt) { ++ cnt++; ++ continue; ++ } ++ ++ spx->cnt++; ++ sp = spx; ++ break; ++ } + } + + if (CRASHDEBUG(2)) { +@@ -12270,7 +13380,7 @@ static void + store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, + long symcount, unsigned int size, ulong base_addr, char *namelist) + { +- int i; ++ int i, t; + asymbol *store; + asymbol *sym; + bfd_byte *from, *fromend; +@@ -12281,7 +13391,7 @@ store_load_module_symbols(bfd *bfd, int + char *nameptr, *secname; + long index; + long symalloc; +- int found; ++ int found = FALSE; + + if ((store = bfd_make_empty_symbol(bfd)) == NULL) + error(FATAL, "bfd_make_empty_symbol() failed\n"); +@@ -12338,8 +13448,17 @@ store_load_module_symbols(bfd *bfd, int + lm->mod_rodata_start = lm->mod_bss_start = 0; + lm->mod_load_symcnt = 0; + lm->mod_sections = 0; +- for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) +- spx->cnt = 0; ++ if (MODULE_MEMORY()) { ++ for_each_mod_mem_type(t) { ++ if (!lm->ext_symtable[t]) ++ continue; ++ for (spx = lm->ext_symtable[t]; spx <= lm->ext_symend[t]; spx++) ++ spx->cnt = 0; ++ } ++ } else { ++ for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) ++ spx->cnt = 0; ++ } + sp = lm->mod_load_symtable; + + if (!(lm->mod_section_data = (struct mod_section_data *) +@@ -12350,13 +13469,14 @@ store_load_module_symbols(bfd *bfd, int + + bfd_map_over_sections(bfd, section_header_info, MODULE_SECTIONS); + +- if (kt->flags & KMOD_V1) ++ if (MODULE_MEMORY()) ++ calculate_load_order_6_4(lm, bfd, dynamic, minisyms, symcount, size); ++ else if (kt->flags & KMOD_V1) + calculate_load_order_v1(lm, bfd); + else + calculate_load_order_v2(lm, bfd, dynamic, minisyms, + symcount, size); + +- + from = (bfd_byte *) minisyms; + fromend = from + symcount * size; + for (; from < fromend; from += size) +@@ -12459,7 +13579,10 @@ store_load_module_symbols(bfd *bfd, int + syminfo.value += lm->mod_percpu; + found = TRUE; + } else { +- syminfo.value += lm->mod_section_data[i].offset + lm->mod_base; ++ if (MODULE_MEMORY()) ++ syminfo.value += lm->mod_section_data[i].addr; ++ else ++ syminfo.value += lm->mod_section_data[i].offset + lm->mod_base; + found = TRUE; + } + } +@@ -12494,6 +13617,53 @@ store_load_module_symbols(bfd *bfd, int + * syminfo data types accepted above, plus the two pseudo symbols. + * Note that the new syment name pointers haven't been resolved yet. + */ ++ if (!MODULE_MEMORY()) ++ goto old_module; ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->ext_symtable[t]) ++ continue; ++ for (spx = lm->ext_symtable[t]; spx <= lm->ext_symend[t]; spx++) { ++ found = FALSE; ++ for (sp = lm->mod_load_symtable; sp < lm->mod_load_symend; sp++) { ++ index = (long)sp->name; ++ nameptr = &lm->mod_load_namespace.address[index]; ++ if (STREQ(spx->name, nameptr)) { ++ found = TRUE; ++ if (spx->value == sp->value) { ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "%s: %s matches!\n", ++ lm->mod_name, nameptr); ++ } else { ++ if (CRASHDEBUG(2)) ++ fprintf(fp, ++ "[%s] %s: %lx != extern'd value: %lx\n", ++ lm->mod_name, ++ nameptr, sp->value, ++ spx->value); ++ } ++ break; ++ } ++ } ++ if (!found) { ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "append ext %s (%lx)\n", spx->name, spx->value); ++ /* append it here... */ ++ namespace_ctl(NAMESPACE_INSTALL, ++ &lm->mod_load_namespace, ++ lm->mod_load_symend, spx->name); ++ ++ lm->mod_load_symend->value = spx->value; ++ lm->mod_load_symend->type = spx->type; ++ lm->mod_load_symend->flags |= MODULE_SYMBOL; ++ lm->mod_load_symend++; ++ lm->mod_load_symcnt++; ++ } ++ } ++ } ++ goto append_section_symbols; ++ ++old_module: + for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) { + found = FALSE; + for (sp = lm->mod_load_symtable; +@@ -12536,6 +13706,7 @@ store_load_module_symbols(bfd *bfd, int + } + } + ++append_section_symbols: + /* + * Append helpful pseudo symbols about found out sections. + * Use 'S' as its type which is never seen in existing symbols. +@@ -12545,8 +13716,11 @@ store_load_module_symbols(bfd *bfd, int + if (!(lm->mod_section_data[i].flags & SEC_FOUND)) + continue; + /* Section start */ +- lm->mod_load_symend->value = lm->mod_base + +- lm->mod_section_data[i].offset; ++ if (MODULE_MEMORY()) ++ lm->mod_load_symend->value = lm->mod_section_data[i].addr; ++ else ++ lm->mod_load_symend->value = lm->mod_base + ++ lm->mod_section_data[i].offset; + lm->mod_load_symend->type = 'S'; + lm->mod_load_symend->flags |= MODULE_SYMBOL; + sprintf(name, "_MODULE_SECTION_START [%s]", +@@ -12557,9 +13731,12 @@ store_load_module_symbols(bfd *bfd, int + lm->mod_load_symcnt++; + + /* Section end */ +- lm->mod_load_symend->value = lm->mod_base + +- lm->mod_section_data[i].offset + +- lm->mod_section_data[i].size; ++ if (MODULE_MEMORY()) ++ lm->mod_load_symend->value = lm->mod_section_data[i].addr; ++ else ++ lm->mod_load_symend->value = lm->mod_base + ++ lm->mod_section_data[i].offset; ++ lm->mod_load_symend->value += lm->mod_section_data[i].size; + lm->mod_load_symend->type = 'S'; + lm->mod_load_symend->flags |= MODULE_SYMBOL; + sprintf(name, "_MODULE_SECTION_END [%s]", +@@ -12576,16 +13753,57 @@ store_load_module_symbols(bfd *bfd, int + qsort(lm->mod_load_symtable, lm->mod_load_symcnt, sizeof(struct syment), + compare_syms); + ++ if (MODULE_MEMORY()) { ++ /* keep load symtable addresses to lm->load_symtable[] */ ++ /* TODO: make more efficient */ ++ for (sp = lm->mod_load_symtable; sp < lm->mod_load_symend; sp++) { ++ char buf1[BUFSIZE], buf2[BUFSIZE]; ++ ++ if (CRASHDEBUG(2)) ++ fprintf(fp, "DEBUG: value %16lx name %s\n", sp->value, sp->name); ++ ++ if (!MODULE_PSEUDO_SYMBOL(sp)) ++ continue; ++ ++ for_each_mod_mem_type(t) { ++ if (!lm->mem[t].size) ++ continue; ++ ++ sprintf(buf1, "%s%s", module_tag[t].start, lm->mod_name); ++ sprintf(buf2, "%s%s", module_tag[t].end, lm->mod_name); ++ ++ if (STREQ(sp->name, buf1)) { ++ lm->load_symtable[t] = sp; ++ break; ++ } else if (STREQ(sp->name, buf2)) { ++ lm->load_symend[t] = sp; ++ break; ++ } ++ } ++ } ++ } ++ + lm->mod_load_symend--; +- if (!MODULE_END(lm->mod_load_symend) && ++ if (!MODULE_MEMORY() && !MODULE_END(lm->mod_load_symend) && + !IN_MODULE_PERCPU(lm->mod_load_symend->value, lm)) + error(INFO, "%s: last symbol: %s is not _MODULE_END_%s?\n", + lm->mod_name, lm->mod_load_symend->name, lm->mod_name); + +- mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); +- lm->mod_symtable = lm->mod_load_symtable; +- lm->mod_symend = lm->mod_load_symend; +- mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); ++ if (MODULE_MEMORY()) { ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ mod_symtable_hash_remove_range(lm->symtable[t], lm->symend[t]); ++ } ++ lm->symtable = lm->load_symtable; ++ lm->symend = lm->load_symend; ++ mod_symtable_hash_install_range(lm->mod_load_symtable, lm->mod_load_symend); ++ } else { ++ mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); ++ lm->mod_symtable = lm->mod_load_symtable; ++ lm->mod_symend = lm->mod_load_symend; ++ mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); ++ } + + lm->mod_flags &= ~MOD_EXT_SYMS; + lm->mod_flags |= MOD_LOAD_SYMS; +@@ -12600,7 +13818,7 @@ store_load_module_symbols(bfd *bfd, int + void + delete_load_module(ulong base_addr) + { +- int i; ++ int i, t; + struct load_module *lm; + struct gnu_request request, *req; + +@@ -12615,7 +13833,18 @@ delete_load_module(ulong base_addr) + req->name = lm->mod_namelist; + gdb_interface(req); + } +- mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); ++ if (MODULE_MEMORY()) { ++ if (lm->mod_load_symtable) { ++ mod_symtable_hash_remove_range(lm->mod_load_symtable, ++ lm->mod_load_symend); ++ for_each_mod_mem_type(t) { ++ lm->load_symtable[t] = NULL; ++ lm->load_symend[t] = NULL; ++ } ++ } ++ } else ++ mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); ++ + if (lm->mod_load_symtable) { + free(lm->mod_load_symtable); + namespace_ctl(NAMESPACE_FREE, +@@ -12623,9 +13852,23 @@ delete_load_module(ulong base_addr) + } + if (lm->mod_flags & MOD_REMOTE) + unlink_module(lm); +- lm->mod_symtable = lm->mod_ext_symtable; +- lm->mod_symend = lm->mod_ext_symend; +- mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); ++ ++ if (MODULE_MEMORY()) { ++ if (lm->mod_load_symtable) { /* still non-NULL */ ++ lm->symtable = lm->ext_symtable; ++ lm->symend = lm->ext_symend; ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ mod_symtable_hash_install_range(lm->symtable[t], ++ lm->symend[t]); ++ } ++ } ++ } else { ++ lm->mod_symtable = lm->mod_ext_symtable; ++ lm->mod_symend = lm->mod_ext_symend; ++ mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); ++ } + lm->mod_flags &= ~(MOD_LOAD_SYMS|MOD_REMOTE|MOD_NOPATCH); + lm->mod_flags |= MOD_EXT_SYMS; + lm->mod_load_symtable = NULL; +@@ -12654,7 +13897,18 @@ delete_load_module(ulong base_addr) + req->name = lm->mod_namelist; + gdb_interface(req); + } +- mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); ++ if (MODULE_MEMORY()) { ++ if (lm->mod_load_symtable) { ++ mod_symtable_hash_remove_range(lm->mod_load_symtable, ++ lm->mod_load_symend); ++ for_each_mod_mem_type(t) { ++ lm->load_symtable[t] = NULL; ++ lm->load_symend[t] = NULL; ++ } ++ } ++ } else ++ mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); ++ + if (lm->mod_load_symtable) { + free(lm->mod_load_symtable); + namespace_ctl(NAMESPACE_FREE, +@@ -12662,9 +13916,23 @@ delete_load_module(ulong base_addr) + } + if (lm->mod_flags & MOD_REMOTE) + unlink_module(lm); +- lm->mod_symtable = lm->mod_ext_symtable; +- lm->mod_symend = lm->mod_ext_symend; +- mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); ++ ++ if (MODULE_MEMORY()) { ++ if (lm->mod_load_symtable) { ++ lm->symtable = lm->ext_symtable; ++ lm->symend = lm->ext_symend; ++ for_each_mod_mem_type(t) { ++ if (!lm->symtable[t]) ++ continue; ++ mod_symtable_hash_install_range(lm->symtable[t], ++ lm->symend[t]); ++ } ++ } ++ } else { ++ lm->mod_symtable = lm->mod_ext_symtable; ++ lm->mod_symend = lm->mod_ext_symend; ++ mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); ++ } + lm->mod_flags &= ~(MOD_LOAD_SYMS|MOD_REMOTE|MOD_NOPATCH); + lm->mod_flags |= MOD_EXT_SYMS; + lm->mod_load_symtable = NULL; +@@ -13413,7 +14681,7 @@ is_downsized(char *name) + struct syment * + symbol_complete_match(const char *match, struct syment *sp_last) + { +- int i; ++ int i, t; + struct syment *sp, *sp_end, *sp_start; + struct load_module *lm; + int search_init; +@@ -13433,6 +14701,34 @@ symbol_complete_match(const char *match, + sp_start = NULL; + } + ++ if (!MODULE_MEMORY()) ++ goto old_module; ++ ++ for (i = 0; i < st->mods_installed; i++) { ++ lm = &st->load_modules[i]; ++ ++ for_each_mod_mem_type(t) { ++ sp_end = lm->symend[t]; ++ if (!sp_start) ++ sp_start = lm->symtable[t]; ++ ++ if (sp_start < lm->symtable[t] || sp_start > sp_end) ++ continue; ++ ++ for (sp = sp_start; sp < sp_end; sp++) { ++ if (MODULE_PSEUDO_SYMBOL(sp)) ++ continue; ++ ++ if (STRNEQ(sp->name, match)) ++ return sp; ++ } ++ sp_start = NULL; ++ } ++ } ++ ++ return NULL; ++ ++old_module: + search_init = FALSE; + + for (i = 0; i < st->mods_installed; i++) { +@@ -13479,3 +14775,58 @@ symbol_complete_match(const char *match, + + return NULL; + } ++ ++/* Returns module memory type if addr is in range, otherwise MOD_INVALID(-1) */ ++static int ++in_module_range(ulong addr, struct load_module *lm, int start, int end) ++{ ++ ulong base = 0, size = 0; ++ int i; ++ ++ if (!MODULE_MEMORY()) ++ goto old_module; ++ ++ for (i = start ; i <= end; i++) { ++ base = lm->mem[i].base; ++ size = lm->mem[i].size; ++ if (!size) ++ continue; ++ if ((addr >= base) && (addr < (base + size))) ++ return i; ++ } ++ return MOD_INVALID; ++ ++old_module: ++ if (start == MOD_TEXT) { ++ base = lm->mod_base; ++ size = lm->mod_size; ++ } else if (start == MOD_INIT_TEXT) { ++ base = lm->mod_init_module_ptr; ++ size = lm->mod_init_size; ++ } else ++ error(FATAL, "invalid module memory type!"); ++ ++ if ((addr >= base) && (addr < (base + size))) ++ return start; ++ ++ return MOD_INVALID; ++} ++ ++/* Returns module memory type, otherwise MOD_INVALID(-1) */ ++static int ++module_mem_type(ulong addr, struct load_module *lm) ++{ ++ return in_module_range(addr, lm, MOD_TEXT, MOD_INIT_RODATA); ++} ++ ++/* Returns the end address of the module memory region. */ ++static ulong ++module_mem_end(ulong addr, struct load_module *lm) ++{ ++ int type = module_mem_type(addr, lm); ++ ++ if (type == MOD_INVALID) ++ return 0; ++ ++ return lm->mem[type].base + lm->mem[type].size; ++} diff -Nru crash-8.0.2/debian/patches/lp2038249-x86_64-Fix-for-move-of-per-cpu-variables-into-struct.patch crash-8.0.2/debian/patches/lp2038249-x86_64-Fix-for-move-of-per-cpu-variables-into-struct.patch --- crash-8.0.2/debian/patches/lp2038249-x86_64-Fix-for-move-of-per-cpu-variables-into-struct.patch 1970-01-01 00:00:00.000000000 +0000 +++ crash-8.0.2/debian/patches/lp2038249-x86_64-Fix-for-move-of-per-cpu-variables-into-struct.patch 2023-10-03 08:56:28.000000000 +0000 @@ -0,0 +1,136 @@ +From: Kazuhito Hagio +Date: Wed Dec 7 09:46:56 2022 +0900 +Subject: x86_64: Fix for move of per-cpu variables into struct pcpu_hot + +The following kernel commits, which are contained in Linux 6.2-rc1 and +later kernels, introduced struct pcpu_hot and moved several per-cpu +variables into it. + + d7b6d709a76a x86/percpu: Move irq_stack variables next to current_task + 7443b296e699 x86/percpu: Move cpu_number next to current_task + e57ef2ed97c1 x86: Put hot per CPU variables into a struct + +Without the patch, crash fails to start session with the following +error: + + $ crash vmlinux vmcore + ... + bt: invalid size request: 0 type: "stack contents" + bt: read of stack at 0 failed + + +Signed-off-by: Kazuhito Hagio + +Bug-Ubuntu: https://launchpad.net/bugs/2038249 +Origin: upstream, https://github.com/crash-utility/crash/commit/df1f0cba729fa0e0d8a63220769c42cc9033acc1 + +--- crash-8.0.2.orig/x86_64.c ++++ crash-8.0.2/x86_64.c +@@ -1290,12 +1290,15 @@ x86_64_per_cpu_init(void) + { + int i, cpus, cpunumber; + struct machine_specific *ms; +- struct syment *irq_sp, *curr_sp, *cpu_sp, *hardirq_stack_ptr_sp; ++ struct syment *irq_sp, *curr_sp, *cpu_sp, *hardirq_stack_ptr_sp, *pcpu_sp; + ulong hardirq_stack_ptr; + ulong __per_cpu_load = 0; ++ long hardirq_addr = 0, cpu_addr = 0, curr_addr = 0; + + ms = machdep->machspec; + ++ pcpu_sp = per_cpu_symbol_search("pcpu_hot"); ++ + hardirq_stack_ptr_sp = per_cpu_symbol_search("hardirq_stack_ptr"); + irq_sp = per_cpu_symbol_search("per_cpu__irq_stack_union"); + cpu_sp = per_cpu_symbol_search("per_cpu__cpu_number"); +@@ -1324,7 +1327,7 @@ x86_64_per_cpu_init(void) + return; + } + +- if (!cpu_sp || (!irq_sp && !hardirq_stack_ptr_sp)) ++ if (!pcpu_sp && (!cpu_sp || (!irq_sp && !hardirq_stack_ptr_sp))) + return; + + if (MEMBER_EXISTS("irq_stack_union", "irq_stack")) +@@ -1337,10 +1340,21 @@ x86_64_per_cpu_init(void) + if (kernel_symbol_exists("__per_cpu_load")) + __per_cpu_load = symbol_value("__per_cpu_load"); + ++ if (pcpu_sp) { ++ hardirq_addr = pcpu_sp->value + MEMBER_OFFSET("pcpu_hot", "hardirq_stack_ptr"); ++ cpu_addr = pcpu_sp->value + MEMBER_OFFSET("pcpu_hot", "cpu_number"); ++ curr_addr = pcpu_sp->value + MEMBER_OFFSET("pcpu_hot", "current_task"); ++ } else { ++ if (hardirq_stack_ptr_sp) ++ hardirq_addr = hardirq_stack_ptr_sp->value; ++ cpu_addr = cpu_sp->value; ++ curr_addr = curr_sp->value; ++ } ++ + for (i = cpus = 0; i < NR_CPUS; i++) { + if (__per_cpu_load && kt->__per_cpu_offset[i] == __per_cpu_load) + break; +- if (!readmem(cpu_sp->value + kt->__per_cpu_offset[i], ++ if (!readmem(cpu_addr + kt->__per_cpu_offset[i], + KVADDR, &cpunumber, sizeof(int), + "cpu number (per_cpu)", QUIET|RETURN_ON_ERROR)) + break; +@@ -1349,8 +1363,8 @@ x86_64_per_cpu_init(void) + break; + cpus++; + +- if (hardirq_stack_ptr_sp) { +- if (!readmem(hardirq_stack_ptr_sp->value + kt->__per_cpu_offset[i], ++ if (pcpu_sp || hardirq_stack_ptr_sp) { ++ if (!readmem(hardirq_addr + kt->__per_cpu_offset[i], + KVADDR, &hardirq_stack_ptr, sizeof(void *), + "hardirq_stack_ptr (per_cpu)", QUIET|RETURN_ON_ERROR)) + continue; +@@ -1373,13 +1387,13 @@ x86_64_per_cpu_init(void) + else + kt->cpus = cpus; + +- if (DUMPFILE() && curr_sp) { ++ if (DUMPFILE() && (pcpu_sp || curr_sp)) { + if ((ms->current = calloc(kt->cpus, sizeof(ulong))) == NULL) + error(FATAL, + "cannot calloc %d x86_64 current pointers!\n", + kt->cpus); + for (i = 0; i < kt->cpus; i++) +- if (!readmem(curr_sp->value + kt->__per_cpu_offset[i], ++ if (!readmem(curr_addr + kt->__per_cpu_offset[i], + KVADDR, &ms->current[i], sizeof(ulong), + "current_task (per_cpu)", RETURN_ON_ERROR)) + continue; +@@ -5625,11 +5639,19 @@ x86_64_get_smp_cpus(void) + char *cpu_pda_buf; + ulong level4_pgt, cpu_pda_addr; + struct syment *sp; +- ulong __per_cpu_load = 0; ++ ulong __per_cpu_load = 0, cpu_addr; + + if (!VALID_STRUCT(x8664_pda)) { +- if (!(sp = per_cpu_symbol_search("per_cpu__cpu_number")) || +- !(kt->flags & PER_CPU_OFF)) ++ ++ if (!(kt->flags & PER_CPU_OFF)) ++ return 1; ++ ++ if ((sp = per_cpu_symbol_search("pcpu_hot")) && ++ (cpu_addr = MEMBER_OFFSET("pcpu_hot", "cpu_number")) != INVALID_OFFSET) ++ cpu_addr += sp->value; ++ else if ((sp = per_cpu_symbol_search("per_cpu__cpu_number"))) ++ cpu_addr = sp->value; ++ else + return 1; + + if (kernel_symbol_exists("__per_cpu_load")) +@@ -5638,7 +5660,7 @@ x86_64_get_smp_cpus(void) + for (i = cpus = 0; i < NR_CPUS; i++) { + if (__per_cpu_load && kt->__per_cpu_offset[i] == __per_cpu_load) + break; +- if (!readmem(sp->value + kt->__per_cpu_offset[i], ++ if (!readmem(cpu_addr + kt->__per_cpu_offset[i], + KVADDR, &cpunumber, sizeof(int), + "cpu number (per_cpu)", QUIET|RETURN_ON_ERROR)) + break; diff -Nru crash-8.0.2/debian/patches/series crash-8.0.2/debian/patches/series --- crash-8.0.2/debian/patches/series 2022-11-17 18:27:25.000000000 +0000 +++ crash-8.0.2/debian/patches/series 2023-10-03 09:20:35.000000000 +0000 @@ -1 +1,8 @@ 0001-dont-git-clone-eppic-extension.patch +lp2038249-SLUB-Fix-for-offset-change-of-struct-slab-members-on.patch +lp2038249-x86_64-Fix-for-move-of-per-cpu-variables-into-struct.patch +lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.1-and-later.patch +lp2038249-SLAB-Fix-for-kmem-s-S-options-on-Linux-6.2-rc1-and-l.patch +lp2038249-Support-module-memory-layout-change-on-Linux-6.4.patch +lp2038249-Fix-failure-of-gathering-task-table-on-Linux-6.5-rc1.patch +lp2038249-Fix-compilation-error-due-to-new-strlcpy-function-th.patch