coredump: Enable thread understanding for arm cortex m
Add support in arm_cortex_m python script to read thread registers off of a thread's stack when switching context. When CONFIG_ARM_STORE_EXC_RETURN is enabled, check the exc_return value in thread's arch struct to determine accurately where the stack pointer is. Also, set r7 (the frame pointer register) in case the frame pointer is not omitted. Only 8 registers are read from the top of the stack for other threads present in the dump. So update the script to reflect that. Signed-off-by: Mark Holden <mholden@meta.com>
This commit is contained in:
parent
0b9b33c540
commit
a56e2f86cc
|
@ -8,6 +8,7 @@ import binascii
|
|||
import logging
|
||||
import struct
|
||||
|
||||
from coredump_parser.elf_parser import ThreadInfoOffset
|
||||
from gdbstubs.gdbstub import GdbStub
|
||||
|
||||
|
||||
|
@ -80,15 +81,15 @@ class GdbStub_ARM_CortexM(GdbStub):
|
|||
self.registers[RegNum.R10] = tu[15]
|
||||
self.registers[RegNum.R11] = tu[16]
|
||||
|
||||
def handle_register_group_read_packet(self):
|
||||
def send_registers_packet(self, registers):
|
||||
reg_fmt = "<I"
|
||||
|
||||
idx = 0
|
||||
pkt = b''
|
||||
|
||||
while idx < self.GDB_G_PKT_NUM_REGS:
|
||||
if idx in self.registers:
|
||||
bval = struct.pack(reg_fmt, self.registers[idx])
|
||||
if idx in registers:
|
||||
bval = struct.pack(reg_fmt, registers[idx])
|
||||
pkt += binascii.hexlify(bval)
|
||||
else:
|
||||
# Register not in coredump -> unknown value
|
||||
|
@ -99,6 +100,12 @@ class GdbStub_ARM_CortexM(GdbStub):
|
|||
|
||||
self.put_gdb_packet(pkt)
|
||||
|
||||
def handle_register_group_read_packet(self):
|
||||
if not self.elffile.has_kernel_thread_info():
|
||||
self.send_registers_packet(self.registers)
|
||||
else:
|
||||
self.handle_thread_register_group_read_packet()
|
||||
|
||||
def handle_register_single_read_packet(self, pkt):
|
||||
# Mark registers as "<unavailable>".
|
||||
# 'p' packets are usually used for registers
|
||||
|
@ -111,3 +118,57 @@ class GdbStub_ARM_CortexM(GdbStub):
|
|||
reg = int(pkt_str[1:pkt_str.index('=')], 16)
|
||||
self.registers[reg] = int.from_bytes(binascii.unhexlify(pkt[3:]), byteorder = 'little')
|
||||
self.put_gdb_packet(b'+')
|
||||
|
||||
def arch_supports_thread_operations(self):
|
||||
return True
|
||||
|
||||
def handle_thread_register_group_read_packet(self):
|
||||
# For selected_thread 0, use the register data retrieved from the dump's arch section
|
||||
if self.selected_thread == 0:
|
||||
self.send_registers_packet(self.registers)
|
||||
else:
|
||||
thread_ptr = self.thread_ptrs[self.selected_thread]
|
||||
|
||||
# Get stack pointer out of thread struct
|
||||
t_stack_ptr_offset = self.elffile.get_kernel_thread_info_offset(ThreadInfoOffset.THREAD_INFO_OFFSET_T_STACK_PTR)
|
||||
size_t_size = self.elffile.get_kernel_thread_info_size_t_size()
|
||||
stack_ptr_bytes = self.get_memory(thread_ptr + t_stack_ptr_offset, size_t_size)
|
||||
|
||||
thread_registers = dict()
|
||||
|
||||
if stack_ptr_bytes is not None:
|
||||
# Read registers stored at top of stack
|
||||
stack_ptr = int.from_bytes(stack_ptr_bytes, "little")
|
||||
barray = self.get_memory(stack_ptr, (size_t_size * 8))
|
||||
|
||||
if barray is not None:
|
||||
tu = struct.unpack("<IIIIIIII", barray)
|
||||
thread_registers[RegNum.R0] = tu[0]
|
||||
thread_registers[RegNum.R1] = tu[1]
|
||||
thread_registers[RegNum.R2] = tu[2]
|
||||
thread_registers[RegNum.R3] = tu[3]
|
||||
thread_registers[RegNum.R12] = tu[4]
|
||||
thread_registers[RegNum.LR] = tu[5]
|
||||
thread_registers[RegNum.PC] = tu[6]
|
||||
thread_registers[RegNum.XPSR] = tu[7]
|
||||
|
||||
# Set SP to point to stack just after these registers
|
||||
thread_registers[RegNum.SP] = stack_ptr + 32
|
||||
|
||||
# Read the exc_return value from the thread's arch struct
|
||||
t_arch_offset = self.elffile.get_kernel_thread_info_offset(ThreadInfoOffset.THREAD_INFO_OFFSET_T_ARCH)
|
||||
t_exc_return_offset = self.elffile.get_kernel_thread_info_offset(ThreadInfoOffset.THREAD_INFO_OFFSET_T_ARM_EXC_RETURN)
|
||||
|
||||
# Value of 0xffffffff indicates THREAD_INFO_UNIMPLEMENTED
|
||||
if t_exc_return_offset != 0xffffffff:
|
||||
exc_return_bytes = self.get_memory(thread_ptr + t_arch_offset + t_exc_return_offset, 1)
|
||||
exc_return = int.from_bytes(exc_return_bytes, "little")
|
||||
|
||||
# If the bit 4 is not set, the stack frame is extended for floating point data, adjust the SP accordingly
|
||||
if (exc_return & (1 << 4)) == 0:
|
||||
thread_registers[RegNum.SP] = thread_registers[RegNum.SP] + 72
|
||||
|
||||
# Set R7 to match the stack pointer in case the frame pointer is not omitted
|
||||
thread_registers[RegNum.R7] = thread_registers[RegNum.SP]
|
||||
|
||||
self.send_registers_packet(thread_registers)
|
||||
|
|
Loading…
Reference in New Issue