Commit 28939c3e authored by Ilya Leoshkevich's avatar Ilya Leoshkevich Committed by Andrew Morton
Browse files

scripts/gdb/symbols: determine KASLR offset on s390

Use QEMU's qemu.PhyMemMode [1] functionality to read vmcore from the
physical memory the same way the existing dump tooling does this. 
Gracefully handle non-QEMU targets, early boot, and memory corruptions;
print a warning if such situation is detected.

[1] https://qemu-project.gitlab.io/qemu/system/gdb.html#examining-physical-memory

Link: https://lkml.kernel.org/r/20250303110437.79070-1-iii@linux.ibm.com


Signed-off-by: default avatarIlya Leoshkevich <iii@linux.ibm.com>
Acked-by: default avatarJan Kiszka <jan.kiszka@siemens.com>
Cc: Alexander Gordeev <agordeev@linux.ibm.com>
Cc: Andrew Donnellan <ajd@linux.ibm.com>
Cc: Christian Borntraeger <borntraeger@linux.ibm.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Kieran Bingham <kbingham@kernel.org>
Cc: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 8a56f266
Loading
Loading
Loading
Loading
+30 −1
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@
import gdb
import os
import re
import struct

from itertools import count
from linux import modules, utils, constants
@@ -54,6 +55,29 @@ if hasattr(gdb, 'Breakpoint'):
            return False


def get_vmcore_s390():
    with utils.qemu_phy_mem_mode():
        vmcore_info = 0x0e0c
        paddr_vmcoreinfo_note = gdb.parse_and_eval("*(unsigned long long *)" +
                                                   hex(vmcore_info))
        inferior = gdb.selected_inferior()
        elf_note = inferior.read_memory(paddr_vmcoreinfo_note, 12)
        n_namesz, n_descsz, n_type = struct.unpack(">III", elf_note)
        desc_paddr = paddr_vmcoreinfo_note + len(elf_note) + n_namesz + 1
        return gdb.parse_and_eval("(char *)" + hex(desc_paddr)).string()


def get_kerneloffset():
    if utils.is_target_arch('s390'):
        try:
            vmcore_str = get_vmcore_s390()
        except gdb.error as e:
            gdb.write("{}\n".format(e))
            return None
        return utils.parse_vmcore(vmcore_str).kerneloffset
    return None


class LxSymbols(gdb.Command):
    """(Re-)load symbols of Linux kernel and currently loaded modules.

@@ -160,7 +184,12 @@ lx-symbols command."""
                obj.filename.endswith('vmlinux.debug')):
                orig_vmlinux = obj.filename
        gdb.execute("symbol-file", to_string=True)
        gdb.execute("symbol-file {0}".format(orig_vmlinux))
        kerneloffset = get_kerneloffset()
        if kerneloffset is None:
            offset_arg = ""
        else:
            offset_arg = " -o " + hex(kerneloffset)
        gdb.execute("symbol-file {0}{1}".format(orig_vmlinux, offset_arg))

        self.loaded_modules = []
        module_list = modules.module_list()
+35 −0
Original line number Diff line number Diff line
@@ -11,6 +11,11 @@
# This work is licensed under the terms of the GNU GPL version 2.
#

import contextlib
import dataclasses
import re
import typing

import gdb


@@ -216,3 +221,33 @@ def gdb_eval_or_none(expresssion):
        return gdb.parse_and_eval(expresssion)
    except gdb.error:
        return None


@contextlib.contextmanager
def qemu_phy_mem_mode():
    connection = gdb.selected_inferior().connection
    orig = connection.send_packet("qqemu.PhyMemMode")
    if orig not in b"01":
        raise gdb.error("Unexpected qemu.PhyMemMode")
    orig = orig.decode()
    if connection.send_packet("Qqemu.PhyMemMode:1") != b"OK":
        raise gdb.error("Failed to set qemu.PhyMemMode")
    try:
        yield
    finally:
        if connection.send_packet("Qqemu.PhyMemMode:" + orig) != b"OK":
            raise gdb.error("Failed to restore qemu.PhyMemMode")


@dataclasses.dataclass
class VmCore:
    kerneloffset: typing.Optional[int]


def parse_vmcore(s):
    match = re.search(r"KERNELOFFSET=([0-9a-f]+)", s)
    if match is None:
        kerneloffset = None
    else:
        kerneloffset = int(match.group(1), 16)
    return VmCore(kerneloffset=kerneloffset)