Hi, Aditya
Thank you for the patch.

On Mon, Sep 11, 2023 at 8:00 PM <crash-utility-request@redhat.com> wrote:
From: Aditya Gupta <adityag@linux.ibm.com>
To: crash-utility@redhat.com
Cc: Hari Bathini <hbathini@linux.ibm.com>, Mahesh J Salgaonkar
        <mahesh@linux.ibm.com>, Sourabh Jain <sourabhjain@linux.ibm.com>,
        "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
Subject: [Crash-utility] [PATCH] ppc64: do page traversal if
        vmemmap_list not populated
Message-ID: <20230911093032.419388-1-adityag@linux.ibm.com>
Content-Type: text/plain; charset="US-ASCII"; x-default=true

Currently 'crash-tool' fails on vmcore collected on upstream kernel on
PowerPC64 with the error:

    crash: invalid kernel virtual address: 0  type: "first list entry

Presently the address translation for vmemmap addresses is done using
the vmemmap_list. But with the below commit in Linux, vmemmap_list can
be empty, in case of Radix MMU on PowerPC64

    368a0590d954: (powerpc/book3s64/vmemmap: switch radix to use a
    different vmemmap handling function)

In case vmemmap_list is empty, then it's head is NULL, which crash tries
to access and fails due to accessing NULL.

Instead of depending on 'vmemmap_list' for address translation for
vmemmap addresses, do a kernel pagetable walk to get the physical
address associated with given virtual address

Reviewed-by: Hari Bathini <hbathini@linux.ibm.com>
Signed-off-by: Aditya Gupta <adityag@linux.ibm.com>

---

Testing
=======

Git tree with patch applied:
https://github.com/adi-g15-ibm/crash/tree/bugzilla-203296-list-v1

This can be tested with '/proc/vmcore' as the vmcore, since makedumpfile

Can you help to describe in detail how to reproduce this issue? Or does this require any kernel configs to be enabled first?  I did not reproduce the current issue with '/proc/kcore' or vmcore(via cp).

Test kernel commit: ce9ecca0238b ("Linux 6.6-rc2")

# ./crash /home/linux/vmlinux /var/crash/127.0.0.1-2023-09-18-06\:58\:57/vmcore

crash 8.0.3++
Copyright (C) 2002-2022  Red Hat, Inc.
Copyright (C) 2004, 2005, 2006, 2010  IBM Corporation
Copyright (C) 1999-2006  Hewlett-Packard Co
Copyright (C) 2005, 2006, 2011, 2012  Fujitsu Limited
Copyright (C) 2006, 2007  VA Linux Systems Japan K.K.
Copyright (C) 2005, 2011, 2020-2022  NEC Corporation
Copyright (C) 1999, 2002, 2007  Silicon Graphics, Inc.
Copyright (C) 1999, 2000, 2001, 2002  Mission Critical Linux, Inc.
Copyright (C) 2015, 2021  VMware, Inc.
This program is free software, covered by the GNU General Public License,
and you are welcome to change it and/or distribute copies of it under
certain conditions.  Enter "help copying" to see the conditions.
This program has absolutely no warranty.  Enter "help warranty" for details.
 
GNU gdb (GDB) 10.2
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "powerpc64le-unknown-linux-gnu".
Type "show configuration" for configuration details.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...

      KERNEL: /home/linux/vmlinux              
    DUMPFILE: /var/crash/127.0.0.1-2023-09-18-06:58:57/vmcore
        CPUS: 8
        DATE: Mon Sep 18 06:57:40 EDT 2023
      UPTIME: 00:03:19
LOAD AVERAGE: 0.20, 0.31, 0.14
       TASKS: 186
    NODENAME: ibm-p9z-16-lp10.khw3.lab.eng.bos.redhat.com
     RELEASE: 6.6.0-rc2
     VERSION: #2 SMP Mon Sep 18 06:11:14 EDT 2023
     MACHINE: ppc64le  (2800 Mhz)
      MEMORY: 16 GB
       PANIC: "Kernel panic - not syncing: sysrq triggered crash"
         PID: 4337
     COMMAND: "bash"
        TASK: c000000052a49900  [THREAD_INFO: c000000052a49900]
         CPU: 3
       STATE: TASK_RUNNING (PANIC)

