mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Support ELF files loadable with gdb
This commit is contained in:
parent
6a9288bc73
commit
5a916ce126
@ -66,7 +66,7 @@ variables:
|
||||
rm -rf "$CUSTOM_TOOLCHAIN_PATH"
|
||||
|
||||
.setup_tools_unless_target_test: &setup_tools_unless_target_test |
|
||||
if [ "$CI_JOB_STAGE" != "target_test" ]; then
|
||||
if [[ "$SETUP_TOOLS" == "1" || "$CI_JOB_STAGE" != "target_test" ]]; then
|
||||
tools/idf_tools.py --non-interactive install && eval "$(tools/idf_tools.py --non-interactive export)" || exit 1
|
||||
fi
|
||||
|
||||
|
77
Kconfig
77
Kconfig
@ -68,6 +68,83 @@ mainmenu "Espressif IoT Development Framework Configuration"
|
||||
|
||||
endmenu # SDK tool configuration
|
||||
|
||||
menu "Build type"
|
||||
|
||||
choice APP_BUILD_TYPE
|
||||
prompt "Application build type"
|
||||
default APP_BUILD_TYPE_APP_2NDBOOT
|
||||
help
|
||||
Select the way the application is built.
|
||||
|
||||
By default, the application is built as a binary file in a format compatible with
|
||||
the ESP32 bootloader. In addition to this application, 2nd stage bootloader is
|
||||
also built. Application and bootloader binaries can be written into flash and
|
||||
loaded/executed from there.
|
||||
|
||||
Another option, useful for only very small and limited applications, is to only link
|
||||
the .elf file of the application, such that it can be loaded directly into RAM over
|
||||
JTAG. Note that since IRAM and DRAM sizes are very limited, it is not possible to
|
||||
build any complex application this way. However for kinds of testing and debugging,
|
||||
this option may provide faster iterations, since the application does not need to be
|
||||
written into flash.
|
||||
Note that at the moment, ESP-IDF does not contain all the startup code required to
|
||||
initialize the CPUs and ROM memory (data/bss). Therefore it is necessary to execute
|
||||
a bit of ROM code prior to executing the application. A gdbinit file may look as follows:
|
||||
|
||||
# Connect to a running instance of OpenOCD
|
||||
target remote :3333
|
||||
# Reset and halt the target
|
||||
mon reset halt
|
||||
# Run to a specific point in ROM code,
|
||||
# where most of initialization is complete.
|
||||
thb *0x40007901
|
||||
c
|
||||
# Load the application into RAM
|
||||
load
|
||||
# Run till app_main
|
||||
tb app_main
|
||||
c
|
||||
|
||||
Execute this gdbinit file as follows:
|
||||
|
||||
xtensa-esp32-elf-gdb build/app-name.elf -x gdbinit
|
||||
|
||||
Recommended sdkconfig.defaults for building loadable ELF files is as follows.
|
||||
CONFIG_APP_BUILD_TYPE_ELF_RAM is required, other options help reduce application
|
||||
memory footprint.
|
||||
|
||||
CONFIG_APP_BUILD_TYPE_ELF_RAM=y
|
||||
CONFIG_VFS_SUPPORT_TERMIOS=
|
||||
CONFIG_NEWLIB_NANO_FORMAT=y
|
||||
CONFIG_ESP32_PANIC_PRINT_HALT=y
|
||||
CONFIG_ESP32_DEBUG_STUBS_ENABLE=
|
||||
CONFIG_ESP_ERR_TO_NAME_LOOKUP=
|
||||
|
||||
|
||||
config APP_BUILD_TYPE_APP_2NDBOOT
|
||||
bool
|
||||
prompt "Default (binary application + 2nd stage bootloader)"
|
||||
select APP_BUILD_GENERATE_BINARIES
|
||||
select APP_BUILD_BOOTLOADER
|
||||
select APP_BUILD_USE_FLASH_SECTIONS
|
||||
|
||||
config APP_BUILD_TYPE_ELF_RAM
|
||||
bool
|
||||
prompt "ELF file, loadable into RAM (EXPERIMENTAL))"
|
||||
endchoice # APP_BUILD_TYPE
|
||||
|
||||
# Hidden options, set according to the choice above
|
||||
config APP_BUILD_GENERATE_BINARIES
|
||||
bool # Whether to generate .bin files or not
|
||||
|
||||
config APP_BUILD_BOOTLOADER
|
||||
bool # Whether to build the bootloader
|
||||
|
||||
config APP_BUILD_USE_FLASH_SECTIONS
|
||||
bool # Whether to place code/data into memory-mapped flash sections
|
||||
|
||||
endmenu # Build type
|
||||
|
||||
source "$COMPONENT_KCONFIGS_PROJBUILD"
|
||||
|
||||
menu "Compiler options"
|
||||
|
@ -1,7 +1,7 @@
|
||||
idf_component_register(PRIV_REQUIRES partition_table)
|
||||
|
||||
# Do not generate flash file when building bootloader or is in early expansion of the build
|
||||
if(BOOTLOADER_BUILD)
|
||||
if(BOOTLOADER_BUILD OR NOT CONFIG_APP_BUILD_BOOTLOADER)
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
set(BOOTLOADER_OFFSET 0x1000)
|
||||
|
||||
# Do not generate flash file when building bootloader
|
||||
if(BOOTLOADER_BUILD)
|
||||
if(BOOTLOADER_BUILD OR NOT CONFIG_APP_BUILD_BOOTLOADER)
|
||||
return()
|
||||
endif()
|
||||
|
||||
@ -125,4 +125,4 @@ endif()
|
||||
# So for now we just have the top-level build remove the final build products...
|
||||
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" APPEND PROPERTY
|
||||
ADDITIONAL_MAKE_CLEAN_FILES
|
||||
${bootloader_binary_files})
|
||||
${bootloader_binary_files})
|
||||
|
@ -738,6 +738,11 @@ menu "ESP32-specific"
|
||||
|
||||
Enabling this setting adds approximately 1KB to the app's IRAM usage.
|
||||
|
||||
config ESP32_APP_INIT_CLK
|
||||
bool
|
||||
default y if ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS
|
||||
default y if APP_BUILD_TYPE_ELF_RAM
|
||||
|
||||
config ESP32_RTCDATA_IN_FAST_MEM
|
||||
bool "Place RTC_DATA_ATTR and RTC_RODATA_ATTR variables into RTC fast memory segment"
|
||||
default n
|
||||
|
@ -75,7 +75,7 @@ void esp_clk_init(void)
|
||||
rtc_config_t cfg = RTC_CONFIG_DEFAULT();
|
||||
rtc_init(cfg);
|
||||
|
||||
#ifdef CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS
|
||||
#if (CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS || CONFIG_ESP32_APP_INIT_CLK)
|
||||
/* Check the bootloader set the XTAL frequency.
|
||||
|
||||
Bootloaders pre-v2.1 don't do this.
|
||||
@ -293,6 +293,8 @@ void esp_perip_clk_init(void)
|
||||
DPORT_I2S1_CLK_EN |
|
||||
DPORT_SPI_DMA_CLK_EN;
|
||||
|
||||
common_perip_clk &= ~DPORT_SPI01_CLK_EN;
|
||||
|
||||
#if CONFIG_SPIRAM_SPEED_80M
|
||||
//80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in
|
||||
//a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs'
|
||||
|
@ -72,6 +72,11 @@
|
||||
#include "esp_efuse.h"
|
||||
#include "bootloader_flash_config.h"
|
||||
|
||||
#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
#include "esp32/rom/efuse.h"
|
||||
#include "esp32/rom/spi_flash.h"
|
||||
#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
|
||||
#define STRINGIFY(s) STRINGIFY2(s)
|
||||
#define STRINGIFY2(s) #s
|
||||
|
||||
@ -391,6 +396,32 @@ void start_cpu0_default(void)
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
esp_dport_access_int_init();
|
||||
#endif
|
||||
|
||||
bootloader_flash_update_id();
|
||||
#if !CONFIG_SPIRAM_BOOT_INIT
|
||||
// Read the application binary image header. This will also decrypt the header if the image is encrypted.
|
||||
esp_image_header_t fhdr = {0};
|
||||
#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
fhdr.spi_mode = ESP_IMAGE_SPI_MODE_DIO;
|
||||
fhdr.spi_speed = ESP_IMAGE_SPI_SPEED_40M;
|
||||
fhdr.spi_size = ESP_IMAGE_FLASH_SIZE_4MB;
|
||||
|
||||
extern void esp_rom_spiflash_attach(uint32_t, bool);
|
||||
esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), false);
|
||||
esp_rom_spiflash_unlock();
|
||||
#else
|
||||
// This assumes that DROM is the first segment in the application binary, i.e. that we can read
|
||||
// the binary header through cache by accessing SOC_DROM_LOW address.
|
||||
memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr));
|
||||
#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM
|
||||
|
||||
// If psram is uninitialized, we need to improve some flash configuration.
|
||||
bootloader_flash_clock_config(&fhdr);
|
||||
bootloader_flash_gpio_config(&fhdr);
|
||||
bootloader_flash_dummy_config(&fhdr);
|
||||
bootloader_flash_cs_timing_config();
|
||||
#endif //!CONFIG_SPIRAM_BOOT_INIT
|
||||
|
||||
spi_flash_init();
|
||||
/* init default OS-aware flash access critical section */
|
||||
spi_flash_guard_set(&g_flash_guard_default_ops);
|
||||
@ -424,20 +455,6 @@ void start_cpu0_default(void)
|
||||
esp_coex_adapter_register(&g_coex_adapter_funcs);
|
||||
#endif
|
||||
|
||||
bootloader_flash_update_id();
|
||||
#if !CONFIG_SPIRAM_BOOT_INIT
|
||||
// Read the application binary image header. This will also decrypt the header if the image is encrypted.
|
||||
esp_image_header_t fhdr = {0};
|
||||
// This assumes that DROM is the first segment in the application binary, i.e. that we can read
|
||||
// the binary header through cache by accessing SOC_DROM_LOW address.
|
||||
memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr));
|
||||
// If psram is uninitialized, we need to improve some flash configuration.
|
||||
bootloader_flash_clock_config(&fhdr);
|
||||
bootloader_flash_gpio_config(&fhdr);
|
||||
bootloader_flash_dummy_config(&fhdr);
|
||||
bootloader_flash_cs_timing_config();
|
||||
#endif
|
||||
|
||||
portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
|
||||
ESP_TASK_MAIN_STACK, NULL,
|
||||
ESP_TASK_MAIN_PRIO, NULL, 0);
|
||||
|
@ -49,6 +49,7 @@ MEMORY
|
||||
/* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
|
||||
iram0_0_seg (RX) : org = 0x40080000, len = 0x20000
|
||||
|
||||
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
/* Even though the segment name is iram, it is actually mapped to flash
|
||||
*/
|
||||
iram0_2_seg (RX) : org = 0x400D0018, len = 0x330000-0x18
|
||||
@ -58,6 +59,7 @@ MEMORY
|
||||
which is flashed to the chip has a 0x18 byte file header. Setting this offset makes it simple to meet the flash
|
||||
cache MMU's constraint that (paddr % 64KB == vaddr % 64KB).)
|
||||
*/
|
||||
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
|
||||
|
||||
/* Shared data RAM, excluding memory reserved for ROM bss/data/stack.
|
||||
@ -72,10 +74,12 @@ MEMORY
|
||||
dram0_0_seg (RW) : org = 0x3FFB0000 + CONFIG_BT_RESERVE_DRAM,
|
||||
len = DRAM0_0_SEG_LEN - CONFIG_BT_RESERVE_DRAM
|
||||
|
||||
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
/* Flash mapped constant data */
|
||||
drom0_0_seg (R) : org = 0x3F400018, len = 0x400000-0x18
|
||||
|
||||
/* (See iram0_2_seg for meaning of 0x18 offset in the above.) */
|
||||
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
|
||||
/* RTC fast memory (executable). Persists over deep sleep.
|
||||
*/
|
||||
@ -116,3 +120,15 @@ REGION_ALIAS("rtc_data_location", rtc_slow_seg );
|
||||
#else
|
||||
REGION_ALIAS("rtc_data_location", rtc_data_seg );
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
REGION_ALIAS("default_code_seg", iram0_2_seg);
|
||||
#else
|
||||
REGION_ALIAS("default_code_seg", iram0_0_seg);
|
||||
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
|
||||
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
REGION_ALIAS("default_rodata_seg", drom0_0_seg);
|
||||
#else
|
||||
REGION_ALIAS("default_rodata_seg", dram0_0_seg);
|
||||
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
|
@ -161,12 +161,8 @@ SECTIONS
|
||||
mapping[iram0_text]
|
||||
|
||||
_iram_text_end = ABSOLUTE(.);
|
||||
_iram_end = ABSOLUTE(.);
|
||||
} > iram0_0_seg
|
||||
|
||||
ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
|
||||
"IRAM0 segment data does not fit.")
|
||||
|
||||
.dram0.data :
|
||||
{
|
||||
_data_start = ABSOLUTE(.);
|
||||
@ -312,7 +308,7 @@ SECTIONS
|
||||
*(.tbss.*)
|
||||
_thread_local_end = ABSOLUTE(.);
|
||||
. = ALIGN(4);
|
||||
} >drom0_0_seg
|
||||
} >default_rodata_seg
|
||||
|
||||
.flash.text :
|
||||
{
|
||||
@ -334,5 +330,25 @@ SECTIONS
|
||||
the flash.text segment.
|
||||
*/
|
||||
_flash_cache_start = ABSOLUTE(0);
|
||||
} >iram0_2_seg
|
||||
} >default_code_seg
|
||||
|
||||
/* Marks the end of IRAM code segment */
|
||||
.iram0.text_end (NOLOAD) :
|
||||
{
|
||||
. = ALIGN (4);
|
||||
_iram_end = ABSOLUTE(.);
|
||||
} > iram0_0_seg
|
||||
|
||||
/* Marks the end of data, bss and possibly rodata */
|
||||
.dram0.heap_start (NOLOAD) :
|
||||
{
|
||||
. = ALIGN (8);
|
||||
_heap_start = ABSOLUTE(.);
|
||||
} > dram0_0_seg
|
||||
}
|
||||
|
||||
ASSERT(((_iram_text_end - ORIGIN(iram0_0_seg)) <= LENGTH(iram0_0_seg)),
|
||||
"IRAM0 segment data does not fit.")
|
||||
|
||||
ASSERT(((_heap_start - ORIGIN(dram0_0_seg)) <= LENGTH(dram0_0_seg)),
|
||||
"DRAM segment data does not fit.")
|
||||
|
@ -50,8 +50,12 @@ entries:
|
||||
|
||||
[scheme:default]
|
||||
entries:
|
||||
text -> flash_text
|
||||
rodata -> flash_rodata
|
||||
if APP_BUILD_USE_FLASH_SECTIONS = y:
|
||||
text -> flash_text
|
||||
rodata -> flash_rodata
|
||||
else:
|
||||
text -> iram0_text
|
||||
rodata -> dram0_data
|
||||
data -> dram0_data
|
||||
bss -> dram0_bss
|
||||
common -> dram0_bss
|
||||
|
@ -450,7 +450,7 @@ static void esp_panic_dig_reset(void)
|
||||
;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||
|
||||
static void putEntry(uint32_t pc, uint32_t sp)
|
||||
{
|
||||
|
@ -8,6 +8,7 @@ PROVIDE ( esp_rom_spiflash_erase_area = 0x400631ac );
|
||||
PROVIDE ( esp_rom_spiflash_erase_block = 0x40062c4c );
|
||||
PROVIDE ( esp_rom_spiflash_erase_chip = 0x40062c14 );
|
||||
PROVIDE ( esp_rom_spiflash_erase_sector = 0x40062ccc );
|
||||
PROVIDE ( esp_rom_spiflash_attach = 0x40062a6c );
|
||||
PROVIDE ( esp_rom_spiflash_lock = 0x400628f0 );
|
||||
PROVIDE ( esp_rom_spiflash_read = 0x40062ed8 );
|
||||
PROVIDE ( esp_rom_spiflash_config_readmode = 0x40062b64 ); /* SPIMasterReadModeCnfig */
|
||||
|
@ -1,6 +1,6 @@
|
||||
idf_component_register(REQUIRES bootloader)
|
||||
|
||||
if(NOT BOOTLOADER_BUILD)
|
||||
if(NOT BOOTLOADER_BUILD AND CONFIG_APP_BUILD_GENERATE_BINARIES)
|
||||
string(REPLACE ";" " " ESPTOOLPY_FLASH_PROJECT_OPTIONS "${ESPTOOLPY_FLASH_OPTIONS}")
|
||||
set(ESPTOOLPY_FLASH_PROJECT_OPTIONS
|
||||
"${ESPTOOLPY_FLASH_PROJECT_OPTIONS}"
|
||||
|
@ -68,7 +68,11 @@ endif
|
||||
APP_BIN_UNSIGNED ?= $(APP_BIN)
|
||||
|
||||
$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC) | check_python_dependencies
|
||||
ifeq ("$(CONFIG_APP_BUILD_GENERATE_BINARIES)","y")
|
||||
$(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $<
|
||||
else
|
||||
@echo "Skipping the BIN generation"
|
||||
endif
|
||||
|
||||
ifdef CONFIG_SECURE_FLASH_ENCRYPTION_MODE_DEVELOPMENT
|
||||
encrypted-flash: all_binaries $(ESPTOOLPY_SRC) $(call prereq_if_explicit,erase_flash) partition_table_get_info | check_python_dependencies
|
||||
|
@ -78,24 +78,28 @@ set(PROJECT_BIN "${elf_name}.bin")
|
||||
#
|
||||
# Add 'app.bin' target - generates with elf2image
|
||||
#
|
||||
add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
|
||||
COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS}
|
||||
-o "${build_dir}/${unsigned_project_binary}" "${elf}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}"
|
||||
COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.bin_timestamp"
|
||||
DEPENDS ${elf}
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${build_dir}
|
||||
COMMENT "Generating binary image from built executable"
|
||||
)
|
||||
add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp")
|
||||
if(CONFIG_APP_BUILD_GENERATE_BINARIES)
|
||||
add_custom_command(OUTPUT "${build_dir}/.bin_timestamp"
|
||||
COMMAND ${ESPTOOLPY} elf2image ${ESPTOOLPY_FLASH_OPTIONS} ${ESPTOOLPY_ELF2IMAGE_OPTIONS}
|
||||
-o "${build_dir}/${unsigned_project_binary}" "${elf}"
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Generated ${build_dir}/${unsigned_project_binary}"
|
||||
COMMAND ${CMAKE_COMMAND} -E md5sum "${build_dir}/${unsigned_project_binary}" > "${build_dir}/.bin_timestamp"
|
||||
DEPENDS ${elf}
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${build_dir}
|
||||
COMMENT "Generating binary image from built executable"
|
||||
)
|
||||
add_custom_target(gen_project_binary DEPENDS "${build_dir}/.bin_timestamp")
|
||||
endif()
|
||||
|
||||
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
|
||||
"${build_dir}/${unsigned_project_binary}"
|
||||
)
|
||||
|
||||
add_custom_target(app ALL DEPENDS gen_project_binary)
|
||||
if(CONFIG_APP_BUILD_GENERATE_BINARIES)
|
||||
add_custom_target(app ALL DEPENDS gen_project_binary)
|
||||
endif()
|
||||
|
||||
if(NOT BOOTLOADER_BUILD AND CONFIG_SECURE_SIGNED_APPS)
|
||||
if(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)
|
||||
|
@ -29,7 +29,7 @@ extern soc_reserved_region_t soc_reserved_memory_region_end;
|
||||
These variables have the start and end of the data and static IRAM
|
||||
area used by the program. Defined in the linker script.
|
||||
*/
|
||||
extern int _data_start, _static_data_end, _iram_start, _iram_end;
|
||||
extern int _data_start, _heap_start, _iram_start, _iram_end;
|
||||
|
||||
/* static DRAM & IRAM chunks */
|
||||
static const size_t EXTRA_RESERVED_REGIONS = 2;
|
||||
@ -67,8 +67,8 @@ static void s_prepare_reserved_regions(soc_reserved_region_t *reserved, size_t c
|
||||
(count - EXTRA_RESERVED_REGIONS) * sizeof(soc_reserved_region_t));
|
||||
|
||||
/* Add the EXTRA_RESERVED_REGIONS at the beginning */
|
||||
reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss */
|
||||
reserved[0].end = (intptr_t)&_static_data_end;
|
||||
reserved[0].start = (intptr_t)&_data_start; /* DRAM used by data+bss and possibly rodata */
|
||||
reserved[0].end = (intptr_t)&_heap_start;
|
||||
reserved[1].start = (intptr_t)&_iram_start; /* IRAM used by code */
|
||||
reserved[1].end = (intptr_t)&_iram_end;
|
||||
|
||||
|
13
examples/get-started/hello_world/.gdbinit.ci
Normal file
13
examples/get-started/hello_world/.gdbinit.ci
Normal file
@ -0,0 +1,13 @@
|
||||
# Connect to a running instance of OpenOCD
|
||||
target remote 127.0.0.1:3333
|
||||
# Reset and halt the target
|
||||
mon reset halt
|
||||
# Run to a specific point in ROM code,
|
||||
# where most of initialization is complete.
|
||||
thb *0x40007901
|
||||
c
|
||||
# Load the application into RAM
|
||||
load
|
||||
# Run till app_main
|
||||
tb app_main
|
||||
c
|
129
examples/get-started/hello_world/loadable_elf_example_test.py
Normal file
129
examples/get-started/hello_world/loadable_elf_example_test.py
Normal file
@ -0,0 +1,129 @@
|
||||
import os
|
||||
import pexpect
|
||||
import serial
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
try:
|
||||
import IDF
|
||||
except ImportError:
|
||||
test_fw_path = os.getenv('TEST_FW_PATH')
|
||||
if test_fw_path and test_fw_path not in sys.path:
|
||||
sys.path.insert(0, test_fw_path)
|
||||
import IDF
|
||||
|
||||
import Utility
|
||||
|
||||
|
||||
class CustomProcess(object):
|
||||
def __init__(self, cmd, logfile):
|
||||
self.f = open(logfile, 'wb')
|
||||
self.p = pexpect.spawn(cmd, timeout=60, logfile=self.f)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def close(self):
|
||||
self.p.terminate(force=True)
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.close()
|
||||
self.f.close()
|
||||
|
||||
|
||||
class OCDProcess(CustomProcess):
|
||||
def __init__(self, proj_path):
|
||||
cmd = 'openocd -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg'
|
||||
log_file = os.path.join(proj_path, 'openocd.log')
|
||||
super(OCDProcess, self).__init__(cmd, log_file)
|
||||
i = self.p.expect_exact(['Info : Listening on port 3333 for gdb connections', 'Error:'])
|
||||
if i == 0:
|
||||
Utility.console_log('openocd is listening for gdb connections')
|
||||
else:
|
||||
raise RuntimeError('openocd initialization has failed')
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self.p.sendcontrol('c')
|
||||
self.p.expect_exact('shutdown command invoked')
|
||||
except Exception:
|
||||
Utility.console_log('openocd needs to be killed', 'O')
|
||||
super(OCDProcess, self).close()
|
||||
|
||||
|
||||
class GDBProcess(CustomProcess):
|
||||
def __init__(self, proj_path, elf_path):
|
||||
cmd = 'xtensa-esp32-elf-gdb -x {} --directory={} {}'.format(os.path.join(proj_path, '.gdbinit.ci'),
|
||||
os.path.join(proj_path, 'main'),
|
||||
elf_path)
|
||||
log_file = os.path.join(proj_path, 'gdb.log')
|
||||
super(GDBProcess, self).__init__(cmd, log_file)
|
||||
self.p.sendline('') # it is for "---Type <return> to continue, or q <return> to quit---"
|
||||
i = self.p.expect_exact(['Thread 1 hit Temporary breakpoint 2, app_main ()',
|
||||
'Load failed'])
|
||||
if i == 0:
|
||||
Utility.console_log('gdb is at breakpoint')
|
||||
else:
|
||||
raise RuntimeError('Load failed: probably the ELF file was not built for loading with gdb')
|
||||
self.p.expect_exact('(gdb)')
|
||||
|
||||
def close(self):
|
||||
try:
|
||||
self.p.sendline('q')
|
||||
self.p.expect_exact('Quit anyway? (y or n)')
|
||||
self.p.sendline('y')
|
||||
self.p.expect_exact('Ending remote debugging.')
|
||||
except Exception:
|
||||
Utility.console_log('gdb needs to be killed', 'O')
|
||||
super(GDBProcess, self).close()
|
||||
|
||||
def break_till_end(self):
|
||||
self.p.sendline('b esp_restart')
|
||||
self.p.sendline('c')
|
||||
self.p.expect_exact('Thread 1 hit Breakpoint 3, esp_restart ()')
|
||||
|
||||
|
||||
class SerialThread(object):
|
||||
def run(self, log_path, exit_event):
|
||||
with serial.Serial('/dev/ttyUSB1', 115200) as ser, open(log_path, 'wb') as f:
|
||||
while True:
|
||||
f.write(ser.read(ser.in_waiting))
|
||||
if exit_event.is_set():
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
def __init__(self, log_path):
|
||||
self.exit_event = threading.Event()
|
||||
self.t = threading.Thread(target=self.run, args=(log_path, self.exit_event,))
|
||||
self.t.start()
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.exit_event.set()
|
||||
self.t.join(60)
|
||||
if self.t.is_alive():
|
||||
Utility.console_log('The pyserial thread is still alive', 'O')
|
||||
|
||||
|
||||
@IDF.idf_example_test(env_tag="test_jtag_arm")
|
||||
def test_examples_loadable_elf(env, extra_data):
|
||||
|
||||
idf_path = os.environ['IDF_PATH']
|
||||
rel_project_path = os.path.join('examples', 'get-started', 'hello_world')
|
||||
proj_path = os.path.join(idf_path, rel_project_path)
|
||||
elf_path = os.path.join(IDF.Example(rel_project_path).get_binary_path(rel_project_path), 'hello-world.elf')
|
||||
esp_log_path = os.path.join(proj_path, 'esp.log')
|
||||
|
||||
with SerialThread(esp_log_path):
|
||||
with OCDProcess(proj_path), GDBProcess(proj_path, elf_path) as gdb:
|
||||
gdb.break_till_end()
|
||||
|
||||
if pexpect.run('grep "Restarting now." {}'.format(esp_log_path), withexitstatus=True)[1]:
|
||||
raise RuntimeError('Expected output from ESP was not received')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_loadable_elf()
|
6
examples/get-started/hello_world/sdkconfig.ci
Normal file
6
examples/get-started/hello_world/sdkconfig.ci
Normal file
@ -0,0 +1,6 @@
|
||||
CONFIG_APP_BUILD_TYPE_ELF_RAM=y
|
||||
CONFIG_VFS_SUPPORT_TERMIOS=
|
||||
CONFIG_NEWLIB_NANO_FORMAT=y
|
||||
CONFIG_ESP32_PANIC_PRINT_HALT=y
|
||||
CONFIG_ESP32_DEBUG_STUBS_ENABLE=
|
||||
CONFIG_ESP_ERR_TO_NAME_LOOKUP=
|
@ -320,9 +320,15 @@ ifndef CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES
|
||||
endif
|
||||
@echo "To flash app & partition table, run 'make flash' or:"
|
||||
else
|
||||
ifdef CONFIG_APP_BUILD_GENERATE_BINARIES
|
||||
@echo "To flash all build output, run 'make flash' or:"
|
||||
endif
|
||||
endif
|
||||
ifdef CONFIG_APP_BUILD_GENERATE_BINARIES
|
||||
@echo $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
|
||||
else
|
||||
@echo "Binary is not available for flashing"
|
||||
endif
|
||||
|
||||
|
||||
# If we have `version.txt` then prefer that for extracting IDF version
|
||||
@ -533,6 +539,7 @@ $(APP_ELF): $(foreach libcomp,$(COMPONENT_LIBRARIES),$(BUILD_DIR_BASE)/$(libcomp
|
||||
$(CC) $(LDFLAGS) -o $@ -Wl,-Map=$(APP_MAP)
|
||||
|
||||
app: $(APP_BIN) partition_table_get_info
|
||||
ifeq ("$(CONFIG_APP_BUILD_GENERATE_BINARIES)","y")
|
||||
ifeq ("$(CONFIG_SECURE_BOOT_ENABLED)$(CONFIG_SECURE_BOOT_BUILD_SIGNED_BINARIES)","y") # secure boot enabled, but remote sign app image
|
||||
@echo "App built but not signed. Signing step via espsecure.py:"
|
||||
@echo "espsecure.py sign_data --keyfile KEYFILE $(APP_BIN)"
|
||||
@ -542,6 +549,9 @@ else
|
||||
@echo "App built. Default flash app command is:"
|
||||
@echo $(ESPTOOLPY_WRITE_FLASH) $(APP_OFFSET) $(APP_BIN)
|
||||
endif
|
||||
else
|
||||
@echo "Application in not built and cannot be flashed."
|
||||
endif
|
||||
|
||||
all_binaries: $(APP_BIN)
|
||||
|
||||
|
@ -202,6 +202,19 @@ example_test_008:
|
||||
- ESP32
|
||||
- Example_Flash_Encryption
|
||||
|
||||
example_test_009:
|
||||
extends: .example_test_template
|
||||
tags:
|
||||
- ESP32
|
||||
- test_jtag_arm
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- $CI_PROJECT_DIR/examples/get-started/hello_world/*.log
|
||||
expire_in: 1 week
|
||||
variables:
|
||||
SETUP_TOOLS: "1"
|
||||
|
||||
UT_001:
|
||||
extends: .unit_test_template
|
||||
parallel: 50
|
||||
|
@ -924,6 +924,10 @@ def init_cli(verbose_output=None):
|
||||
print("Done")
|
||||
return
|
||||
|
||||
if not os.path.exists(os.path.join(args.build_dir, "flasher_args.json")):
|
||||
print("Done")
|
||||
return
|
||||
|
||||
# Otherwise, if we built any binaries print a message about
|
||||
# how to flash them
|
||||
def print_flashing_message(title, key):
|
||||
|
@ -35,18 +35,21 @@ class IDFApp(App.BaseApp):
|
||||
self.binary_path = self.get_binary_path(app_path)
|
||||
self.elf_file = self._get_elf_file_path(self.binary_path)
|
||||
assert os.path.exists(self.binary_path)
|
||||
if self.IDF_DOWNLOAD_CONFIG_FILE not in os.listdir(self.binary_path):
|
||||
if self.IDF_FLASH_ARGS_FILE not in os.listdir(self.binary_path):
|
||||
msg = ("Neither {} nor {} exists. "
|
||||
"Try to run 'make print_flash_cmd | tail -n 1 > {}/{}' "
|
||||
"or 'idf.py build' "
|
||||
"for resolving the issue."
|
||||
"").format(self.IDF_DOWNLOAD_CONFIG_FILE, self.IDF_FLASH_ARGS_FILE,
|
||||
self.binary_path, self.IDF_DOWNLOAD_CONFIG_FILE)
|
||||
raise AssertionError(msg)
|
||||
sdkconfig_dict = self.get_sdkconfig()
|
||||
if "CONFIG_APP_BUILD_GENERATE_BINARIES" in sdkconfig_dict:
|
||||
# There are no flashing targets available when no binaries where generated.
|
||||
if self.IDF_DOWNLOAD_CONFIG_FILE not in os.listdir(self.binary_path):
|
||||
if self.IDF_FLASH_ARGS_FILE not in os.listdir(self.binary_path):
|
||||
msg = ("Neither {} nor {} exists. "
|
||||
"Try to run 'make print_flash_cmd | tail -n 1 > {}/{}' "
|
||||
"or 'idf.py build' "
|
||||
"for resolving the issue."
|
||||
"").format(self.IDF_DOWNLOAD_CONFIG_FILE, self.IDF_FLASH_ARGS_FILE,
|
||||
self.binary_path, self.IDF_DOWNLOAD_CONFIG_FILE)
|
||||
raise AssertionError(msg)
|
||||
|
||||
self.flash_files, self.flash_settings = self._parse_flash_download_config()
|
||||
self.partition_table = self._parse_partition_table()
|
||||
self.flash_files, self.flash_settings = self._parse_flash_download_config()
|
||||
self.partition_table = self._parse_partition_table()
|
||||
|
||||
@classmethod
|
||||
def get_sdk_path(cls):
|
||||
|
@ -70,7 +70,15 @@ void setUp(void)
|
||||
#endif
|
||||
|
||||
printf("%s", ""); /* sneakily lazy-allocate the reent structure for this test task */
|
||||
|
||||
#ifdef CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
/* TODO: add sufficient startup code in case of building an ELF file, so that
|
||||
* flash cache is initialized and can work in such mode.
|
||||
* For now this is disabled to allow running unit tests which don't require
|
||||
* flash cache related operations.
|
||||
*/
|
||||
get_test_data_partition(); /* allocate persistent partition table structures */
|
||||
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
|
||||
|
||||
unity_reset_leak_checks();
|
||||
test_utils_set_leak_level(CONFIG_UNITY_CRITICAL_LEAK_LEVEL_GENERAL, TYPE_LEAK_CRITICAL, COMP_LEAK_GENERAL);
|
||||
|
Loading…
Reference in New Issue
Block a user