Source code for crash.arch.x86_64

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

from crash.arch import CrashArchitecture, KernelFrameFilter, register_arch
from crash.arch import FetchRegistersCallback
from crash.util.symbols import Types, MinimalSymvals
from crash.util.symbols import TypeCallbacks, MinimalSymbolCallbacks

import gdb

types = Types(['struct inactive_task_frame *', 'struct thread_info *',
               'unsigned long *'])
msymvals = MinimalSymvals(['thread_return'])

# pylint: disable=abstract-method
class _FetchRegistersBase(FetchRegistersCallback):
    def fetch_active(self, thread: gdb.InferiorThread, register: int) -> None:
        task = thread.info
        for reg in task.regs:
            if reg == "rip" and register not in (16, -1):
                continue
            try:
                thread.registers[reg].value = task.regs[reg]
            except KeyError:
                pass

    def fetch_scheduled(self, thread: gdb.InferiorThread,
                        register: int) -> None:
        pass

# pylint: disable=abstract-method
class _FRC_inactive_task_frame(_FetchRegistersBase):
    def fetch_scheduled(self, thread: gdb.InferiorThread,
                        register: int) -> None:
        task = thread.info.task_struct

        rsp = task['thread']['sp'].cast(types.unsigned_long_p_type)
        thread.registers['rsp'].value = rsp

        frame = rsp.cast(types.inactive_task_frame_p_type).dereference()

        # Only write rip when requested; It resets the frame cache
        if register in (16, -1):
            thread.registers['rip'].value = frame['ret_addr']
            if register == 16:
                return

        thread.registers['rbp'].value = frame['bp']
        thread.registers['rbx'].value = frame['bx']
        thread.registers['r12'].value = frame['r12']
        thread.registers['r13'].value = frame['r13']
        thread.registers['r14'].value = frame['r14']
        thread.registers['r15'].value = frame['r15']
        thread.registers['cs'].value = 2*8
        thread.registers['ss'].value = 3*8

        thread.info.stack_pointer = rsp
        thread.info.valid_stack = True

class _FRC_thread_return(_FetchRegistersBase):
    def fetch_scheduled(self, thread: gdb.InferiorThread,
                        register: int) -> None:
        task = thread.info.task_struct

        # Only write rip when requested; It resets the frame cache
        if register in (16, -1):
            thread.registers['rip'].value = msymvals.thread_return
            if register == 16:
                return

        rsp = task['thread']['sp'].cast(types.unsigned_long_p_type)
        rbp = rsp.dereference().cast(types.unsigned_long_p_type)
        rbx = (rbp - 1).dereference()
        r12 = (rbp - 2).dereference()
        r13 = (rbp - 3).dereference()
        r14 = (rbp - 4).dereference()
        r15 = (rbp - 5).dereference()

        # The two pushes that don't have CFI info
        # rsp += 2

        # ex = in_exception_stack(rsp)
        # if ex:
        #     print("EXCEPTION STACK: pid {:d}".format(task['pid']))

        thread.registers['rsp'].value = rsp
        thread.registers['rbp'].value = rbp
        thread.registers['rbx'].value = rbx
        thread.registers['r12'].value = r12
        thread.registers['r13'].value = r13
        thread.registers['r14'].value = r14
        thread.registers['r15'].value = r15
        thread.registers['cs'].value = 2*8
        thread.registers['ss'].value = 3*8

        thread.info.stack_pointer = rsp
        thread.info.valid_stack = True

[docs]class x86_64Architecture(CrashArchitecture): ident = "i386:x86-64" aliases = ["x86_64"] def __init__(self) -> None: super(x86_64Architecture, self).__init__() # Stop stack traces with addresses below this self.filter = KernelFrameFilter(0xffff000000000000)
[docs] def setup_thread_info(self, thread: gdb.InferiorThread) -> None: task = thread.info.task_struct thread_info = task['stack'].cast(types.thread_info_p_type) thread.info.set_thread_info(thread_info)
[docs] @classmethod # pylint: disable=unused-argument def setup_inactive_task_frame_handler(cls, inactive: gdb.Type) -> None: cls.set_fetch_registers(_FRC_inactive_task_frame)
[docs] @classmethod # pylint: disable=unused-argument def setup_thread_return_handler(cls, inactive: gdb.Type) -> None: cls.set_fetch_registers(_FRC_thread_return)
[docs] @classmethod def get_stack_pointer(cls, thread_struct: gdb.Value) -> int: return int(thread_struct['sp'])
type_cbs = TypeCallbacks([('struct inactive_task_frame', x86_64Architecture.setup_inactive_task_frame_handler)]) msymbol_cbs = MinimalSymbolCallbacks([('thread_return', x86_64Architecture.setup_thread_return_handler)]) register_arch(x86_64Architecture)