crash> 

Thanks
Lianbo

also fails in absence of 'vmemmap_list' in upstream linux

The fix for makedumpfile will also been sent to upstream

---
---
 ppc64.c | 47 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 33 insertions(+), 14 deletions(-)

diff --git a/ppc64.c b/ppc64.c
index fc34006f4863..1e84c5f56773 100644
--- a/ppc64.c
+++ b/ppc64.c
@@ -1280,8 +1280,30 @@ void ppc64_vmemmap_init(void)
        long backing_size, virt_addr_offset, phys_offset, list_offset;
        ulong *vmemmap_list;
        char *vmemmap_buf;
-       struct machine_specific *ms;
-       
+       struct machine_specific *ms = machdep->machspec;
+
+       ld = &list_data;
+       BZERO(ld, sizeof(struct list_data));
+
+       /*
+        * vmemmap_list is missing or set to 0 in the kernel would imply
+        * vmemmap region is mapped in the kernel pagetable. So, read vmemmap_list
+        * anyway and use the translation method accordingly.
+        */
+       readmem(symbol_value("vmemmap_list"), KVADDR, &ld->start, sizeof(void *),
+               "vmemmap_list", RETURN_ON_ERROR);
+       if (!ld->start) {
+               /*
+                * vmemmap_list is set to 0 or missing. Do kernel pagetable walk
+                * for vmemmamp address translation.
+                */
+               ms->vmemmap_list = NULL;
+               ms->vmemmap_cnt = 0;
+
+               machdep->flags |= VMEMMAP_AWARE;
+               return;
+       }
+
        if (!(kernel_symbol_exists("vmemmap_list")) ||
            !(kernel_symbol_exists("mmu_psize_defs")) ||
            !(kernel_symbol_exists("mmu_vmemmap_psize")) ||
@@ -1293,8 +1315,6 @@ void ppc64_vmemmap_init(void)
            !MEMBER_EXISTS("vmemmap_backing", "list"))
                return;

-       ms = machdep->machspec;
-
        backing_size = STRUCT_SIZE("vmemmap_backing");
        virt_addr_offset = MEMBER_OFFSET("vmemmap_backing", "virt_addr");
        phys_offset = MEMBER_OFFSET("vmemmap_backing", "phys");
@@ -1313,14 +1333,8 @@ void ppc64_vmemmap_init(void)

        ms->vmemmap_psize = 1 << shift;

-        ld =  &list_data;
-        BZERO(ld, sizeof(struct list_data));
-       if (!readmem(symbol_value("vmemmap_list"),
-           KVADDR, &ld->start, sizeof(void *), "vmemmap_list",
-           RETURN_ON_ERROR))
-               return;
-        ld->end = symbol_value("vmemmap_list");
-        ld->list_head_offset = list_offset;
+       ld->end = symbol_value("vmemmap_list");
+       ld->list_head_offset = list_offset;

         hq_open();
        cnt = do_list(ld);
@@ -1366,7 +1380,7 @@ ppc64_vmemmap_to_phys(ulong kvaddr, physaddr_t *paddr, int verbose)
 {
        int i;
        ulong offset;
-       struct machine_specific *ms;
+       struct machine_specific *ms = machdep->machspec;

        if (!(machdep->flags & VMEMMAP_AWARE)) {
                /*
@@ -1386,7 +1400,12 @@ ppc64_vmemmap_to_phys(ulong kvaddr, physaddr_t *paddr, int verbose)
                return FALSE;
        }

-       ms = machdep->machspec;
+       /**
+        * When vmemmap_list is not populated, kernel does the mapping in init_mm
+        * page table, so do a pagetable walk in kernel page table
+        */
+       if (!ms->vmemmap_list)
+               return ppc64_vtop_level4(kvaddr, (ulong *)vt->kernel_pgd[0], paddr, verbose);

        for (i = 0; i < ms->vmemmap_cnt; i++) {
                if ((kvaddr >= ms->vmemmap_list[i].virt) &&
--
2.41.0