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 i386_regnum in GDB 19 EAX = 0 20 ECX = 1 21 EDX = 2 22 EBX = 3 23 ESP = 4 24 EBP = 5 25 ESI = 6 26 EDI = 7 27 EIP = 8 28 EFLAGS = 9 29 CS = 10 30 SS = 11 31 DS = 12 32 ES = 13 33 FS = 14 34 GS = 15 35 36 37class ExceptionVectors(): 38 # Matches arch/x86/include/kernel_arch_data.h 39 IV_DIVIDE_ERROR = 0 40 IV_DEBUG = 1 41 IV_NON_MASKABLE_INTERRUPT = 2 42 IV_BREAKPOINT = 3 43 IV_OVERFLOW = 4 44 IV_BOUND_RANGE = 5 45 IV_INVALID_OPCODE = 6 46 IV_DEVICE_NOT_AVAILABLE = 7 47 IV_DOUBLE_FAULT = 8 48 IV_COPROC_SEGMENT_OVERRUN = 9 49 IV_INVALID_TSS = 10 50 IV_SEGMENT_NOT_PRESENT = 11 51 IV_STACK_FAULT = 12 52 IV_GENERAL_PROTECTION = 13 53 IV_PAGE_FAULT = 14 54 IV_RESERVED = 15 55 IV_X87_FPU_FP_ERROR = 16 56 IV_ALIGNMENT_CHECK = 17 57 IV_MACHINE_CHECK = 18 58 IV_SIMD_FP = 19 59 IV_VIRT_EXCEPTION = 20 60 IV_SECURITY_EXCEPTION = 30 61 62 63class GdbStub_x86(GdbStub): 64 ARCH_DATA_BLK_STRUCT = "<IIIIIIIIIIIII" 65 66 GDB_SIGNAL_DEFAULT = 7 67 68 # Mapping is from GDB's gdb/i386-stubs.c 69 GDB_SIGNAL_MAPPING = { 70 ExceptionVectors.IV_DIVIDE_ERROR: 8, 71 ExceptionVectors.IV_DEBUG: 5, 72 ExceptionVectors.IV_BREAKPOINT: 5, 73 ExceptionVectors.IV_OVERFLOW: 16, 74 ExceptionVectors.IV_BOUND_RANGE: 16, 75 ExceptionVectors.IV_INVALID_OPCODE: 4, 76 ExceptionVectors.IV_DEVICE_NOT_AVAILABLE: 8, 77 ExceptionVectors.IV_DOUBLE_FAULT: 7, 78 ExceptionVectors.IV_COPROC_SEGMENT_OVERRUN: 11, 79 ExceptionVectors.IV_INVALID_TSS: 11, 80 ExceptionVectors.IV_SEGMENT_NOT_PRESENT: 11, 81 ExceptionVectors.IV_STACK_FAULT: 11, 82 ExceptionVectors.IV_GENERAL_PROTECTION: 11, 83 ExceptionVectors.IV_PAGE_FAULT: 11, 84 ExceptionVectors.IV_X87_FPU_FP_ERROR: 7, 85 } 86 87 GDB_G_PKT_NUM_REGS = 16 88 89 def __init__(self, logfile, elffile): 90 super().__init__(logfile=logfile, elffile=elffile) 91 self.registers = None 92 self.exception_vector = None 93 self.exception_code = None 94 self.gdb_signal = self.GDB_SIGNAL_DEFAULT 95 96 self.parse_arch_data_block() 97 self.compute_signal() 98 99 def parse_arch_data_block(self): 100 arch_data_blk = self.logfile.get_arch_data()['data'] 101 tu = struct.unpack(self.ARCH_DATA_BLK_STRUCT, arch_data_blk) 102 103 self.registers = dict() 104 105 self.exception_vector = tu[0] 106 self.exception_code = tu[1] 107 108 self.registers[RegNum.EAX] = tu[2] 109 self.registers[RegNum.ECX] = tu[3] 110 self.registers[RegNum.EDX] = tu[4] 111 self.registers[RegNum.EBX] = tu[5] 112 self.registers[RegNum.ESP] = tu[6] 113 self.registers[RegNum.EBP] = tu[7] 114 self.registers[RegNum.ESI] = tu[8] 115 self.registers[RegNum.EDI] = tu[9] 116 self.registers[RegNum.EIP] = tu[10] 117 self.registers[RegNum.EFLAGS] = tu[11] 118 self.registers[RegNum.CS] = tu[12] 119 120 def compute_signal(self): 121 sig = self.GDB_SIGNAL_DEFAULT 122 vector = self.exception_vector 123 124 if vector is None: 125 sig = self.GDB_SIGNAL_DEFAULT 126 127 # Map vector number to GDB signal number 128 if vector in self.GDB_SIGNAL_MAPPING: 129 sig = self.GDB_SIGNAL_MAPPING[vector] 130 131 self.gdb_signal = sig 132 133 def handle_register_group_read_packet(self): 134 reg_fmt = "<I" 135 136 idx = 0 137 pkt = b'' 138 139 while idx < self.GDB_G_PKT_NUM_REGS: 140 if idx in self.registers: 141 bval = struct.pack(reg_fmt, self.registers[idx]) 142 pkt += binascii.hexlify(bval) 143 else: 144 # Register not in coredump -> unknown value 145 # Send in "xxxxxxxx" 146 pkt += b'x' * 8 147 148 idx += 1 149 150 self.put_gdb_packet(pkt) 151 152 def handle_register_single_read_packet(self, pkt): 153 # Mark registers as "<unavailable>". 154 # 'p' packets are usually used for registers 155 # other than the general ones (e.g. eax, ebx) 156 # so we can safely reply "xxxxxxxx" here. 157 self.put_gdb_packet(b'x' * 8) 158