Source code for kdump.target

# -*- coding: utf-8 -*-
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

from typing import Tuple, Callable

import sys

from kdumpfile import kdumpfile, KDUMP_KVADDR
from kdumpfile.exceptions import AddressTranslationException, EOFException
import addrxlat.exceptions

import gdb

TargetFetchRegisters = Callable[[gdb.InferiorThread, gdb.Register], None]

PTID = Tuple[int, int, int]

[docs]class Target(gdb.Target): _fetch_registers: TargetFetchRegisters def __init__(self, debug: bool = False) -> None: super().__init__() self.debug = debug self.shortname = "kdumpfile" self.longname = "Use a Linux kernel kdump file as a target" self.kdump: kdumpfile self.base_offset = 0 self.register() # pylint: disable=unused-argument
[docs] def open(self, filename: str, from_tty: bool) -> None: objfiles = gdb.objfiles() if not objfiles: raise gdb.GdbError("kdumpfile target requires kernel to be already loaded for symbol resolution") try: self.kdump = kdumpfile(file=filename) except Exception as e: raise gdb.GdbError("Failed to open `{}': {}" .format(filename, str(e))) # pylint: disable=unsupported-assignment-operation self.kdump.attr['addrxlat.ostype'] = 'linux' KERNELOFFSET = "linux.vmcoreinfo.lines.KERNELOFFSET" try: attr = self.kdump.attr.get(KERNELOFFSET, "0") # pylint: disable=no-member self.base_offset = int(attr, base=16) except (TypeError, ValueError): pass vmlinux = gdb.objfiles()[0].filename # Load the kernel at the relocated address # Unfortunately, the percpu section has an offset of 0 and # ends up getting placed at the offset base. This is easy # enough to handle in the percpu code. result = gdb.execute("add-symbol-file {} -o {:#x}" .format(vmlinux, self.base_offset), to_string=True) if self.debug: print(result) # Clear out the old symbol cache gdb.execute("file {}".format(vmlinux))
[docs] def close(self) -> None: try: self.unregister() except RuntimeError: pass del self.kdump
[docs] @classmethod def report_error(cls, addr: int, length: int, error: Exception) -> None: print("Error while reading {:d} bytes from {:#x}: {}" .format(length, addr, str(error)), file=sys.stderr)
# pylint: disable=unused-argument
[docs] def xfer_partial(self, obj: int, annex: str, readbuf: bytearray, writebuf: bytearray, offset: int, ln: int) -> int: ret = -1 if obj == self.TARGET_OBJECT_MEMORY: try: r = self.kdump.read(KDUMP_KVADDR, offset, ln) readbuf[:] = r ret = ln except EOFException as e: if self.debug: self.report_error(offset, ln, e) raise gdb.TargetXferEOF(str(e)) except addrxlat.exceptions.NoDataError as e: # pylint: disable=no-member if self.debug: self.report_error(offset, ln, e) raise gdb.TargetXferUnavailable(str(e)) except AddressTranslationException as e: if self.debug: self.report_error(offset, ln, e) raise gdb.TargetXferUnavailable(str(e)) else: raise IOError("Unknown obj type") return ret
# pylint: disable=unused-argument
[docs] def thread_alive(self, ptid: PTID) -> bool: return True
[docs] def pid_to_str(self, ptid: PTID) -> str: return "pid {:d}".format(ptid[1])
[docs] def set_fetch_registers(self, callback: TargetFetchRegisters) -> None: self._fetch_registers = callback # type: ignore
[docs] def fetch_registers(self, thread: gdb.InferiorThread, register: gdb.Register) -> None: try: return self._fetch_registers(thread, register) # type: ignore except AttributeError: raise NotImplementedError("Target did not define fetch_registers callback")
[docs] def prepare_to_store(self, thread: gdb.InferiorThread) -> None: pass
# We don't need to store anything; The regcache is already written. # pylint: disable=unused-argument
[docs] def store_registers(self, thread: gdb.InferiorThread, register: gdb.Register) -> None: pass
# pylint: disable=unused-argument
[docs] def has_execution(self, ptid: PTID) -> bool: return False