mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/ldgen_ignore_nonexistent_archives_and_obj_v4.2' into 'release/v4.2'
ldgen: Check mappings (v4.2) See merge request espressif/esp-idf!13994
This commit is contained in:
commit
0b45e84e2a
@ -3,10 +3,11 @@ archive: libapp_trace.a
|
||||
entries:
|
||||
app_trace (noflash)
|
||||
app_trace_util (noflash)
|
||||
SEGGER_SYSVIEW (noflash)
|
||||
SEGGER_RTT_esp32 (noflash)
|
||||
SEGGER_SYSVIEW_Config_FreeRTOS (noflash)
|
||||
SEGGER_SYSVIEW_FreeRTOS (noflash)
|
||||
if SYSVIEW_ENABLE = y:
|
||||
SEGGER_SYSVIEW (noflash)
|
||||
SEGGER_RTT_esp32 (noflash)
|
||||
SEGGER_SYSVIEW_Config_FreeRTOS (noflash)
|
||||
SEGGER_SYSVIEW_FreeRTOS (noflash)
|
||||
|
||||
[mapping:driver]
|
||||
archive: libdriver.a
|
||||
|
@ -3,4 +3,4 @@ archive: libesp_system.a
|
||||
entries:
|
||||
panic (noflash)
|
||||
panic_handler (noflash)
|
||||
system_api:esp_system_abort (noflash)
|
||||
system_api:esp_system_abort (noflash)
|
||||
|
@ -19,13 +19,11 @@ entries:
|
||||
else:
|
||||
* (default)
|
||||
|
||||
[mapping:mbedtls]
|
||||
archive: libmbedtls.a
|
||||
[mapping:sha256_coredump]
|
||||
archive: libmbedcrypto.a
|
||||
entries:
|
||||
if ESP32_COREDUMP_CHECKSUM_SHA256 = y :
|
||||
if MBEDTLS_HARDWARE_SHA = n:
|
||||
sha256 (noflash_text)
|
||||
else:
|
||||
esp_sha256 (noflash_text)
|
||||
else:
|
||||
* (default)
|
||||
|
@ -2,5 +2,6 @@
|
||||
archive: libfreertos.a
|
||||
entries:
|
||||
* (noflash_text)
|
||||
queue:xQueueGenericCreateStatic (default)
|
||||
if FREERTOS_SUPPORT_STATIC_ALLOCATION = y:
|
||||
queue:xQueueGenericCreateStatic (default)
|
||||
|
||||
|
@ -2,4 +2,6 @@
|
||||
archive: libheap.a
|
||||
entries:
|
||||
multi_heap (noflash)
|
||||
multi_heap_poisoning (noflash)
|
||||
if HEAP_POISONING_DISABLED = n:
|
||||
multi_heap_poisoning (noflash)
|
||||
|
||||
|
@ -62,7 +62,6 @@ entries:
|
||||
pbuf:pbuf_header_impl (noflash_text)
|
||||
pbuf:pbuf_header (noflash_text)
|
||||
pbuf:pbuf_free (noflash_text)
|
||||
timeouts:sys_timeouts_mbox_fetch (noflash_text)
|
||||
udp:udp_input_local_match (noflash_text)
|
||||
udp:udp_input (noflash_text)
|
||||
udp:udp_send (noflash_text)
|
||||
|
@ -7,7 +7,6 @@ entries:
|
||||
rtc_clk (noflash)
|
||||
rtc_clk_init (noflash_text)
|
||||
rtc_init (noflash_text)
|
||||
rtc_periph (noflash_text)
|
||||
rtc_pm (noflash_text)
|
||||
rtc_sleep (noflash_text)
|
||||
rtc_time (noflash_text)
|
||||
@ -21,13 +20,14 @@ entries:
|
||||
spi_flash_hal_iram (noflash)
|
||||
ledc_hal_iram (noflash)
|
||||
i2c_hal_iram (noflash)
|
||||
spi_flash_hal_gpspi (noflash)
|
||||
lldesc (noflash)
|
||||
cpu_hal (noflash)
|
||||
soc_hal (noflash)
|
||||
wdt_hal_iram (noflash)
|
||||
systimer_hal (noflash)
|
||||
if TWAI_ISR_IN_IRAM = y:
|
||||
twai_hal_iram (noflash)
|
||||
else:
|
||||
twai_hal_iram (default)
|
||||
if IDF_TARGET_ESP32 = n:
|
||||
spi_flash_hal_gpspi (noflash)
|
||||
systimer_hal (noflash)
|
||||
|
@ -11,5 +11,3 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "soc/rtc_periph.h"
|
||||
|
@ -1,7 +1,8 @@
|
||||
[mapping:spi_flash]
|
||||
archive: libspi_flash.a
|
||||
entries:
|
||||
spi_flash_rom_patch (noflash)
|
||||
if IDF_TARGET_ESP32 = y:
|
||||
spi_flash_rom_patch (noflash)
|
||||
spi_flash_chip_generic (noflash)
|
||||
spi_flash_chip_issi (noflash)
|
||||
spi_flash_chip_mxic (noflash)
|
||||
|
@ -2,7 +2,8 @@
|
||||
archive: libxtensa.a
|
||||
entries:
|
||||
eri (noflash_text)
|
||||
stdatomic (noflash)
|
||||
if IDF_TARGET_ESP32S2 = y:
|
||||
stdatomic (noflash)
|
||||
|
||||
[mapping:hal]
|
||||
archive: libhal.a
|
||||
|
3
tools/ci/check_ldgen_mapping_exceptions.txt
Normal file
3
tools/ci/check_ldgen_mapping_exceptions.txt
Normal file
@ -0,0 +1,3 @@
|
||||
libc
|
||||
sha256_coredump
|
||||
gcc
|
@ -59,6 +59,7 @@ build_ssc_esp32s2:
|
||||
variables:
|
||||
LOG_PATH: "$CI_PROJECT_DIR/log_ut_cmake"
|
||||
PYTHON_VER: 3
|
||||
LDGEN_CHECK_MAPPING: 1
|
||||
script:
|
||||
- export EXTRA_CFLAGS=${PEDANTIC_CFLAGS}
|
||||
- export EXTRA_CXXFLAGS=${PEDANTIC_CXXFLAGS}
|
||||
@ -81,6 +82,7 @@ build_esp_idf_tests_cmake_esp32s2:
|
||||
extends: .build_template
|
||||
variables:
|
||||
PYTHON_VER: 3
|
||||
LDGEN_CHECK_MAPPING: 1
|
||||
parallel: 10
|
||||
artifacts:
|
||||
when: always
|
||||
|
@ -56,6 +56,12 @@ function(__ldgen_process_template template output)
|
||||
|
||||
idf_build_get_property(config_env_path CONFIG_ENV_PATH)
|
||||
|
||||
if($ENV{LDGEN_CHECK_MAPPING})
|
||||
set(ldgen_check "--check-mapping"
|
||||
"--check-mapping-exceptions=${idf_path}/tools/ci/check_ldgen_mapping_exceptions.txt")
|
||||
message(STATUS "Mapping check enabled in ldgen")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output}
|
||||
COMMAND ${python} ${idf_path}/tools/ldgen/ldgen.py
|
||||
@ -67,6 +73,7 @@ function(__ldgen_process_template template output)
|
||||
--env-file "${config_env_path}"
|
||||
--libraries-file ${build_dir}/ldgen_libraries
|
||||
--objdump ${CMAKE_OBJDUMP}
|
||||
${ldgen_check}
|
||||
DEPENDS ${template} ${ldgen_fragment_files} ${ldgen_depends} ${SDKCONFIG}
|
||||
)
|
||||
|
||||
|
@ -21,7 +21,7 @@ import fnmatch
|
||||
|
||||
from fragments import Sections, Scheme, Mapping, Fragment
|
||||
from pyparsing import Suppress, White, ParseException, Literal, Group, ZeroOrMore
|
||||
from pyparsing import Word, OneOrMore, nums, alphanums, alphas, Optional, restOfLine
|
||||
from pyparsing import Word, OneOrMore, nums, alphas, restOfLine, SkipTo
|
||||
from ldgen_common import LdGenFailure
|
||||
|
||||
|
||||
@ -80,7 +80,6 @@ class PlacementRule():
|
||||
def do_section_expansion(rule, section):
|
||||
if section in rule.get_section_names():
|
||||
sections_in_obj = sections_infos.get_obj_sections(rule.archive, rule.obj)
|
||||
|
||||
expansions = fnmatch.filter(sections_in_obj, section)
|
||||
return expansions
|
||||
|
||||
@ -254,11 +253,18 @@ class GenerationModel:
|
||||
|
||||
DEFAULT_SCHEME = "default"
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, check_mappings=False, check_mapping_exceptions=None):
|
||||
self.schemes = {}
|
||||
self.sections = {}
|
||||
self.mappings = {}
|
||||
|
||||
self.check_mappings = check_mappings
|
||||
|
||||
if check_mapping_exceptions:
|
||||
self.check_mapping_exceptions = check_mapping_exceptions
|
||||
else:
|
||||
self.check_mapping_exceptions = []
|
||||
|
||||
def _add_mapping_rules(self, archive, obj, symbol, scheme_name, scheme_dict, rules):
|
||||
# Use an ordinary dictionary to raise exception on non-existing keys
|
||||
temp_dict = dict(scheme_dict)
|
||||
@ -338,6 +344,19 @@ class GenerationModel:
|
||||
try:
|
||||
if not (obj == Mapping.MAPPING_ALL_OBJECTS and symbol is None and
|
||||
scheme_name == GenerationModel.DEFAULT_SCHEME):
|
||||
if self.check_mappings and mapping.name not in self.check_mapping_exceptions:
|
||||
if not obj == Mapping.MAPPING_ALL_OBJECTS:
|
||||
obj_sections = sections_infos.get_obj_sections(archive, obj)
|
||||
if not obj_sections:
|
||||
message = "'%s:%s' not found" % (archive, obj)
|
||||
raise GenerationException(message, mapping)
|
||||
|
||||
if symbol:
|
||||
obj_sym = fnmatch.filter(obj_sections, "*%s" % symbol)
|
||||
if not obj_sym:
|
||||
message = "'%s:%s %s' not found" % (archive, obj, symbol)
|
||||
raise GenerationException(message, mapping)
|
||||
|
||||
self._add_mapping_rules(archive, obj, symbol, scheme_name, scheme_dictionary, mapping_rules)
|
||||
except KeyError:
|
||||
message = GenerationException.UNDEFINED_REFERENCE + " to scheme '" + scheme_name + "'."
|
||||
@ -589,7 +608,7 @@ class SectionsInfo(dict):
|
||||
results = None
|
||||
|
||||
try:
|
||||
results = parser.parseString(first_line)
|
||||
results = parser.parseString(first_line, parseAll=True)
|
||||
except ParseException as p:
|
||||
raise ParseException("Parsing sections info for library " + sections_info_dump.name + " failed. " + p.message)
|
||||
|
||||
@ -597,43 +616,57 @@ class SectionsInfo(dict):
|
||||
self.sections[archive] = SectionsInfo.__info(sections_info_dump.name, sections_info_dump.read())
|
||||
|
||||
def _get_infos_from_file(self, info):
|
||||
# Object file line: '{object}: file format elf32-xtensa-le'
|
||||
object = Fragment.ENTITY.setResultsName("object") + Literal(":").suppress() + Literal("file format elf32-xtensa-le").suppress()
|
||||
# {object}: file format elf32-xtensa-le
|
||||
object_line = SkipTo(":").setResultsName("object") + Suppress(restOfLine)
|
||||
|
||||
# Sections table
|
||||
header = Suppress(Literal("Sections:") + Literal("Idx") + Literal("Name") + Literal("Size") + Literal("VMA") +
|
||||
Literal("LMA") + Literal("File off") + Literal("Algn"))
|
||||
entry = Word(nums).suppress() + Fragment.ENTITY + Suppress(OneOrMore(Word(alphanums, exact=8)) +
|
||||
Word(nums + "*") + ZeroOrMore(Word(alphas.upper()) +
|
||||
Optional(Literal(","))))
|
||||
# Sections:
|
||||
# Idx Name ...
|
||||
section_start = Suppress(Literal("Sections:"))
|
||||
section_header = Suppress(OneOrMore(Word(alphas)))
|
||||
|
||||
# Content is object file line + sections table
|
||||
content = Group(object + header + Group(ZeroOrMore(entry)).setResultsName("sections"))
|
||||
# 00 {section} 0000000 ...
|
||||
# CONTENTS, ALLOC, ....
|
||||
section_entry = Suppress(Word(nums)) + SkipTo(' ') + Suppress(restOfLine) + \
|
||||
Suppress(ZeroOrMore(Word(alphas) + Literal(",")) + Word(alphas))
|
||||
|
||||
content = Group(object_line + section_start + section_header + Group(OneOrMore(section_entry)).setResultsName("sections"))
|
||||
parser = Group(ZeroOrMore(content)).setResultsName("contents")
|
||||
|
||||
sections_info_text = info.content
|
||||
results = None
|
||||
|
||||
try:
|
||||
results = parser.parseString(sections_info_text)
|
||||
results = parser.parseString(info.content, parseAll=True)
|
||||
except ParseException as p:
|
||||
raise ParseException("Unable to parse section info file " + info.filename + ". " + p.message)
|
||||
|
||||
return results
|
||||
|
||||
def get_obj_sections(self, archive, obj):
|
||||
stored = self.sections[archive]
|
||||
res = []
|
||||
try:
|
||||
stored = self.sections[archive]
|
||||
|
||||
# Parse the contents of the sections file
|
||||
if not isinstance(stored, dict):
|
||||
parsed = self._get_infos_from_file(stored)
|
||||
stored = dict()
|
||||
for content in parsed.contents:
|
||||
sections = list(map(lambda s: s, content.sections))
|
||||
stored[content.object] = sections
|
||||
self.sections[archive] = stored
|
||||
# Parse the contents of the sections file on-demand,
|
||||
# save the result for later
|
||||
if not isinstance(stored, dict):
|
||||
parsed = self._get_infos_from_file(stored)
|
||||
stored = dict()
|
||||
for content in parsed.contents:
|
||||
sections = list(map(lambda s: s, content.sections))
|
||||
stored[content.object] = sections
|
||||
self.sections[archive] = stored
|
||||
|
||||
for obj_key in stored.keys():
|
||||
if obj_key == obj + ".o" or obj_key == obj + ".c.obj":
|
||||
return stored[obj_key]
|
||||
try:
|
||||
res = stored[obj + ".o"]
|
||||
except KeyError:
|
||||
try:
|
||||
res = stored[obj + ".c.obj"]
|
||||
except KeyError:
|
||||
try:
|
||||
res = stored[obj + ".cpp.obj"]
|
||||
except KeyError:
|
||||
res = stored[obj + ".S.obj"]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return res
|
||||
|
@ -83,6 +83,18 @@ def main():
|
||||
"--kconfig", "-k",
|
||||
help="IDF Kconfig file")
|
||||
|
||||
argparser.add_argument(
|
||||
"--check-mapping",
|
||||
help="Perform a check if a mapping (archive, obj, symbol) exists",
|
||||
action='store_true'
|
||||
)
|
||||
|
||||
argparser.add_argument(
|
||||
"--check-mapping-exceptions",
|
||||
help="Mappings exempted from check",
|
||||
type=argparse.FileType("r")
|
||||
)
|
||||
|
||||
argparser.add_argument(
|
||||
"--env", "-e",
|
||||
action='append', default=[],
|
||||
@ -106,6 +118,12 @@ def main():
|
||||
kconfig_file = args.kconfig
|
||||
objdump = args.objdump
|
||||
|
||||
check_mapping = args.check_mapping
|
||||
if args.check_mapping_exceptions:
|
||||
check_mapping_exceptions = [line.strip() for line in args.check_mapping_exceptions]
|
||||
else:
|
||||
check_mapping_exceptions = None
|
||||
|
||||
try:
|
||||
sections_infos = SectionsInfo()
|
||||
for library in libraries_file:
|
||||
@ -115,7 +133,7 @@ def main():
|
||||
dump.name = library
|
||||
sections_infos.add_sections_info(dump)
|
||||
|
||||
generation_model = GenerationModel()
|
||||
generation_model = GenerationModel(check_mapping, check_mapping_exceptions)
|
||||
|
||||
_update_environment(args) # assign args.env and args.env_file to os.environ
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
In archive /home/user/ãóç+ěščřžýáíé/build/esp-idf/freertos/libfreertos.a:
|
||||
In archive /home/user/build/esp-idf/freertos/libfreertos.a:
|
||||
|
||||
FreeRTOS-openocd.c.obj: file format elf32-xtensa-le
|
||||
|
||||
|
19
tools/ldgen/test/data/sections_parse.info
Normal file
19
tools/ldgen/test/data/sections_parse.info
Normal file
@ -0,0 +1,19 @@
|
||||
In archive /home/user/ãóç+ěščřžýáíé/build/esp-idf/freertos/libsections_parse.a:
|
||||
|
||||
croutine.c.obj: file format elf32-littleriscv
|
||||
|
||||
Sections:
|
||||
Idx Name Size VMA LMA File off Algn
|
||||
0 .text 00000000 00000000 00000000 00000034 2**0
|
||||
CONTENTS, ALLOC, LOAD, READONLY, CODE
|
||||
1 .data 00000000 00000000 00000000 00000034 2**0
|
||||
CONTENTS, ALLOC, LOAD, DATA
|
||||
2 .bss 00000000 00000000 00000000 00000034 2**0
|
||||
ALLOC
|
||||
|
||||
FreeRTOS-openocd.c.obj: file format elf32-xtensa-le // 'F' should not get included in match for 'CONTENTS, ALLOC, LOAD ...' prior
|
||||
|
||||
Sections:
|
||||
Idx Name Size VMA LMA File off Algn
|
||||
0 .literal.prvCheckPendingReadyList 00000018 00000000 00000000 00000034 2**2
|
||||
CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
|
@ -1422,6 +1422,19 @@ entries:
|
||||
self.assertListEqual(actual["flash_text"], expected["flash_text"])
|
||||
self.assertListEqual(actual["iram0_text"], expected["iram0_text"])
|
||||
|
||||
def test_sections_info_parsing(self):
|
||||
|
||||
self.sections_info = SectionsInfo()
|
||||
|
||||
with open("data/sections_parse.info") as sections_info_file_obj:
|
||||
self.sections_info.add_sections_info(sections_info_file_obj)
|
||||
|
||||
sections = self.sections_info.get_obj_sections("libsections_parse.a", "croutine")
|
||||
self.assertEqual(set(sections), set([".text", ".data", ".bss"]))
|
||||
|
||||
sections = self.sections_info.get_obj_sections("libsections_parse.a", "FreeRTOS-openocd")
|
||||
self.assertEqual(set(sections), set([".literal.prvCheckPendingReadyList"]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user