Source code for crash.arch
# -*- coding: utf-8 -*-
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
from typing import List, Iterator, Any, Optional, Type
import crash
import gdb
from gdb.FrameDecorator import FrameDecorator
[docs]class FetchRegistersCallback:
"""
The base class from which to implement the fetch_registers callback.
The architecture code must implement the :meth:`fetch_active` and
:meth:`fetch_scheduled` methods.
"""
[docs] def fetch_active(self, thread: gdb.InferiorThread, register: int) -> None:
raise NotImplementedError("Target has no fetch_active callback")
[docs] def fetch_scheduled(self, thread: gdb.InferiorThread,
register: int) -> None:
raise NotImplementedError("Target has no fetch_scheduled callback")
def __call__(self, thread: gdb.InferiorThread,
register: gdb.Register) -> None:
if register is None:
regnum = -1
else:
regnum = register.regnum
if thread.info.active:
return self.fetch_active(thread, regnum)
return self.fetch_scheduled(thread, regnum)
[docs]class CrashArchitecture:
ident = "base-class"
aliases: List[str] = list()
_fetch_registers: Type[FetchRegistersCallback]
def __init__(self) -> None:
target = crash.current_target()
try:
target.set_fetch_registers(self._fetch_registers())
except AttributeError:
raise NotImplementedError("No fetch_registers callback defined")
[docs] @classmethod
def set_fetch_registers(cls,
callback: Type[FetchRegistersCallback]) -> None:
"""
Set a fetch_regisers callback for the Target to use.
Args:
callback: A Callable that accepts a :obj:`gdb.InferiorThread` and
:obj:`gdb.Register` and populates the requested registers for
the specified thread. A register with the seemingly invalid
register number of -1 is a request to populate all registers.
"""
cls._fetch_registers = callback
[docs] def setup_thread_info(self, thread: gdb.InferiorThread) -> None:
raise NotImplementedError("setup_thread_info not implemented")
[docs] def get_stack_pointer(self, thread_struct: gdb.Value) -> int:
raise NotImplementedError("get_stack_pointer is not implemented")
# This keeps stack traces from continuing into userspace and causing problems.
[docs]class KernelFrameFilter:
def __init__(self, address: int) -> None:
self.name = "KernelFrameFilter"
self.priority = 100
self.enabled = True
self.address = address
gdb.frame_filters[self.name] = self
[docs] def filter(self, frame_iter: Iterator[Any]) -> Any:
return KernelAddressIterator(frame_iter, self.address)
[docs]class KernelAddressIterator:
def __init__(self, ii: Iterator, address: int) -> None:
self.input_iterator = ii
self.address = address
def __iter__(self) -> Any:
return self
def __next__(self) -> Any:
frame = next(self.input_iterator)
if frame.inferior_frame().pc() < self.address:
raise StopIteration
return frame
architectures = {}
[docs]def register_arch(arch: Type[CrashArchitecture]) -> None:
architectures[arch.ident] = arch
for ident in arch.aliases:
architectures[ident] = arch
[docs]def get_architecture(archname: str) -> Type[CrashArchitecture]:
if archname in architectures:
return architectures[archname]
raise RuntimeError(f"Couldn't locate helpers for arch: {archname}")