Skip to content

Commit

Permalink
tools: add test for ROM symbols in GDB
Browse files Browse the repository at this point in the history
  • Loading branch information
Lapshin committed Oct 3, 2022
1 parent 2e9f175 commit 7561367
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitlab/ci/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- "**/build*/flash_project_args"
- "**/build*/config/sdkconfig.json"
- "**/build*/bootloader/*.bin"
- "**/build*/bootloader/*.elf"
- "**/build*/partition_table/*.bin"
- $SIZE_INFO_LOCATION
when: always
Expand Down
8 changes: 8 additions & 0 deletions tools/idf_py_actions/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,11 @@

SUPPORTED_TARGETS = ['esp32', 'esp32s2', 'esp32c3', 'esp32s3', 'esp32c2']
PREVIEW_TARGETS = ['linux', 'esp32h2']

OPENOCD_TAGET_CONFIG_DEFAULT = '-f interface/ftdi/esp32_devkitj_v1.cfg -f target/{target}.cfg'
OPENOCD_TAGET_CONFIG: Dict[str, str] = {
'esp32': '-f board/esp32-wrover-kit-3.3v.cfg',
'esp32s2': '-f board/esp32s2-kaluga-1.cfg',
'esp32c3': '-f board/esp32c3-builtin.cfg',
'esp32s3': '-f board/esp32s3-builtin.cfg',
}
34 changes: 20 additions & 14 deletions tools/idf_py_actions/debug_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from typing import Any, Dict, List, Optional

from click.core import Context
from idf_py_actions.constants import OPENOCD_TAGET_CONFIG, OPENOCD_TAGET_CONFIG_DEFAULT
from idf_py_actions.errors import FatalError
from idf_py_actions.tools import PropertyDict, ensure_build_directory

