Merge branch 'feature/check_section_references' into 'master'

ci: add script to check section references

See merge request espressif/esp-idf!9513
pull/5919/head
Ivan Grokhotkov 2020-09-04 06:19:13 +08:00
commit ab0fc70104
23 zmienionych plików z 643 dodań i 119 usunięć

Wyświetl plik

@ -86,6 +86,10 @@ elseif(CONFIG_COMPILER_STACK_CHECK_MODE_ALL)
list(APPEND compile_options "-fstack-protector-all")
endif()
if(CONFIG_COMPILER_DUMP_RTL_FILES)
list(APPEND compile_options "-fdump-rtl-expand")
endif()
list(APPEND link_options "-fno-lto")
idf_build_set_property(COMPILE_OPTIONS "${compile_options}" APPEND)

Wyświetl plik

@ -335,6 +335,12 @@ mainmenu "Espressif IoT Development Framework Configuration"
Enable this option if using GCC 6 or newer, and wanting to disable warnings which don't appear with
GCC 5.
config COMPILER_DUMP_RTL_FILES
bool "Dump RTL files during compilation"
help
If enabled, RTL files will be produced during compilation. These files
can be used by other tools, for example to calculate call graphs.
endmenu # Compiler Options

Wyświetl plik

@ -38,14 +38,15 @@ SECTIONS
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
*liblog.a:(.literal .text .literal.* .text.*)
*libgcc.a:(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_clock.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_common.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_clock_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_common_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_efuse_esp32.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
@ -53,8 +54,9 @@ SECTIONS
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
*libsoc.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
*libsoc.a:rtc_clk.*(.literal .text .literal.* .text.*)
*libsoc.a:rtc_time.*(.literal .text .literal.* .text.*)
*libefuse.a:*.*(.literal .text .literal.* .text.*)
*(.fini.literal)
*(.fini)

Wyświetl plik

@ -25,13 +25,15 @@ SECTIONS
*(.iram1 .iram1.*) /* catch stray IRAM_ATTR */
*liblog.a:(.literal .text .literal.* .text.*)
*libgcc.a:(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_common.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_clock_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_common_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_flash.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_random.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_efuse_esp32s2.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_utility.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_sha.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_console_loader.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:bootloader_panic.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:esp_image_format.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_encrypt.*(.literal .text .literal.* .text.*)
*libbootloader_support.a:flash_partitions.*(.literal .text .literal.* .text.*)
@ -39,7 +41,9 @@ SECTIONS
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
*libsoc.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
*libsoc.a:rtc_clk.*(.literal .text .literal.* .text.*)
*libsoc.a:rtc_time.*(.literal .text .literal.* .text.*)
*libefuse.a:*.*(.literal .text .literal.* .text.*)
*(.fini.literal)
*(.fini)

Wyświetl plik

@ -40,7 +40,7 @@ SECTIONS
*libbootloader_support.a:secure_boot_signatures.*(.literal .text .literal.* .text.*)
*libmicro-ecc.a:*.*(.literal .text .literal.* .text.*)
*libspi_flash.a:*.*(.literal .text .literal.* .text.*)
*libsoc.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
*libhal.a:wdt_hal_iram.*(.literal .text .literal.* .text.*)
*libsoc.a:rtc_clk.*(.literal .text .literal.* .text.*)
*libefuse.a:*.*(.literal .text .literal.* .text.*)
*(.fini.literal)

Wyświetl plik

@ -1,6 +1,7 @@
set(srcs
"src/bootloader_clock.c"
"src/bootloader_common.c"
"src/bootloader_common_loader.c"
"src/bootloader_clock_init.c"
"src/bootloader_flash.c"
"src/bootloader_mem.c"
"src/bootloader_random.c"
@ -18,8 +19,10 @@ if(BOOTLOADER_BUILD)
set(priv_requires micro-ecc spi_flash efuse)
list(APPEND srcs
"src/bootloader_init.c"
"src/bootloader_clock_loader.c"
"src/bootloader_console.c"
"src/bootloader_console_loader.c"
"src/bootloader_panic.c"
"src/${IDF_TARGET}/bootloader_sha.c"
"src/${IDF_TARGET}/flash_encrypt.c"
"src/${IDF_TARGET}/bootloader_${IDF_TARGET}.c"
@ -114,3 +117,7 @@ if(CONFIG_SECURE_SIGNED_APPS AND (CONFIG_SECURE_BOOT_V1_ENABLED OR CONFIG_SECURE
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
"${secure_boot_verification_key}")
endif()
if(BOOTLOADER_BUILD)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u abort")
endif()

Wyświetl plik

@ -16,7 +16,11 @@ COMPONENT_SRCDIRS += src/$(IDF_TARGET) # one sub-dir per chip
endif
ifndef IS_BOOTLOADER_BUILD
COMPONENT_OBJEXCLUDE := src/bootloader_init.o
COMPONENT_OBJEXCLUDE := src/bootloader_init.o \
src/bootloader_panic.o \
src/bootloader_clock_loader.o \
src/bootloader_console.o \
src/bootloader_console_loader.o
endif
COMPONENT_OBJEXCLUDE += src/bootloader_flash_config_esp32s2.o \

Wyświetl plik

@ -75,11 +75,4 @@ void bootloader_clock_configure(void)
#endif // CONFIG_ESP_SYSTEM_RTC_EXT_XTAL
}
#ifdef BOOTLOADER_BUILD
int esp_clk_apb_freq(void)
{
return rtc_clk_apb_freq_get();
}
#endif // BOOTLOADER_BUILD

Wyświetl plik

@ -0,0 +1,24 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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.h"
#ifdef BOOTLOADER_BUILD
int esp_clk_apb_freq(void)
{
return rtc_clk_apb_freq_get();
}
#endif // BOOTLOADER_BUILD

Wyświetl plik

@ -41,21 +41,6 @@
static const char* TAG = "boot_comm";
uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s)
{
return esp_rom_crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
}
bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s)
{
return s->ota_seq == UINT32_MAX || s->ota_state == ESP_OTA_IMG_INVALID || s->ota_state == ESP_OTA_IMG_ABORTED;
}
bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s)
{
return bootloader_common_ota_select_invalid(s) == false && s->crc == bootloader_common_ota_select_crc(s);
}
esp_comm_gpio_hold_t bootloader_common_check_long_hold_gpio(uint32_t num_pin, uint32_t delay_sec)
{
esp_rom_gpio_pad_select_gpio(num_pin);
@ -190,43 +175,6 @@ esp_err_t bootloader_common_get_sha256_of_partition (uint32_t address, uint32_t
return bootloader_sha256_flash_contents(address, size, out_sha_256);
}
int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata, bool *valid_two_otadata, bool max)
{
if (two_otadata == NULL || valid_two_otadata == NULL) {
return -1;
}
int active_otadata = -1;
if (valid_two_otadata[0] && valid_two_otadata[1]) {
int condition = (max == true) ? MAX(two_otadata[0].ota_seq, two_otadata[1].ota_seq) : MIN(two_otadata[0].ota_seq, two_otadata[1].ota_seq);
if (condition == two_otadata[0].ota_seq) {
active_otadata = 0;
} else {
active_otadata = 1;
}
ESP_LOGD(TAG, "Both OTA copies are valid");
} else {
for (int i = 0; i < 2; ++i) {
if (valid_two_otadata[i]) {
active_otadata = i;
ESP_LOGD(TAG, "Only otadata[%d] is valid", i);
break;
}
}
}
return active_otadata;
}
int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata)
{
if (two_otadata == NULL) {
return -1;
}
bool valid_two_otadata[2];
valid_two_otadata[0] = bootloader_common_ota_select_valid(&two_otadata[0]);
valid_two_otadata[1] = bootloader_common_ota_select_valid(&two_otadata[1]);
return bootloader_common_select_otadata(two_otadata, valid_two_otadata, true);
}
esp_err_t bootloader_common_get_partition_description(const esp_partition_pos_t *partition, esp_app_desc_t *app_desc)
{
if (partition == NULL || app_desc == NULL || partition->offset == 0) {
@ -265,26 +213,6 @@ void bootloader_common_vddsdio_configure(void)
}
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr, esp_image_type type)
{
esp_err_t err = ESP_OK;
esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID;
if (chip_id != img_hdr->chip_id) {
ESP_LOGE(TAG, "mismatch chip ID, expected %d, found %d", chip_id, img_hdr->chip_id);
err = ESP_FAIL;
}
uint8_t revision = bootloader_common_get_chip_revision();
if (revision < img_hdr->min_chip_rev) {
ESP_LOGE(TAG, "can't run on lower chip revision, expected %d, found %d", revision, img_hdr->min_chip_rev);
err = ESP_FAIL;
} else if (revision != img_hdr->min_chip_rev) {
#ifdef BOOTLOADER_BUILD
ESP_LOGI(TAG, "chip revision: %d, min. %s chip revision: %d", revision, type == ESP_IMAGE_BOOTLOADER ? "bootloader" : "application", img_hdr->min_chip_rev);
#endif
}
return err;
}
RESET_REASON bootloader_common_get_reset_reason(int cpu_no)
{
return rtc_get_reset_reason(cpu_no);

Wyświetl plik

@ -0,0 +1,99 @@
#include "string.h"
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_log.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/spi_flash.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/spi_flash.h"
#include "esp32s2/rom/ets_sys.h"
#endif
#include "esp_rom_crc.h"
#include "esp_rom_gpio.h"
#include "esp_flash_partitions.h"
#include "bootloader_flash.h"
#include "bootloader_common.h"
#include "soc/gpio_periph.h"
#include "soc/rtc.h"
#include "soc/efuse_reg.h"
#include "hal/gpio_ll.h"
#include "esp_image_format.h"
#include "bootloader_sha.h"
#include "sys/param.h"
#define ESP_PARTITION_HASH_LEN 32 /* SHA-256 digest length */
static const char* TAG = "boot_comm";
uint32_t bootloader_common_ota_select_crc(const esp_ota_select_entry_t *s)
{
return esp_rom_crc32_le(UINT32_MAX, (uint8_t*)&s->ota_seq, 4);
}
bool bootloader_common_ota_select_invalid(const esp_ota_select_entry_t *s)
{
return s->ota_seq == UINT32_MAX || s->ota_state == ESP_OTA_IMG_INVALID || s->ota_state == ESP_OTA_IMG_ABORTED;
}
bool bootloader_common_ota_select_valid(const esp_ota_select_entry_t *s)
{
return bootloader_common_ota_select_invalid(s) == false && s->crc == bootloader_common_ota_select_crc(s);
}
int bootloader_common_get_active_otadata(esp_ota_select_entry_t *two_otadata)
{
if (two_otadata == NULL) {
return -1;
}
bool valid_two_otadata[2];
valid_two_otadata[0] = bootloader_common_ota_select_valid(&two_otadata[0]);
valid_two_otadata[1] = bootloader_common_ota_select_valid(&two_otadata[1]);
return bootloader_common_select_otadata(two_otadata, valid_two_otadata, true);
}
esp_err_t bootloader_common_check_chip_validity(const esp_image_header_t* img_hdr, esp_image_type type)
{
esp_err_t err = ESP_OK;
esp_chip_id_t chip_id = CONFIG_IDF_FIRMWARE_CHIP_ID;
if (chip_id != img_hdr->chip_id) {
ESP_LOGE(TAG, "mismatch chip ID, expected %d, found %d", chip_id, img_hdr->chip_id);
err = ESP_FAIL;
}
uint8_t revision = bootloader_common_get_chip_revision();
if (revision < img_hdr->min_chip_rev) {
ESP_LOGE(TAG, "can't run on lower chip revision, expected %d, found %d", revision, img_hdr->min_chip_rev);
err = ESP_FAIL;
} else if (revision != img_hdr->min_chip_rev) {
#ifdef BOOTLOADER_BUILD
ESP_LOGI(TAG, "chip revision: %d, min. %s chip revision: %d", revision, type == ESP_IMAGE_BOOTLOADER ? "bootloader" : "application", img_hdr->min_chip_rev);
#endif
}
return err;
}
int bootloader_common_select_otadata(const esp_ota_select_entry_t *two_otadata, bool *valid_two_otadata, bool max)
{
if (two_otadata == NULL || valid_two_otadata == NULL) {
return -1;
}
int active_otadata = -1;
if (valid_two_otadata[0] && valid_two_otadata[1]) {
int condition = (max == true) ? MAX(two_otadata[0].ota_seq, two_otadata[1].ota_seq) : MIN(two_otadata[0].ota_seq, two_otadata[1].ota_seq);
if (condition == two_otadata[0].ota_seq) {
active_otadata = 0;
} else {
active_otadata = 1;
}
ESP_LOGD(TAG, "Both OTA copies are valid");
} else {
for (int i = 0; i < 2; ++i) {
if (valid_two_otadata[i]) {
active_otadata = i;
ESP_LOGD(TAG, "Only otadata[%d] is valid", i);
break;
}
}
}
return active_otadata;
}

Wyświetl plik

@ -101,10 +101,3 @@ void bootloader_print_banner(void)
ESP_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", IDF_VER);
ESP_LOGI(TAG, "compile time " __TIME__);
}
void __assert_func(const char *file, int line, const char *func, const char *expr)
{
ESP_LOGE(TAG, "Assert failed in %s, %s:%d (%s)", func, file, line, expr);
while (1) {
}
}

