Skip to content

Commit ee182ce

Browse files
authored
Merge branch 'espressif:master' into pioarduino
2 parents dea4c70 + b683ec7 commit ee182ce

File tree

8 files changed

+141
-54
lines changed

8 files changed

+141
-54
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@
2020
</div>
2121
<hr>
2222

23+
## v5.0.1 (2025-07-15)
24+
25+
### 🐛 Bug Fixes
26+
27+
- **elf2image**: validate ELF section types and addresses before processing *(Jaroslav Burian - 97a1546)*
28+
- **elf2image**: handle PREINIT_ARRAY section type in ESP32-P4 elf file properly *(Jaroslav Burian - ec84a75)*
29+
- **elf2image**: Fix incorrect logger call *(Marek Matej - 637f0e6)*
30+
31+
2332
## v5.0.0 (2025-07-02)
2433

2534
### 🚨 Breaking changes

docs/en/esptool/scripting.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,4 +354,4 @@ To ensure compatibility with esptool, the custom logger should re-implement (or
354354
:members: print, note, warning, error, stage, progress_bar, set_verbosity
355355
:member-order: bysource
356356

357-
These methods are essential for maintaining proper integration and behavior with esptool. Additionally, all output printing should be made using ``log.print()`` (or the respective method, such as ``log.info()`` or ``log.warning()``) instead of the standard ``print()`` function to ensure the output is routed through the custom logger. This ensures consistency and allows the custom logger to handle all output appropriately. You can further customize this logger to fit your application's needs, such as integrating with GUI components or advanced logging frameworks.
357+
These methods are essential for maintaining proper integration and behavior with esptool. Additionally, all output printing should be made using ``log.print()`` (or the respective method, such as ``log.note()`` or ``log.warning()``) instead of the standard ``print()`` function to ensure the output is routed through the custom logger. This ensures consistency and allows the custom logger to handle all output appropriately. You can further customize this logger to fit your application's needs, such as integrating with GUI components or advanced logging frameworks.

docs/en/migration-guide.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ The esptool ``v5`` release introduces a centralized logging mechanism to improve
7777

7878
**Migration Steps:**
7979

80-
1. If your scripts rely on direct ``print()`` statements, update them to use the centralized logger for consistent output. Calls to the logger should be made using ``log.print()`` (or the respective method, such as ``log.info()``, ``log.warning()``, or ``log.error()``).
80+
1. If your scripts rely on direct ``print()`` statements, update them to use the centralized logger for consistent output. Calls to the logger should be made using ``log.print()`` (or the respective method, such as ``log.note()``, ``log.warning()``, or ``log.error()``).
8181
2. Refer to the provided documentation to implement custom loggers as needed.
8282
3. Update GUIs or tools to leverage the progress tracking API for better user feedback during lengthy operations.
8383

esptool/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"write_mem",
3232
]
3333

34-
__version__ = "5.0.0"
34+
__version__ = "5.0.1"
3535

3636
import os
3737
import shlex

