From 9220eea4e4c5a23adf43d7d57c55c4a5440edaae Mon Sep 17 00:00:00 2001 From: Alexey Lapshin Date: Wed, 19 Apr 2023 15:36:26 +0800 Subject: [PATCH] test: gdbstub_runtime: initial commit --- tools/test_apps/.build-test-rules.yml | 6 + .../system/gdbstub_runtime/CMakeLists.txt | 8 ++ .../system/gdbstub_runtime/README.md | 2 + .../system/gdbstub_runtime/conftest.py | 26 ++++ .../gdbstub_runtime/main/CMakeLists.txt | 3 + .../gdbstub_runtime/main/test_app_main.c | 26 ++++ .../system/gdbstub_runtime/pytest_runtime.py | 114 ++++++++++++++++++ .../system/gdbstub_runtime/sdkconfig.defaults | 2 + 8 files changed, 187 insertions(+) create mode 100644 tools/test_apps/system/gdbstub_runtime/CMakeLists.txt create mode 100644 tools/test_apps/system/gdbstub_runtime/README.md create mode 100644 tools/test_apps/system/gdbstub_runtime/conftest.py create mode 100644 tools/test_apps/system/gdbstub_runtime/main/CMakeLists.txt create mode 100644 tools/test_apps/system/gdbstub_runtime/main/test_app_main.c create mode 100644 tools/test_apps/system/gdbstub_runtime/pytest_runtime.py create mode 100644 tools/test_apps/system/gdbstub_runtime/sdkconfig.defaults diff --git a/tools/test_apps/.build-test-rules.yml b/tools/test_apps/.build-test-rules.yml index 7ea0994d55..a0d6b22dd5 100644 --- a/tools/test_apps/.build-test-rules.yml +++ b/tools/test_apps/.build-test-rules.yml @@ -130,6 +130,12 @@ tools/test_apps/system/gdb_loadable_elf: temporary: true reason: target esp32c6, esp32h2 is not supported yet +tools/test_apps/system/gdbstub_runtime: + disable_test: + - if: IDF_TARGET in ["esp32c2", "esp32h2"] + temporary: true + reason: resolve IDF-7264 + tools/test_apps/system/longjmp_test: enable: - if: IDF_TARGET in ["esp32", "esp32s2", "esp32s3"] diff --git a/tools/test_apps/system/gdbstub_runtime/CMakeLists.txt b/tools/test_apps/system/gdbstub_runtime/CMakeLists.txt new file mode 100644 index 0000000000..d6b8539cb6 --- /dev/null +++ b/tools/test_apps/system/gdbstub_runtime/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(COMPONENTS main) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_gdbstub_runtime) diff --git a/tools/test_apps/system/gdbstub_runtime/README.md b/tools/test_apps/system/gdbstub_runtime/README.md new file mode 100644 index 0000000000..a8b7833fa3 --- /dev/null +++ b/tools/test_apps/system/gdbstub_runtime/README.md @@ -0,0 +1,2 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | diff --git a/tools/test_apps/system/gdbstub_runtime/conftest.py b/tools/test_apps/system/gdbstub_runtime/conftest.py new file mode 100644 index 0000000000..986d24ae12 --- /dev/null +++ b/tools/test_apps/system/gdbstub_runtime/conftest.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 + +# pylint: disable=W0621 # redefined-outer-name + +import os +import sys + +import pytest +from _pytest.fixtures import FixtureRequest +from _pytest.monkeypatch import MonkeyPatch + +sys.path.append(os.path.expandvars(os.path.join('$IDF_PATH', 'tools', 'test_apps', 'system', 'panic'))) +from test_panic_util import PanicTestDut # noqa: E402 + + +@pytest.fixture(scope='module') +def monkeypatch_module(request: FixtureRequest) -> MonkeyPatch: + mp = MonkeyPatch() + request.addfinalizer(mp.undo) + return mp + + +@pytest.fixture(scope='module', autouse=True) +def replace_dut_class(monkeypatch_module: MonkeyPatch) -> None: + monkeypatch_module.setattr('pytest_embedded_idf.IdfDut', PanicTestDut) diff --git a/tools/test_apps/system/gdbstub_runtime/main/CMakeLists.txt b/tools/test_apps/system/gdbstub_runtime/main/CMakeLists.txt new file mode 100644 index 0000000000..c1aeb15ca9 --- /dev/null +++ b/tools/test_apps/system/gdbstub_runtime/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "test_app_main.c" + INCLUDE_DIRS "" + REQUIRES esp_gdbstub) diff --git a/tools/test_apps/system/gdbstub_runtime/main/test_app_main.c b/tools/test_apps/system/gdbstub_runtime/main/test_app_main.c new file mode 100644 index 0000000000..341bd254bf --- /dev/null +++ b/tools/test_apps/system/gdbstub_runtime/main/test_app_main.c @@ -0,0 +1,26 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +int var_1; +int var_2; + +void foo(void) +{ + var_2++; +} + +void app_main(void) +{ + printf("tested app is runnig.\n"); + while(1) { + var_1++; + if (var_1 % 10 == 0) { + foo(); + } + } +} diff --git a/tools/test_apps/system/gdbstub_runtime/pytest_runtime.py b/tools/test_apps/system/gdbstub_runtime/pytest_runtime.py new file mode 100644 index 0000000000..864828e498 --- /dev/null +++ b/tools/test_apps/system/gdbstub_runtime/pytest_runtime.py @@ -0,0 +1,114 @@ +# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import os +import sys + +import pytest + +sys.path.append(os.path.expandvars(os.path.join('$IDF_PATH', 'tools', 'test_apps', 'system', 'panic'))) +from test_panic_util import PanicTestDut # noqa: E402 + + +@pytest.mark.supported_targets +@pytest.mark.temp_skip_ci(targets=['esp32c2', 'esp32h2'], reason='resolve IDF-7264') +@pytest.mark.generic +def test_gdbstub_runtime(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 --line 23' + 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 + 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['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): + # does not stoped 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['stopped-threads'] == 'all' + + # Test finish command + cmd = '-exec-finish' + 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 + 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' + assert payload['frame']['func'] == 'app_main' + 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): + # does not stoped 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']['func'] == 'app_main' + assert payload['stopped-threads'] == 'all' + + # test delete breakpoint + cmd = '-break-delete 1' + responses = dut.gdb_write(cmd) + assert dut.find_gdb_response('done', 'result', responses) is not None + 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 ctrl-c + responses = dut.gdbmi.send_signal_to_gdb(2) + # assert dut.find_gdb_response('stopped', 'notify', responses) is not None + # ?? No response? check we stopped + dut.gdb_backtrace() + + # test watchpoint + cmd = '-break-watch var_2' + responses = dut.gdb_write(cmd) + assert dut.find_gdb_response('done', 'result', responses) 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 + 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['frame']['func'] == 'foo' + assert payload['stopped-threads'] == 'all' + # Uncomment this when implement send reason to gdb: GCC-313 + # + # assert payload['reason'] == 'watchpoint-trigger' + # assert int(payload['value']['new']) == int(payload['value']['old']) + 1 + # assert payload['frame']['line'] == '14' diff --git a/tools/test_apps/system/gdbstub_runtime/sdkconfig.defaults b/tools/test_apps/system/gdbstub_runtime/sdkconfig.defaults new file mode 100644 index 0000000000..9895931bc7 --- /dev/null +++ b/tools/test_apps/system/gdbstub_runtime/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME=y +CONFIG_ESP_GDBSTUB_SUPPORT_TASKS=y