mirror of
https://github.com/espressif/esp-idf.git
synced 2025-10-19 09:41:20 +00:00
feat(gdbstub): add f- and q-registers support
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
import os
|
||||
import os.path as path
|
||||
import sys
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
@@ -23,12 +23,12 @@ def get_line_number(lookup: str, offset: int = 0) -> int:
|
||||
|
||||
|
||||
def start_gdb(dut: PanicTestDut) -> None:
|
||||
dut.expect_exact('tested app is running.')
|
||||
dut.expect_exact('waiting start_testing variable to be changed.')
|
||||
dut.write(b'\x03') # send Ctrl-C
|
||||
dut.start_gdb_for_gdbstub()
|
||||
|
||||
|
||||
def run_and_break(dut: PanicTestDut, cmd: str) -> Dict[Any, Any]:
|
||||
def run_and_break(dut: PanicTestDut, cmd: str) -> dict[Any, Any]:
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('running', 'result', responses) is not None
|
||||
if not dut.find_gdb_response('stopped', 'notify', responses): # have not stopped on breakpoint yet
|
||||
@@ -39,11 +39,37 @@ def run_and_break(dut: PanicTestDut, cmd: str) -> Dict[Any, Any]:
|
||||
return payload
|
||||
|
||||
|
||||
def dut_set_variable(dut: PanicTestDut, var_name: str, value: int) -> None:
|
||||
cmd = f'-gdb-set {var_name}={value}'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
|
||||
def dut_enable_test(dut: PanicTestDut, testcase: str | None = None) -> None:
|
||||
dut_set_variable(dut, 'start_testing', 1)
|
||||
|
||||
# enable specific testcase (otherwise default testcase)
|
||||
if testcase:
|
||||
dut_set_variable(dut, f'do_test_{testcase}', 1)
|
||||
|
||||
|
||||
def dut_get_threads(dut: PanicTestDut) -> Any:
|
||||
cmd = '-thread-info'
|
||||
responses = dut.gdb_write(cmd)
|
||||
if not responses[0]['message']:
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert responses is not None
|
||||
return responses[0]['payload']['threads']
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
|
||||
def test_hwloop_jump(dut: PanicTestDut) -> None:
|
||||
start_gdb(dut)
|
||||
|
||||
# enable coprocessors registers testing
|
||||
dut_enable_test(dut, 'xesppie_loops')
|
||||
|
||||
cmd = '-break-insert --source xesppie_loops.S --function test_loop_start'
|
||||
response = dut.find_gdb_response('done', 'result', dut.gdb_write(cmd))
|
||||
assert response is not None
|
||||
@@ -98,11 +124,153 @@ def test_hwloop_jump(dut: PanicTestDut) -> None:
|
||||
assert payload['stopped-threads'] == 'all'
|
||||
|
||||
|
||||
def check_registers_numbers(dut: PanicTestDut) -> None:
|
||||
cmd = '-data-list-register-values d'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
registers = responses[0]['payload']['register-values']
|
||||
assert len(registers) == 83 # 80 registers supported + xesppie misc + pseudo frm, fflags
|
||||
|
||||
r_id = 0
|
||||
for r in registers:
|
||||
assert int(r['number']) == r_id
|
||||
|
||||
if r_id == 4211: # check if value of q0 register is uint128
|
||||
assert 'uint128' in r['value']
|
||||
|
||||
if r_id == 64:
|
||||
r_id = 68 # fcsr
|
||||
elif r_id == 68:
|
||||
r_id = 4211 # q0
|
||||
else:
|
||||
r_id += 1
|
||||
|
||||
|
||||
def set_float_registers(dut: PanicTestDut, t_id: int, addition: int) -> None:
|
||||
cmd = f'-thread-select {t_id}'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
for i in range(32):
|
||||
cmd = f'-data-write-register-values d {33 + i} {i + addition}'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
# Note that it's a gap between the last floating register number and fcsr register number.
|
||||
cmd = f'-data-write-register-values d 68 {32 + addition}'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
|
||||
def set_pie_registers(dut: PanicTestDut, t_id: int, addition: int) -> None:
|
||||
cmd = f'-thread-select {t_id}'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
def set_gdb_128_bit_register(reg: str, byte: int) -> None:
|
||||
val64 = f'0x{hex(byte)[2:] * 8}'
|
||||
value = f'{{{val64}, {val64}}}'
|
||||
cmd = f'-interpreter-exec console "set ${reg}.v2_int64={value}"'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
for i in range(8):
|
||||
set_gdb_128_bit_register(f'q{i}', 0x10 + i + addition)
|
||||
|
||||
set_gdb_128_bit_register('qacc_l_l', 0x18 + addition)
|
||||
set_gdb_128_bit_register('qacc_l_h', 0x19 + addition)
|
||||
set_gdb_128_bit_register('qacc_h_l', 0x1A + addition)
|
||||
set_gdb_128_bit_register('qacc_h_h', 0x1B + addition)
|
||||
set_gdb_128_bit_register('ua_state', 0x1C + addition)
|
||||
|
||||
xacc_val = ','.join([hex(0x1D + addition)] * 5)
|
||||
cmd = f'-interpreter-exec console "set $xacc={{{xacc_val}}}"'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
|
||||
def coproc_registers_test(dut: PanicTestDut, regs_type: str, set_registers: Callable) -> None:
|
||||
# set start test breakpoint
|
||||
cmd = f'-break-insert --source coproc_regs.c --function test_{regs_type} --label {regs_type}_start'
|
||||
response = dut.find_gdb_response('done', 'result', dut.gdb_write(cmd))
|
||||
assert response is not None
|
||||
|
||||
# stop when the second task is stopped
|
||||
for i in range(2):
|
||||
cmd = '-exec-continue'
|
||||
payload = run_and_break(dut, cmd)
|
||||
assert payload['reason'] == 'breakpoint-hit'
|
||||
assert payload['frame']['func'] == f'test_{regs_type}'
|
||||
assert payload['stopped-threads'] == 'all'
|
||||
|
||||
threads = dut_get_threads(dut)
|
||||
|
||||
"""
|
||||
Set expected values to both testing tasks.
|
||||
This will test setting register for both:
|
||||
- Task coproc owner (direct registers write)
|
||||
- Other tasks (write registers to task's stack)
|
||||
"""
|
||||
coproc_tasks = [f'test_{regs_type}_1', f'test_{regs_type}_2']
|
||||
found_tasks = [False] * len(coproc_tasks)
|
||||
for t in threads:
|
||||
for index, test in enumerate(coproc_tasks):
|
||||
if test in t['details']:
|
||||
set_registers(dut, t['id'], index + 1)
|
||||
found_tasks[index] = True
|
||||
|
||||
assert all(found_tasks)
|
||||
|
||||
dut_set_variable(dut, f'test_{regs_type}_ready', 1)
|
||||
|
||||
cmd = '-break-delete'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
cmd = f'-break-insert --source coproc_regs.c --function test_coproc_regs --label {regs_type}_succeed'
|
||||
response = dut.find_gdb_response('done', 'result', dut.gdb_write(cmd))
|
||||
assert response is not None
|
||||
|
||||
cmd = '-exec-continue'
|
||||
payload = run_and_break(dut, cmd)
|
||||
assert payload['reason'] == 'breakpoint-hit'
|
||||
assert payload['frame']['func'] == 'test_coproc_regs'
|
||||
assert payload['stopped-threads'] == 'all'
|
||||
|
||||
threads = dut_get_threads(dut)
|
||||
|
||||
found_tasks = [False] * len(coproc_tasks)
|
||||
for t in threads:
|
||||
for index, test in enumerate(coproc_tasks):
|
||||
if test in t['details']:
|
||||
found_tasks[index] = True
|
||||
|
||||
assert not any(found_tasks)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
|
||||
def test_coproc_registers(dut: PanicTestDut) -> None:
|
||||
start_gdb(dut)
|
||||
|
||||
# enable coprocessors registers testing
|
||||
dut_enable_test(dut, 'coproc_regs')
|
||||
|
||||
check_registers_numbers(dut)
|
||||
|
||||
coproc_registers_test(dut, 'fpu', set_float_registers)
|
||||
if dut.target == 'esp32p4':
|
||||
coproc_registers_test(dut, 'pie', set_pie_registers)
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('target', ['supported_targets'], indirect=['target'])
|
||||
def test_gdbstub_runtime(dut: PanicTestDut) -> None:
|
||||
start_gdb(dut)
|
||||
|
||||
dut_enable_test(dut)
|
||||
|
||||
# Test breakpoint
|
||||
cmd = '-break-insert --source test_app_main.c --function app_main --label label_1'
|
||||
response = dut.find_gdb_response('done', 'result', dut.gdb_write(cmd))
|
||||
@@ -187,9 +355,7 @@ def test_gdbstub_runtime(dut: PanicTestDut) -> None:
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
|
||||
# test set variable
|
||||
cmd = '-gdb-set do_panic=1'
|
||||
responses = dut.gdb_write(cmd)
|
||||
assert dut.find_gdb_response('done', 'result', responses) is not None
|
||||
dut_set_variable(dut, 'do_panic', 1)
|
||||
|
||||
# test panic handling
|
||||
cmd = '-exec-continue'
|
||||
@@ -207,6 +373,8 @@ def test_gdbstub_runtime(dut: PanicTestDut) -> None:
|
||||
def test_gdbstub_runtime_xtensa_stepping_bug(dut: PanicTestDut) -> None:
|
||||
start_gdb(dut)
|
||||
|
||||
dut_enable_test(dut)
|
||||
|
||||
# Test breakpoint
|
||||
cmd = '-break-insert --source test_app_main.c --function app_main --label label_1'
|
||||
response = dut.find_gdb_response('done', 'result', dut.gdb_write(cmd))
|
||||
|
Reference in New Issue
Block a user