Wyświetl plik

@ -0,0 +1,38 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// 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 "esp_log.h"
#include "bootloader_common.h"
#include "soc/cpu.h"
#include "esp_rom_sys.h"
void __assert_func(const char *file, int line, const char *func, const char *expr)
{
esp_rom_printf("Assert failed in %s, %s:%d (%s)\r\n", func, file, line, expr);
while (1) {
}
}
void abort(void)
{
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
esp_rom_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3);
#endif
if (esp_cpu_in_ocd_debug_mode()) {
__asm__("break 0,0");
}
while (1) {
}
}

Wyświetl plik

@ -351,18 +351,6 @@ static void bootloader_check_wdt_reset(void)
wdt_reset_cpu0_info_enable();
}
void abort(void)
{
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
esp_rom_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3);
#endif
if (esp_cpu_in_ocd_debug_mode()) {
__asm__("break 0,0");
}
while (1) {
}
}
esp_err_t bootloader_init(void)
{
esp_err_t ret = ESP_OK;

Wyświetl plik

@ -46,7 +46,7 @@
#include <string.h>
static const char *TAG = "boot.esp32s2";
void bootloader_configure_spi_pins(int drv)
void IRAM_ATTR bootloader_configure_spi_pins(int drv)
{
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
uint8_t wp_pin = esp_rom_efuse_get_flash_wp_gpio();
@ -276,18 +276,6 @@ static void bootloader_check_wdt_reset(void)
wdt_reset_cpu0_info_enable();
}
void abort(void)
{
#if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
esp_rom_printf("abort() was called at PC 0x%08x\r\n", (intptr_t)__builtin_return_address(0) - 3);
#endif
if (esp_cpu_in_ocd_debug_mode()) {
__asm__("break 0,0");
}
while (1) {
}
}
static void bootloader_super_wdt_auto_feed(void)
{
REG_SET_BIT(RTC_CNTL_SWD_CONF_REG, RTC_CNTL_SWD_AUTO_FEED_EN);

Wyświetl plik

@ -0,0 +1,418 @@
#!/usr/bin/env python
#
# Based on cally.py (https://github.com/chaudron/cally/), Copyright 2018, Eelco Chaudron
# Copyright 2020 Espressif Systems (Shanghai) PTE LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
import argparse
from functools import partial
import os
import re
import elftools
from elftools.elf import elffile
try:
from typing import List, Optional, BinaryIO, Tuple, Generator, Dict, Callable
except ImportError:
pass
FUNCTION_REGEX = re.compile(
r"^;; Function (?P<mangle>.*)\s+\((?P<function>\S+)(,.*)?\).*$"
)
CALL_REGEX = re.compile(r'^.*\(call.*"(?P<target>.*)".*$')
SYMBOL_REF_REGEX = re.compile(r'^.*\(symbol_ref[^()]*\("(?P<target>.*)"\).*$')
class RtlFunction(object):
def __init__(self, name, rtl_filename, tu_filename):
self.name = name
self.rtl_filename = rtl_filename
self.tu_filename = tu_filename
self.calls = list() # type: List[str]
self.refs = list() # type: List[str]
self.sym = None
class SectionAddressRange(object):
def __init__(self, name, addr, size): # type: (str, int, int) -> None
self.name = name
self.low = addr
self.high = addr + size
def __str__(self):
return "{}: 0x{:08x} - 0x{:08x}".format(self.name, self.low, self.high)
def contains_address(self, addr):
return self.low <= addr < self.high
TARGET_SECTIONS = {
"esp32": [
SectionAddressRange(".rom.text", 0x40000000, 0x70000),
SectionAddressRange(".rom.rodata", 0x3ff96000, 0x9018)
],
"esp32s2": [
SectionAddressRange(".rom.text", 0x40000000, 0x1bed0),
SectionAddressRange(".rom.rodata", 0x3ffac600, 0x392c)
],
"esp32s3": [
SectionAddressRange(".rom.text", 0x40000000, 0x568d0),
SectionAddressRange(".rom.rodata", 0x3ff071c0, 0x8e30)
]
} # type: Dict[str, List[SectionAddressRange]]
class Symbol(object):
def __init__(self, name, addr, local, filename, section): # type: (str, int, bool, Optional[str], Optional[str]) -> None
self.name = name
self.addr = addr
self.local = local
self.filename = filename
self.section = section
self.refers_to = list() # type: List[Symbol]
self.referred_from = list() # type: List[Symbol]
def __str__(self):
return "{} @0x{:08x} [{}]{} {}".format(
self.name,
self.addr,
self.section or "unknown",
" (local)" if self.local else "",
self.filename
)
class Reference(object):
def __init__(self, from_sym, to_sym): # type: (Symbol, Symbol) -> None
self.from_sym = from_sym
self.to_sym = to_sym
def __str__(self):
return "{} @0x{:08x} ({}) -> {} @0x{:08x} ({})".format(
self.from_sym.name,
self.from_sym.addr,
self.from_sym.section,
self.to_sym.name,
self.to_sym.addr,
self.to_sym.section
)
class ElfInfo(object):
def __init__(self, elf_file): # type: (BinaryIO) -> None
self.elf_file = elf_file
self.elf_obj = elffile.ELFFile(self.elf_file)
self.section_ranges = self._load_sections()
self.symbols = self._load_symbols()
def _load_symbols(self): # type: () -> List[Symbol]
symbols = []
for s in self.elf_obj.iter_sections():
if not isinstance(s, elftools.elf.sections.SymbolTableSection):
continue
filename = None
for sym in s.iter_symbols():
sym_type = sym.entry["st_info"]["type"]
if sym_type == "STT_FILE":
filename = sym.name
if sym_type in ["STT_NOTYPE", "STT_FUNC", "STT_OBJECT"]:
local = sym.entry["st_info"]["bind"] == "STB_LOCAL"
addr = sym.entry["st_value"]
symbols.append(
Symbol(
sym.name,
addr,
local,
filename if local else None,
self.section_for_addr(addr),
)
)
return symbols
def _load_sections(self): # type: () -> List[SectionAddressRange]
result = []
for segment in self.elf_obj.iter_segments():
if segment["p_type"] == "PT_LOAD":
for section in self.elf_obj.iter_sections():
if not segment.section_in_segment(section):
continue
result.append(
SectionAddressRange(
section.name, section["sh_addr"], section["sh_size"]
)
)
target = os.environ.get("IDF_TARGET")
if target in TARGET_SECTIONS:
result += TARGET_SECTIONS[target]
return result
def symbols_by_name(self, name): # type: (str) -> List[Symbol]
res = []
for sym in self.symbols:
if sym.name == name:
res.append(sym)
return res
def section_for_addr(self, sym_addr): # type: (int) -> Optional[str]
for sar in self.section_ranges:
if sar.contains_address(sym_addr):
return sar.name
return None
def load_rtl_file(rtl_filename, tu_filename, functions): # type: (str, str, List[RtlFunction]) -> None
last_function = None # type: Optional[RtlFunction]
for line in open(rtl_filename):
# Find function definition
match = re.match(FUNCTION_REGEX, line)
if match:
function_name = match.group("function")
last_function = RtlFunction(function_name, rtl_filename, tu_filename)
functions.append(last_function)
continue
if last_function:
# Find direct function calls
match = re.match(CALL_REGEX, line)
if match:
target = match.group("target")
if target not in last_function.calls:
last_function.calls.append(target)
continue
# Find symbol references
match = re.match(SYMBOL_REF_REGEX, line)
if match:
target = match.group("target")
if target not in last_function.refs:
last_function.refs.append(target)
continue
def rtl_filename_matches_sym_filename(rtl_filename, symbol_filename): # type: (str, str) -> bool
# Symbol file names (from ELF debug info) are short source file names, without path: "cpu_start.c".
# RTL file names are paths relative to the build directory, e.g.:
# "build/esp-idf/esp_system/CMakeFiles/__idf_esp_system.dir/port/cpu_start.c.234r.expand"
#
# The check below may give a false positive if there are two files with the same name in
# different directories. This doesn't seem to happen in IDF now, but if it does happen,
# an assert in find_symbol_by_rtl_func should catch this.
#
# If this becomes and issue, consider also loading the .map file and using it to figure out
# which object file was used as the source of each symbol. Names of the object files and RTL files
# should be much easier to match.
return os.path.basename(rtl_filename).startswith(symbol_filename)
class SymbolNotFound(RuntimeError):
pass
def find_symbol_by_name(name, elfinfo, local_func_matcher): # type: (str, ElfInfo, Callable[[Symbol], bool]) -> Optional[Symbol]
"""
Find an ELF symbol for the given name.
local_func_matcher is a callback function which checks is the candidate local symbol is suitable.
"""
syms = elfinfo.symbols_by_name(name)
if not syms:
return None
if len(syms) == 1:
return syms[0]
else:
# There are multiple symbols with a given name. Find the best fit.
local_candidate = None
global_candidate = None
for sym in syms:
if not sym.local:
assert not global_candidate # can't have two global symbols with the same name
global_candidate = sym
elif local_func_matcher(sym):
assert not local_candidate # can't have two symbols with the same name in a single file
local_candidate = sym
# If two symbols with the same name are defined, a global and a local one,
# prefer the local symbol as the reference target.
return local_candidate or global_candidate
def match_local_source_func(rtl_filename, sym): # type: (str, Symbol) -> bool
"""
Helper for match_rtl_funcs_to_symbols, checks if local symbol sym is a good candidate for the
reference source (caller), based on the RTL file name.
"""
assert sym.filename # should be set for local functions
return rtl_filename_matches_sym_filename(rtl_filename, sym.filename)
def match_local_target_func(rtl_filename, sym_from, sym): # type: (str, Symbol, Symbol) -> bool
"""
Helper for match_rtl_funcs_to_symbols, checks if local symbol sym is a good candidate for the
reference target (callee or referenced data), based on RTL filename of the source symbol
and the source symbol itself.
"""
assert sym.filename # should be set for local functions
if sym_from.local:
# local symbol referencing another local symbol
return sym_from.filename == sym.filename
else:
# global symbol referencing a local symbol;
# source filename is not known, use RTL filename as a hint
return rtl_filename_matches_sym_filename(rtl_filename, sym.filename)
def match_rtl_funcs_to_symbols(rtl_functions, elfinfo): # type: (List[RtlFunction], ElfInfo) -> Tuple[List[Symbol], List[Reference]]
symbols = [] # type: List[Symbol]
refs = [] # type: List[Reference]
# General idea:
# - iterate over RTL functions.
# - for each RTL function, find the corresponding symbol
# - iterate over the functions and variables referenced from this RTL function
# - find symbols corresponding to the references
# - record every pair (sym_from, sym_to) as a Reference object
for source_rtl_func in rtl_functions:
maybe_sym_from = find_symbol_by_name(source_rtl_func.name, elfinfo, partial(match_local_source_func, source_rtl_func.rtl_filename))
if maybe_sym_from is None:
# RTL references a symbol, but the symbol is not defined in the generated object file.
# This means that the symbol was likely removed (or not included) at link time.
# There is nothing we can do to check section placement in this case.
continue
sym_from = maybe_sym_from
if sym_from not in symbols:
symbols.append(sym_from)
for target_rtl_func_name in source_rtl_func.calls + source_rtl_func.refs:
if "*.LC" in target_rtl_func_name: # skip local labels
continue
maybe_sym_to = find_symbol_by_name(target_rtl_func_name, elfinfo, partial(match_local_target_func, source_rtl_func.rtl_filename, sym_from))
if not maybe_sym_to:
# This may happen for a extern reference in the RTL file, if the reference was later removed
# by one of the optimization passes, and the external definition got garbage-collected.
# TODO: consider adding some sanity check that we are here not because of some bug in
# find_symbol_by_name?..
continue
sym_to = maybe_sym_to
sym_from.refers_to.append(sym_to)
sym_to.referred_from.append(sym_from)
refs.append(Reference(sym_from, sym_to))
if sym_to not in symbols:
symbols.append(sym_to)
return symbols, refs
def get_symbols_and_refs(rtl_list, elf_file): # type: (List[str], BinaryIO) -> Tuple[List[Symbol], List[Reference]]
elfinfo = ElfInfo(elf_file)
rtl_functions = [] # type: List[RtlFunction]
for file_name in rtl_list:
load_rtl_file(file_name, file_name, rtl_functions)
return match_rtl_funcs_to_symbols(rtl_functions, elfinfo)
def list_refs_from_to_sections(refs, from_sections, to_sections): # type: (List[Reference], List[str], List[str]) -> int
found = 0
for ref in refs:
if (not from_sections or ref.from_sym.section in from_sections) and \
(not to_sections or ref.to_sym.section in to_sections):
print(str(ref))
found += 1
return found
def find_files_recursive(root_path, ext): # type: (str, str) -> Generator[str, None, None]
for root, _, files in os.walk(root_path):
for basename in files:
if basename.endswith(ext):
filename = os.path.join(root, basename)
yield filename
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--rtl-list",
help="File with the list of RTL files",
type=argparse.FileType("r"),
)
parser.add_argument(
"--rtl-dir", help="Directory where to look for RTL files, recursively"
)
parser.add_argument(
"--elf-file",
required=True,
help="Program ELF file",
type=argparse.FileType("rb"),
)
action_sub = parser.add_subparsers(dest="action")
find_refs_parser = action_sub.add_parser(
"find-refs",
help="List the references coming from a given list of source sections"
"to a given list of target sections.",
)
find_refs_parser.add_argument(
"--from-sections", help="comma-separated list of source sections"
)
find_refs_parser.add_argument(
"--to-sections", help="comma-separated list of target sections"
)
find_refs_parser.add_argument(
"--exit-code",
action="store_true",
help="If set, exits with non-zero code when any references found",
)
action_sub.add_parser(
"all-refs",
help="Print the list of all references",
)
parser.parse_args()
args = parser.parse_args()
if args.rtl_list:
with open(args.rtl_list, "r") as rtl_list_file:
rtl_list = [line.strip for line in rtl_list_file]
else:
if not args.rtl_dir:
raise RuntimeError("Either --rtl-list or --rtl-dir must be specified")
rtl_list = list(find_files_recursive(args.rtl_dir, ".expand"))
if not rtl_list:
raise RuntimeError("No RTL files specified")
_, refs = get_symbols_and_refs(rtl_list, args.elf_file)
if args.action == "find-refs":
from_sections = args.from_sections.split(",") if args.from_sections else []
to_sections = args.to_sections.split(",") if args.to_sections else []
found = list_refs_from_to_sections(
refs, from_sections, to_sections
)
if args.exit_code and found:
raise SystemExit(1)
elif args.action == "all-refs":
for r in refs:
print(str(r))
if __name__ == "__main__":
main()

Wyświetl plik

@ -39,6 +39,7 @@ tools/ci/build_template_app.sh
tools/ci/check-executable.sh
tools/ci/check-line-endings.sh
tools/ci/check_build_warnings.py
tools/ci/check_callgraph.py
tools/ci/check_deprecated_kconfigs.py
tools/ci/check_examples_cmake_make.py
tools/ci/check_examples_rom_header.sh

Wyświetl plik

@ -0,0 +1,17 @@
# 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.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_build)
add_custom_target(check_bootloader_sections ALL
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
--rtl-dir ${CMAKE_BINARY_DIR}/bootloader
--elf-file ${CMAKE_BINARY_DIR}/bootloader/bootloader.elf
find-refs
--from-sections=.iram_loader.text
--to-sections=.iram.text
--exit-code
DEPENDS bootloader
)

Wyświetl plik

@ -0,0 +1,4 @@
idf_component_register(SRCS "test_main.c"
INCLUDE_DIRS ".")

Wyświetl plik

@ -0,0 +1,3 @@
void app_main(void)
{
}

Wyświetl plik

@ -0,0 +1,2 @@
CONFIG_SECURE_FLASH_ENC_ENABLED=y
CONFIG_SECURE_FLASH_ENCRYPTION_MODE_RELEASE=y

Wyświetl plik

@ -0,0 +1 @@
CONFIG_COMPILER_DUMP_RTL_FILES=y