Expand Down Expand Up @@ -59,6 +60,11 @@
'''


def get_openocd_arguments(target: str) -> str:
default_args = OPENOCD_TAGET_CONFIG_DEFAULT.format(target=target)
return str(OPENOCD_TAGET_CONFIG.get(target, default_args))


def action_extensions(base_actions: Dict, project_path: str) -> Dict:
OPENOCD_OUT_FILE = 'openocd_out.txt'
GDBGUI_OUT_FILE = 'gdbgui_out.txt'
Expand Down Expand Up @@ -286,21 +292,14 @@ def openocd(action: str, ctx: Context, args: PropertyDict, openocd_scripts: Opti
"""
Execute openocd as external tool
"""
OPENOCD_TAGET_CONFIG = {
'esp32': '-f board/esp32-wrover-kit-3.3v.cfg',
'esp32s2': '-f board/esp32s2-kaluga-1.cfg',
'esp32c3': '-f board/esp32c3-builtin.cfg',
'esp32s3': '-f board/esp32s3-builtin.cfg',
}
if os.getenv('OPENOCD_SCRIPTS') is None:
raise FatalError('OPENOCD_SCRIPTS not found in the environment: Please run export.sh/export.bat', ctx)
openocd_arguments = os.getenv('OPENOCD_COMMANDS') if openocd_commands is None else openocd_commands
project_desc = get_project_desc(args, ctx)
if openocd_arguments is None:
# use default value if commands not defined in the environment nor command line
target = project_desc['target']
default_args = '-f interface/ftdi/esp32_devkitj_v1.cfg -f target/{}.cfg'.format(target)
openocd_arguments = OPENOCD_TAGET_CONFIG.get(target, default_args)
openocd_arguments = get_openocd_arguments(target)
print('Note: OpenOCD cfg not found (via env variable OPENOCD_COMMANDS nor as a --openocd-commands argument)\n'
'OpenOCD arguments default to: "{}"'.format(openocd_arguments))
# script directory is taken from the environment by OpenOCD, update only if command line arguments to override
Expand Down Expand Up @@ -405,9 +404,9 @@ def gdbtui(action: str, ctx: Context, args: PropertyDict, gdbinit: str, require_
"""
Synchronous GDB target with text ui mode
"""
gdb(action, ctx, args, 1, gdbinit, require_openocd)
gdb(action, ctx, args, False, 1, gdbinit, require_openocd)

def gdb(action: str, ctx: Context, args: PropertyDict, gdb_tui: Optional[int], gdbinit: Optional[str], require_openocd: bool) -> None:
def gdb(action: str, ctx: Context, args: PropertyDict, batch: bool, gdb_tui: Optional[int], gdbinit: Optional[str], require_openocd: bool) -> None:
"""
Synchronous GDB target
"""
Expand All @@ -420,6 +419,8 @@ def gdb(action: str, ctx: Context, args: PropertyDict, gdb_tui: Optional[int], g
args = [gdb, *get_gdb_args(project_desc)]
if gdb_tui is not None:
args += ['-tui']
if batch:
args += ['--batch']
t = Thread(target=run_gdb, args=(args,))
t.start()
while True:
Expand Down Expand Up @@ -476,12 +477,17 @@ def gdb(action: str, ctx: Context, args: PropertyDict, gdb_tui: Optional[int], g
'callback': gdb,
'help': 'Run the GDB.',
'options': [
{
'names': ['--batch'],
'help': ('exit after processing gdbinit.\n'),
'hidden': True,
'is_flag': True,
'default': False,
},
{
'names': ['--gdb-tui', '--gdb_tui'],
'help':
('run gdb in TUI mode\n'),
'default':
None,
'help': ('run gdb in TUI mode\n'),
'default': None,
}, gdbinit, fail_if_openocd_failed
],
'order_dependencies': ['all', 'flash'],
Expand Down
6 changes: 6 additions & 0 deletions tools/test_apps/system/gdb/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# 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)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(gdb)
6 changes: 6 additions & 0 deletions tools/test_apps/system/gdb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |

# IDF GDB test application

This project tests if `idf.py gdb` works correct
3 changes: 3 additions & 0 deletions tools/test_apps/system/gdb/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
idf_component_register(SRCS "hello_world_main.c"
INCLUDE_DIRS "")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
46 changes: 46 additions & 0 deletions tools/test_apps/system/gdb/main/hello_world_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_chip_info.h"
#include "esp_flash.h"

void app_main(void)
{
printf("Hello world!\n");

/* Print chip information */
esp_chip_info_t chip_info;
uint32_t flash_size;
esp_chip_info(&chip_info);
printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
CONFIG_IDF_TARGET,
chip_info.cores,
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");

printf("silicon revision %d, ", chip_info.revision);
if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {
printf("Get flash size failed");
return;
}

printf("%uMB %s flash\n", flash_size / (1024 * 1024),
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");

printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());

for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");
fflush(stdout);
esp_restart();
}
53 changes: 53 additions & 0 deletions tools/test_apps/system/gdb/pytest_gdb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import os
import re
import signal
import subprocess
import sys

import pexpect
import pytest
from pytest_embedded import Dut

try:
from idf_py_actions.debug_ext import get_openocd_arguments
except ModuleNotFoundError:
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', '..'))
from idf_py_actions.debug_ext import get_openocd_arguments


@pytest.mark.supported_targets
@pytest.mark.test_jtag_arm
def test_idf_gdb(dut: Dut) -> None:
# Need to wait a moment to connect via OpenOCD after the hard reset happened.
# Along with this check that app runs ok
dut.expect('Hello world!')

# Don't need to have output from UART any more
dut.serial.stop_redirect_thread()

with open(os.path.join(dut.logdir, 'ocd.log'), 'w') as ocd_log:
ocd = subprocess.Popen(f'openocd {get_openocd_arguments(dut.target)}', stdout=ocd_log, stderr=ocd_log, shell=True)

try:
gdb_env = os.environ.copy()
gdb_env['ESP_IDF_GDB_TESTING'] = '1'

with open(os.path.join(dut.logdir, 'gdb.log'), 'w') as gdb_log, \
pexpect.spawn(f'idf.py -B {dut.app.binary_path} gdb --batch',
env=gdb_env,
timeout=60,
logfile=gdb_log,
encoding='utf-8',
codec_errors='ignore') as p:
p.expect(re.compile(r'add symbol table from file.*bootloader.elf'))
p.expect(re.compile(r'add symbol table from file.*rom.elf'))
p.expect_exact('hit Temporary breakpoint 1, app_main ()')
finally:
try:
ocd.send_signal(signal.SIGINT)
ocd.communicate(timeout=15)
except subprocess.TimeoutExpired:
ocd.kill()
ocd.communicate()

0 comments on commit 7561367

Please sign in to comment.