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 coredump_parser.elf_parser import ThreadInfoOffset 12from gdbstubs.gdbstub import GdbStub 13 14 15logger = logging.getLogger("gdbstub") 16 17 18class RegNum(): 19 R0 = 0 20 R1 = 1 21 R2 = 2 22 R3 = 3 23 R4 = 4 24 R5 = 5 25 R6 = 6 26 R7 = 7 27 R8 = 8 28 R9 = 9 29 R10 = 10 30 R11 = 11 31 R12 = 12 32 SP = 13 33 LR = 14 34 PC = 15 35 XPSR = 16 36 37 38class GdbStub_ARM_CortexM(GdbStub): 39 ARCH_DATA_BLK_STRUCT = "<IIIIIIIII" 40 ARCH_DATA_BLK_STRUCT_V2 = "<IIIIIIIIIIIIIIIII" 41 42 GDB_SIGNAL_DEFAULT = 7 43 44 GDB_G_PKT_NUM_REGS = 17 45 46 def __init__(self, logfile, elffile): 47 super().__init__(logfile=logfile, elffile=elffile) 48 self.registers = None 49 self.gdb_signal = self.GDB_SIGNAL_DEFAULT 50 51 self.parse_arch_data_block() 52 53 def parse_arch_data_block(self): 54 arch_data_blk = self.logfile.get_arch_data()['data'] 55 arch_data_ver = self.logfile.get_arch_data()['hdr_ver'] 56 57 if arch_data_ver == 1: 58 tu = struct.unpack(self.ARCH_DATA_BLK_STRUCT, arch_data_blk) 59 elif arch_data_ver == 2: 60 tu = struct.unpack(self.ARCH_DATA_BLK_STRUCT_V2, arch_data_blk) 61 62 self.registers = dict() 63 64 self.registers[RegNum.R0] = tu[0] 65 self.registers[RegNum.R1] = tu[1] 66 self.registers[RegNum.R2] = tu[2] 67 self.registers[RegNum.R3] = tu[3] 68 self.registers[RegNum.R12] = tu[4] 69 self.registers[RegNum.LR] = tu[5] 70 self.registers[RegNum.PC] = tu[6] 71 self.registers[RegNum.XPSR] = tu[7] 72 self.registers[RegNum.SP] = tu[8] 73 74 if arch_data_ver > 1: 75 self.registers[RegNum.R4] = tu[9] 76 self.registers[RegNum.R5] = tu[10] 77 self.registers[RegNum.R6] = tu[11] 78 self.registers[RegNum.R7] = tu[12] 79 self.registers[RegNum.R8] = tu[13] 80 self.registers[RegNum.R9] = tu[14] 81 self.registers[RegNum.R10] = tu[15] 82 self.registers[RegNum.R11] = tu[16] 83 84 def send_registers_packet(self, registers): 85 reg_fmt = "<I" 86 87 idx = 0 88 pkt = b'' 89 90 while idx < self.GDB_G_PKT_NUM_REGS: 91 if idx in registers: 92 bval = struct.pack(reg_fmt, registers[idx]) 93 pkt += binascii.hexlify(bval) 94 else: 95 # Register not in coredump -> unknown value 96 # Send in "xxxxxxxx" 97 pkt += b'x' * 8 98 99 idx += 1 100 101 self.put_gdb_packet(pkt) 102 103 def handle_register_group_read_packet(self): 104 if not self.elffile.has_kernel_thread_info(): 105 self.send_registers_packet(self.registers) 106 else: 107 self.handle_thread_register_group_read_packet() 108 109 def handle_register_single_read_packet(self, pkt): 110 # Mark registers as "<unavailable>". 111 # 'p' packets are usually used for registers 112 # other than the general ones (e.g. eax, ebx) 113 # so we can safely reply "xxxxxxxx" here. 114 self.put_gdb_packet(b'x' * 8) 115 116 def handle_register_single_write_packet(self, pkt): 117 pkt_str = pkt.decode("ascii") 118 reg = int(pkt_str[1:pkt_str.index('=')], 16) 119 self.registers[reg] = int.from_bytes(binascii.unhexlify(pkt[3:]), byteorder = 'little') 120 self.put_gdb_packet(b'+') 121 122 def arch_supports_thread_operations(self): 123 return True 124 125 def handle_thread_register_group_read_packet(self): 126 # For selected_thread 0, use the register data retrieved from the dump's arch section 127 if self.selected_thread == 0: 128 self.send_registers_packet(self.registers) 129 else: 130 thread_ptr = self.thread_ptrs[self.selected_thread] 131 132 # Get stack pointer out of thread struct 133 t_stack_ptr_offset = self.elffile.get_kernel_thread_info_offset(ThreadInfoOffset.THREAD_INFO_OFFSET_T_STACK_PTR) 134 size_t_size = self.elffile.get_kernel_thread_info_size_t_size() 135 stack_ptr_bytes = self.get_memory(thread_ptr + t_stack_ptr_offset, size_t_size) 136 137 thread_registers = dict() 138 139 if stack_ptr_bytes is not None: 140 # Read registers stored at top of stack 141 stack_ptr = int.from_bytes(stack_ptr_bytes, "little") 142 barray = self.get_memory(stack_ptr, (size_t_size * 8)) 143 144 if barray is not None: 145 tu = struct.unpack("<IIIIIIII", barray) 146 thread_registers[RegNum.R0] = tu[0] 147 thread_registers[RegNum.R1] = tu[1] 148 thread_registers[RegNum.R2] = tu[2] 149 thread_registers[RegNum.R3] = tu[3] 150 thread_registers[RegNum.R12] = tu[4] 151 thread_registers[RegNum.LR] = tu[5] 152 thread_registers[RegNum.PC] = tu[6] 153 thread_registers[RegNum.XPSR] = tu[7] 154 155 # Set SP to point to stack just after these registers 156 thread_registers[RegNum.SP] = stack_ptr + 32 157 158 # Read the exc_return value from the thread's arch struct 159 t_arch_offset = self.elffile.get_kernel_thread_info_offset(ThreadInfoOffset.THREAD_INFO_OFFSET_T_ARCH) 160 t_exc_return_offset = self.elffile.get_kernel_thread_info_offset(ThreadInfoOffset.THREAD_INFO_OFFSET_T_ARM_EXC_RETURN) 161 162 # Value of 0xffffffff indicates THREAD_INFO_UNIMPLEMENTED 163 if t_exc_return_offset != 0xffffffff: 164 exc_return_bytes = self.get_memory(thread_ptr + t_arch_offset + t_exc_return_offset, 1) 165 exc_return = int.from_bytes(exc_return_bytes, "little") 166 167 # If the bit 4 is not set, the stack frame is extended for floating point data, adjust the SP accordingly 168 if (exc_return & (1 << 4)) == 0: 169 thread_registers[RegNum.SP] = thread_registers[RegNum.SP] + 72 170 171 # Set R7 to match the stack pointer in case the frame pointer is not omitted 172 thread_registers[RegNum.R7] = thread_registers[RegNum.SP] 173 174 self.send_registers_packet(thread_registers) 175