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:
Mark Holden 2024-06-24 13:24:07 -07:00 committed by Anas Nashif
parent 0b9b33c540
commit a56e2f86cc
1 changed files with 64 additions and 3 deletions

View File

@ -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)