feature(gdbstub): Move runtime gdbstub out of panic config

Closes https://github.com/espressif/esp-idf/pull/11569
This commit is contained in:
Alexey Lapshin
2023-07-27 23:35:44 +04:00
parent cfa1896780
commit 47e400c296
11 changed files with 148 additions and 49 deletions

View File

@@ -1,15 +1,24 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import os
import os.path as path
import sys
import pytest
sys.path.append(os.path.expandvars(os.path.join('$IDF_PATH', 'tools', 'test_apps', 'system', 'panic')))
sys.path.append(path.expandvars(path.join('$IDF_PATH', 'tools', 'test_apps', 'system', 'panic')))
from test_panic_util import PanicTestDut # noqa: E402
def get_line_number(lookup: str, offset: int = 0) -> int:
src_file = path.join(path.dirname(path.abspath(__file__)), 'main', 'test_app_main.c')
with open(src_file) as f:
for num, line in enumerate(f, 1):
if lookup in line:
return num + offset
return -1
@pytest.mark.supported_targets
@pytest.mark.generic
def test_gdbstub_runtime(dut: PanicTestDut) -> None:
@@ -18,21 +27,21 @@ def test_gdbstub_runtime(dut: PanicTestDut) -> None:
dut.start_gdb()
# Test breakpoint
cmd = '-break-insert --source test_app_main.c --line 23'
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))
assert response is not None
cmd = '-exec-continue'
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):
# does not stoped on breakpoint yet
# have not stopped on breakpoint yet
responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
assert dut.find_gdb_response('stopped', 'notify', responses) is not None
payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
assert payload['reason'] == 'breakpoint-hit'
assert payload['bkptno'] == '1'
assert payload['frame']['func'] == 'app_main'
assert payload['frame']['line'] == '23'
assert payload['frame']['line'] == str(get_line_number('label_1:', 1))
assert payload['stopped-threads'] == 'all'
# Test step command
@@ -40,13 +49,13 @@ def test_gdbstub_runtime(dut: PanicTestDut) -> None:
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):
# does not stoped on breakpoint yet
# have not stopped on breakpoint yet
responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
assert dut.find_gdb_response('stopped', 'notify', responses) is not None
payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
assert payload['reason'] == 'end-stepping-range'
assert payload['frame']['func'] == 'foo'
assert payload['frame']['line'] == '14'
assert payload['frame']['line'] == str(get_line_number('var_2+=2;'))
assert payload['stopped-threads'] == 'all'
# Test finish command
@@ -54,26 +63,36 @@ def test_gdbstub_runtime(dut: PanicTestDut) -> None:
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):
# does not stoped on breakpoint yet
# have not stopped on breakpoint yet
responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
assert dut.find_gdb_response('stopped', 'notify', responses) is not None
payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
assert payload['reason'] == 'function-finished'
assert payload['frame']['line'] == '23'
# On riscv we may have situation when returned from a function but stay on exactly the same line
# foo();
# 4200ae5c: f99ff0ef jal ra,4200adf4 <foo>
# 4200ae60: a011 j 4200ae64 <app_main+0x4e> <----------- here after return from foo()
# }
assert payload['frame']['line'] == str(get_line_number('label_3:', 1) if dut.is_xtensa else get_line_number('foo();', 0))
assert payload['frame']['func'] == 'app_main'
assert payload['stopped-threads'] == 'all'
cmd = '-exec-continue'
responses = dut.gdb_write(cmd)
assert dut.find_gdb_response('running', 'result', responses) is not None
assert dut.find_gdb_response('running', 'notify', responses) is not None
# Test next command
cmd = '-exec-next'
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):
# does not stoped on breakpoint yet
# have not stopped on breakpoint yet
responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
assert dut.find_gdb_response('stopped', 'notify', responses) is not None
payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
assert payload['reason'] == 'end-stepping-range'
assert payload['frame']['line'] == '21'
assert payload['frame']['line'] == str(get_line_number('label_3:', 1))
assert payload['frame']['func'] == 'app_main'
assert payload['stopped-threads'] == 'all'
@@ -100,7 +119,7 @@ def test_gdbstub_runtime(dut: PanicTestDut) -> None:
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):
# does not stoped on breakpoint yet
# have not stopped on breakpoint yet
responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
assert payload['reason'] == 'signal-received'
@@ -111,3 +130,83 @@ def test_gdbstub_runtime(dut: PanicTestDut) -> None:
# assert payload['reason'] == 'watchpoint-trigger'
# assert int(payload['value']['new']) == int(payload['value']['old']) + 1
# assert payload['frame']['line'] == '14'
cmd = '-break-delete 2'
responses = dut.gdb_write(cmd)
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
# test panic handling
cmd = '-exec-continue'
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
responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
assert payload['reason'] == 'signal-received'
assert payload['signal-name'] == 'SIGSEGV'
assert payload['frame']['func'] == 'app_main'
assert payload['frame']['line'] == str(get_line_number('label_5', 1))
assert payload['stopped-threads'] == 'all'
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32s3
@pytest.mark.generic
@pytest.mark.temp_skip_ci(targets=['esp32s3'], reason='fix IDF-7927')
def test_gdbstub_runtime_xtensa_stepping_bug(dut: PanicTestDut) -> None:
dut.expect_exact('tested app is runnig.')
dut.write(b'\x03') # send Ctrl-C
dut.start_gdb()
# 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))
assert response is not None
cmd = '-exec-continue'
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
responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
assert dut.find_gdb_response('stopped', 'notify', responses) is not None
payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
assert payload['reason'] == 'breakpoint-hit'
assert payload['bkptno'] == '1'
assert payload['frame']['func'] == 'app_main'
assert payload['frame']['line'] == str(get_line_number('label_1:', 1))
assert payload['stopped-threads'] == 'all'
# Test step command
cmd = '-exec-step'
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
responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
assert dut.find_gdb_response('stopped', 'notify', responses) is not None
payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
assert payload['reason'] == 'end-stepping-range'
assert payload['frame']['func'] == 'foo'
assert payload['frame']['line'] == str(get_line_number('var_2+=2;'))
assert payload['stopped-threads'] == 'all'
# Test next command
cmd = '-exec-next'
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
responses = dut.gdbmi.get_gdb_response(timeout_sec=3)
assert dut.find_gdb_response('stopped', 'notify', responses) is not None
payload = dut.find_gdb_response('stopped', 'notify', responses)['payload']
assert payload['reason'] == 'end-stepping-range'
assert payload['frame']['line'] == str(get_line_number('var_2--;', 0))
assert payload['frame']['func'] == 'foo'
assert payload['stopped-threads'] == 'all'