1#!/usr/bin/env python3 2# 3# Copyright (c) 2020 Intel Corporation 4# 5# SPDX-License-Identifier: Apache-2.0 6 7import binascii 8import logging 9import struct 10 11from gdbstubs.gdbstub import GdbStub 12 13 14logger = logging.getLogger("gdbstub") 15 16 17class RegNum(): 18 # Matches the enum amd64_regnum in GDB 19 RAX = 0 20 RBX = 1 21 RCX = 2 22 RDX = 3 23 RSI = 4 24 RDI = 5 25 RBP = 6 26 RSP = 7 27 R8 = 8 28 R9 = 9 29 R10 = 10 30 R11 = 11 31 R12 = 12 32 R13 = 13 33 R14 = 14 34 R15 = 15 35 RIP = 16 36 EFLAGS = 17 37 CS = 18 38 SS = 19 39 DS = 20 40 ES = 21 41 FS = 22 42 GS = 23 43 FS_BASE = 24 44 GS_BASE = 25 45 K_GS_BASE = 26 46 47 48class ExceptionVectors(): 49 # Matches arch/x86/include/kernel_arch_data.h 50 IV_DIVIDE_ERROR = 0 51 IV_DEBUG = 1 52 IV_NON_MASKABLE_INTERRUPT = 2 53 IV_BREAKPOINT = 3 54 IV_OVERFLOW = 4 55 IV_BOUND_RANGE = 5 56 IV_INVALID_OPCODE = 6 57 IV_DEVICE_NOT_AVAILABLE = 7 58 IV_DOUBLE_FAULT = 8 59 IV_COPROC_SEGMENT_OVERRUN = 9 60 IV_INVALID_TSS = 10 61 IV_SEGMENT_NOT_PRESENT = 11 62 IV_STACK_FAULT = 12 63 IV_GENERAL_PROTECTION = 13 64 IV_PAGE_FAULT = 14 65 IV_RESERVED = 15 66 IV_X87_FPU_FP_ERROR = 16 67 IV_ALIGNMENT_CHECK = 17 68 IV_MACHINE_CHECK = 18 69 IV_SIMD_FP = 19 70 IV_VIRT_EXCEPTION = 20 71 IV_SECURITY_EXCEPTION = 30 72 73 74class GdbStub_x86_64(GdbStub): 75 GDB_SIGNAL_DEFAULT = 7 76 77 # Mapping is from GDB's gdb/i386-stubs.c 78 GDB_SIGNAL_MAPPING = { 79 ExceptionVectors.IV_DIVIDE_ERROR: 8, 80 ExceptionVectors.IV_DEBUG: 5, 81 ExceptionVectors.IV_BREAKPOINT: 5, 82 ExceptionVectors.IV_OVERFLOW: 16, 83 ExceptionVectors.IV_BOUND_RANGE: 16, 84 ExceptionVectors.IV_INVALID_OPCODE: 4, 85 ExceptionVectors.IV_DEVICE_NOT_AVAILABLE: 8, 86 ExceptionVectors.IV_DOUBLE_FAULT: 7, 87 ExceptionVectors.IV_COPROC_SEGMENT_OVERRUN: 11, 88 ExceptionVectors.IV_INVALID_TSS: 11, 89 ExceptionVectors.IV_SEGMENT_NOT_PRESENT: 11, 90 ExceptionVectors.IV_STACK_FAULT: 11, 91 ExceptionVectors.IV_GENERAL_PROTECTION: 11, 92 ExceptionVectors.IV_PAGE_FAULT: 11, 93 ExceptionVectors.IV_X87_FPU_FP_ERROR: 7, 94 } 95 96 GDB_G_PKT_NUM_REGS = 34 97 98 GDB_32BIT_REGS = { 99 RegNum.EFLAGS, 100 RegNum.CS, 101 RegNum.SS, 102 RegNum.DS, 103 RegNum.ES, 104 RegNum.FS, 105 RegNum.GS, 106 } 107 108 def __init__(self, logfile, elffile): 109 super().__init__(logfile=logfile, elffile=elffile) 110 self.registers = None 111 self.exception_vector = None 112 self.exception_code = None 113 self.gdb_signal = self.GDB_SIGNAL_DEFAULT 114 115 self.parse_arch_data_block() 116 self.compute_signal() 117 118 def parse_arch_data_block(self): 119 arch_data_blk = self.logfile.get_arch_data()['data'] 120 121 arch_data_blk_struct = "<QQQQQQQQQQQQQQQQQQQQQQ" 122 cfg_exception_debug = True 123 if len(arch_data_blk) != struct.calcsize(arch_data_blk_struct): 124 # There are fewer registers dumped 125 # when CONFIG_EXCEPTION_DEBUG=n 126 arch_data_blk_struct = "<QQQQQQQQQQQQQQQQQ" 127 cfg_exception_debug = False 128 129 tu = struct.unpack(arch_data_blk_struct, arch_data_blk) 130 131 self.registers = dict() 132 133 self.exception_vector = tu[0] 134 self.exception_code = tu[1] 135 136 self.registers[RegNum.RAX] = tu[2] 137 self.registers[RegNum.RCX] = tu[3] 138 self.registers[RegNum.RDX] = tu[4] 139 self.registers[RegNum.RSI] = tu[5] 140 self.registers[RegNum.RDI] = tu[6] 141 self.registers[RegNum.RSP] = tu[7] 142 self.registers[RegNum.R8 ] = tu[8] 143 self.registers[RegNum.R9 ] = tu[9] 144 self.registers[RegNum.R10] = tu[10] 145 self.registers[RegNum.R11] = tu[11] 146 self.registers[RegNum.RIP] = tu[12] 147 self.registers[RegNum.EFLAGS] = tu[13] 148 self.registers[RegNum.CS] = tu[14] 149 self.registers[RegNum.SS] = tu[15] 150 self.registers[RegNum.RBP] = tu[16] 151 152 if cfg_exception_debug: 153 self.registers[RegNum.RBX] = tu[17] 154 self.registers[RegNum.R12] = tu[18] 155 self.registers[RegNum.R13] = tu[19] 156 self.registers[RegNum.R14] = tu[20] 157 self.registers[RegNum.R15] = tu[21] 158 159 def compute_signal(self): 160 sig = self.GDB_SIGNAL_DEFAULT 161 vector = self.exception_vector 162 163 if vector is None: 164 sig = self.GDB_SIGNAL_DEFAULT 165 166 # Map vector number to GDB signal number 167 if vector in self.GDB_SIGNAL_MAPPING: 168 sig = self.GDB_SIGNAL_MAPPING[vector] 169 170 self.gdb_signal = sig 171 172 def handle_register_group_read_packet(self): 173 idx = 0 174 pkt = b'' 175 176 while idx < self.GDB_G_PKT_NUM_REGS: 177 if idx in self.GDB_32BIT_REGS: 178 reg_fmt = "<I" 179 reg_bytes = 4 180 else: 181 reg_fmt = "<Q" 182 reg_bytes = 8 183 184 if idx in self.registers: 185 bval = struct.pack(reg_fmt, self.registers[idx]) 186 pkt += binascii.hexlify(bval) 187 else: 188 # Register not in coredump -> unknown value 189 # Send in "xxxxxxxx" 190 pkt += b'x' * (reg_bytes * 2) 191 192 idx += 1 193 194 self.put_gdb_packet(pkt) 195 196 def handle_register_single_read_packet(self, pkt): 197 # Mark registers as "<unavailable>". 198 # 'p' packets are usually used for registers 199 # other than the general ones (e.g. eax, ebx) 200 # so we can safely reply "xxxxxxxx" here. 201 self.put_gdb_packet(b'x' * 16) 202