esptool/bin_image.py

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ def merge_adjacent_segments(self):
443443
elem_pad_addr != elem.addr + len(elem.data)
444444
and elem_pad_addr == next_elem.addr
445445
):
446-
log.info(
446+
log.note(
447447
"Inserting {} bytes padding between {} and {}".format(
448448
next_elem.addr - (elem.addr + len(elem.data)),
449449
elem.name,
@@ -1281,14 +1281,6 @@ class ESP32H21FirmwareImage(ESP32C6FirmwareImage):
12811281

12821282

12831283
class ELFFile(object):
1284-
SEC_TYPE_PROGBITS = 0x01
1285-
SEC_TYPE_STRTAB = 0x03
1286-
SEC_TYPE_NOBITS = 0x08 # e.g. .bss section
1287-
SEC_TYPE_INITARRAY = 0x0E
1288-
SEC_TYPE_FINIARRAY = 0x0F
1289-
1290-
PROG_SEC_TYPES = (SEC_TYPE_PROGBITS, SEC_TYPE_INITARRAY, SEC_TYPE_FINIARRAY)
1291-
12921284
LEN_SEC_HEADER = 0x28
12931285

12941286
SEG_TYPE_LOAD = 0x01
@@ -1347,6 +1339,22 @@ def _read_elf_file(self, f):
13471339
self._read_segments(f, _phoff, _phnum, shstrndx)
13481340

13491341
def _read_sections(self, f, section_header_offs, section_header_count, shstrndx):
1342+
SEC_TYPE_PROGBITS = 0x01
1343+
SEC_TYPE_STRTAB = 0x03
1344+
SEC_TYPE_NOBITS = 0x08 # e.g. .bss section
1345+
SEC_TYPE_INITARRAY = 0x0E
1346+
SEC_TYPE_FINIARRAY = 0x0F
1347+
SEC_TYPE_PREINITARRAY = 0x10
1348+
1349+
PROG_SEC_TYPES = (
1350+
SEC_TYPE_PROGBITS,
1351+
SEC_TYPE_INITARRAY,
1352+
SEC_TYPE_FINIARRAY,
1353+
SEC_TYPE_PREINITARRAY,
1354+
)
1355+
1356+
KNOWN_SEC_TYPES = PROG_SEC_TYPES + (SEC_TYPE_NOBITS, SEC_TYPE_STRTAB)
1357+
13501358
f.seek(section_header_offs)
13511359
len_bytes = section_header_count * self.LEN_SEC_HEADER
13521360
section_header = f.read(len_bytes)
@@ -1378,17 +1386,13 @@ def read_section_header(offs):
13781386
) = struct.unpack_from("<LLLLLLLLL", section_header[offs:])
13791387
return (name_offs, sec_type, lma, size, sec_offs, _flags, align)
13801388

1381-
all_sections = [read_section_header(offs) for offs in section_header_offsets]
1382-
prog_sections = [s for s in all_sections if s[1] in ELFFile.PROG_SEC_TYPES]
1383-
nobits_secitons = [s for s in all_sections if s[1] == ELFFile.SEC_TYPE_NOBITS]
1384-
13851389
# search for the string table section
13861390
if (shstrndx * self.LEN_SEC_HEADER) not in section_header_offsets:
13871391
raise FatalError(f"ELF file has no STRTAB section at shstrndx {shstrndx}")
13881392
_, sec_type, _, sec_size, sec_offs, _flags, align = read_section_header(
13891393
shstrndx * self.LEN_SEC_HEADER
13901394
)
1391-
if sec_type != ELFFile.SEC_TYPE_STRTAB:
1395+
if sec_type != SEC_TYPE_STRTAB:
13921396
log.warning(f"ELF file has incorrect STRTAB section type {sec_type:#04x}")
13931397
f.seek(sec_offs)
13941398
string_table = f.read(sec_size)
@@ -1404,23 +1408,42 @@ def read_data(offs, size):
14041408
f.seek(offs)
14051409
return f.read(size)
14061410

1407-
prog_sections = [
1408-
ELFSection(
1409-
lookup_string(n_offs),
1410-
lma,
1411-
read_data(offs, size),
1412-
flags=_flags,
1413-
align=align,
1414-
)
1415-
for (n_offs, _type, lma, size, offs, _flags, align) in prog_sections
1416-
if lma != 0 and size > 0
1417-
]
1418-
self.sections = prog_sections
1419-
self.nobits_sections = [
1420-
ELFSection(lookup_string(n_offs), lma, b"", flags=_flags, align=align)
1421-
for (n_offs, _type, lma, size, offs, _flags, align) in nobits_secitons
1422-
if lma != 0 and size > 0
1423-
]
1411+
all_sections = [read_section_header(offs) for offs in section_header_offsets]
1412+
1413+
self.sections = []
1414+
self.nobits_sections = []
1415+
# Process all sections and raise an error if an unknown section type is found
1416+
for section in all_sections:
1417+
n_offs, sec_type, lma, size, offs, _flags, align = section
1418+
1419+
# Skip sections with lma == 0 or size == 0
1420+
if lma == 0 or size == 0:
1421+
continue
1422+
1423+
if sec_type not in KNOWN_SEC_TYPES:
1424+
log.warning(f"Unknown section type {sec_type:#04x} in ELF file")
1425+
continue
1426+
1427+
if sec_type in PROG_SEC_TYPES:
1428+
self.sections.append(
1429+
ELFSection(
1430+
lookup_string(n_offs),
1431+
lma,
1432+
read_data(offs, size),
1433+
flags=_flags,
1434+
align=align,
1435+
)
1436+
)
1437+
elif sec_type == SEC_TYPE_NOBITS:
1438+
self.nobits_sections.append(
1439+
ELFSection(
1440+
lookup_string(n_offs),
1441+
lma,
1442+
b"",
1443+
flags=_flags,
1444+
align=align,
1445+
)
1446+
)
14241447

14251448
def _read_segments(self, f, segment_header_offs, segment_header_count, shstrndx):
14261449
f.seek(segment_header_offs)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878

7979
[tool.commitizen]
8080
name = "czespressif"
81-
version = "5.0.0"
81+
version = "5.0.1"
8282
update_changelog_on_bump = true
8383
tag_format = "v$version"
8484
changelog_start_rev = "v4.2.1"

test/test_esptool_sdm.py

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
#
66
# How to use:
77
#
8-
# Run with a physical connection to a chip:
9-
# - `pytest test_esptool_sdm.py --chip esp32 --port /dev/ttyUSB0 --baud 115200`
8+
# Run with a physical connection to a chip (ESP8266 and ESP32 do not support
9+
# secure download mode):
10+
# - `pytest test_esptool_sdm.py --chip esp32s2 --port /dev/ttyUSB0 --baud 115200`
1011
#
1112
# where - --port - a serial port for esptool operation
1213
# - --chip - ESP chip name
@@ -17,27 +18,20 @@
1718

1819

1920
@pytest.mark.skipif(
20-
arg_chip == "esp8266", reason="ESP8266 does not support Secure Download Mode"
21+
arg_chip in ("esp8266", "esp32"),
22+
reason="ESP8266 and ESP32 do not support secure download mode",
2123
)
2224
class TestSecureDownloadMode(EsptoolTestCase):
2325
expected_chip_name = esptool.util.expand_chip_name(arg_chip)
2426

25-
@pytest.mark.skipif(
26-
arg_chip in ("esp8266", "esp32"),
27-
reason="No get-security-info on ESP8266 and ESP32",
28-
)
2927
def test_auto_detect(self):
3028
output = self.run_esptool("get-security-info", chip="auto")
3129

32-
if arg_chip == "esp32s2": # no autodetection from security info, only magic no.
33-
assert "Secure Download Mode is enabled" in output
34-
assert "autodetection will not work" in output
35-
else:
36-
assert f"Detecting chip type... {self.expected_chip_name}" in output
37-
assert (
38-
f"{'Chip type:':<20}{self.expected_chip_name} "
39-
"in Secure Download Mode" in output
40-
)
30+
assert f"Detecting chip type... {self.expected_chip_name}" in output
31+
assert (
32+
f"{'Chip type:':<20}{self.expected_chip_name} "
33+
"in Secure Download Mode" in output
34+
)
4135

4236
# Commands not supported in SDM
4337
def test_sdm_incompatible_commands(self):
@@ -65,6 +59,5 @@ def test_sdm_compatible_commands(self):
6559
assert "Stub flasher is not supported in Secure Download Mode" in output
6660
assert "Flash memory region erased successfully" in output
6761

68-
if arg_chip != "esp32": # esp32 does not support get-security-info
69-
output = self.run_esptool("get-security-info")
70-
assert "Security Information:" in output
62+
output = self.run_esptool("get-security-info")
63+
assert "Security Information:" in output

test/test_imagegen.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,68 @@ def test_hash_append(self):
539539
assert bytes(expected_bin_without_hash) == bin_without_hash
540540

541541

542+
class TestELFSectionHandling(BaseTestCase):
543+
"""Test ELF section type handling and related functionality."""
544+
545+
@staticmethod
546+
def _modify_section_type(elf_path, section_name, new_type):
547+
"""
548+
Modify the type of a specific section in the ELF file.
549+
"""
550+
with open(elf_path, "rb+") as f:
551+
elf = ELFFile(f)
552+
section = elf.get_section_by_name(section_name)
553+
554+
index = elf.get_section_index(section_name)
555+
# Calculate the section header's position in the file (using section index,
556+
# the section header table's offset and section header entry size)
557+
sh_entry_offset = elf.header["e_shoff"] + index * elf.header["e_shentsize"]
558+
559+
# Modify the section type in the header
560+
section.header.sh_type = new_type
561+
562+
f.seek(sh_entry_offset)
563+
f.write(elf.structs.Elf_Shdr.build(section.header))
564+
565+
@staticmethod
566+
def _get_section_type(elf_path, section_name):
567+
"""
568+
Get the current type of a specific section in the ELF file.
569+
"""
570+
with open(elf_path, "rb") as f:
571+
elf = ELFFile(f)
572+
section = elf.get_section_by_name(section_name)
573+
return section.header.sh_type
574+
575+
def test_unknown_section_type_warning(self, capsys):
576+
"""Test that unknown section types generate the expected warning message."""
577+
ELF = "esp32c6-appdesc.elf"
578+
BIN = "esp32c6-appdesc.bin"
579+
SECTION_NAME = ".flash.appdesc"
580+
UNKNOWN_TYPE = 0x99
581+
582+
original_sec_type = self._get_section_type(ELF, SECTION_NAME)
583+
584+
# Modify the section to have an unknown type
585+
self._modify_section_type(ELF, SECTION_NAME, UNKNOWN_TYPE)
586+
587+
# Verify the section was actually modified
588+
modified_type = self._get_section_type(ELF, SECTION_NAME)
589+
assert modified_type == UNKNOWN_TYPE
590+
591+
try:
592+
self.run_elf2image("esp32c6", ELF, allow_warnings=True)
593+
output = capsys.readouterr().out
594+
print(output)
595+
596+
expected_warning = f"Unknown section type {UNKNOWN_TYPE:#04x} in ELF file"
597+
assert expected_warning in output
598+
599+
finally:
600+
self._modify_section_type(ELF, SECTION_NAME, original_sec_type)
601+
try_delete(BIN)
602+
603+
542604
class TestMMUPageSize(BaseTestCase):
543605
def test_appdesc_aligned(self, capsys):
544606
ELF = "esp32c6-appdesc.elf"

0 commit comments

Comments
 (0)