| From: Ilya Leoshkevich <iii@linux.ibm.com> |
| Subject: scripts/gdb/symbols: determine KASLR offset on s390 |
| Date: Mon, 3 Mar 2025 12:03:58 +0100 |
| |
| 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: Ilya Leoshkevich <iii@linux.ibm.com> |
| Acked-by: Jan 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: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| scripts/gdb/linux/symbols.py | 31 ++++++++++++++++++++++++++++- |
| scripts/gdb/linux/utils.py | 35 +++++++++++++++++++++++++++++++++ |
| 2 files changed, 65 insertions(+), 1 deletion(-) |
| |
| --- a/scripts/gdb/linux/symbols.py~scripts-gdb-symbols-determine-kaslr-offset-on-s390 |
| +++ a/scripts/gdb/linux/symbols.py |
| @@ -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() |
| --- a/scripts/gdb/linux/utils.py~scripts-gdb-symbols-determine-kaslr-offset-on-s390 |
| +++ a/scripts/gdb/linux/utils.py |
| @@ -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) |
| _ |