tools: add test for ROM symbols in GDB

This commit is contained in:
Alexey Lapshin 2022-09-08 00:45:04 +04:00
parent 2e9f175ae5
commit 7561367808
8 changed files with 143 additions and 14 deletions

View File

@ -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

View File

@ -34,3 +34,11 @@ URL_TO_DOC = 'https://docs.espressif.com/projects/esp-idf'
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',
}

View File

@ -14,6 +14,7 @@ from threading import Thread
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
@ -59,6 +60,11 @@ source {connect}
'''
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'
@ -286,12 +292,6 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
"""
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
@ -299,8 +299,7 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
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
@ -405,9 +404,9 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
"""
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
"""
@ -420,6 +419,8 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
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:
@ -476,12 +477,17 @@ def action_extensions(base_actions: Dict, project_path: str) -> Dict:
'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'],

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "hello_world_main.c"
INCLUDE_DIRS "")
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")

View File

@ -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();
}

View File

@ -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()