Procházet zdrojové kódy

test: gdbstub_runtime: initial commit

Alexey Lapshin před 2 roky
rodič
revize
9220eea4e4

+ 6 - 0
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"]

+ 8 - 0
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)

+ 2 - 0
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 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |

+ 26 - 0
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)

+ 3 - 0
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)

+ 26 - 0
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 <stdio.h>
+
+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();
+        }
+    }
+}

+ 114 - 0
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'

+ 2 - 0
tools/test_apps/system/gdbstub_runtime/sdkconfig.defaults

@@ -0,0 +1,2 @@
+CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME=y
+CONFIG_ESP_GDBSTUB_SUPPORT_TASKS=y