3030#include "memfault/esp_port/uart.h"
3131#include "memfault/util/crc16_ccitt.h"
3232
33+ // Needed for >= v4.4.0 default coredump collection
34+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (4 , 4 , 0 )
35+ #include "memfault/ports/freertos_coredump.h"
36+ #endif
37+
3338// Factor out issues with Espressif's ESP32 to ESP conversion in sdkconfig
3439#define COREDUMPS_ENABLED \
3540 (CONFIG_ESP32_ENABLE_COREDUMP || CONFIG_ESP_COREDUMP_ENABLE)
5358 esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_COREDUMP, NULL)
5459#endif
5560
61+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (4 , 4 , 0 )
62+ // Memory regions used for esp-idf >= 4.4.0
63+ // Active stack (1) + task/timer and bss/common regions (4) +
64+ // freertos tasks (MEMFAULT_PLATFORM_MAX_TASK_REGIONS) + bss(1) + data(1) + heap(1)
65+ #define MEMFAULT_ESP_PORT_NUM_REGIONS (1 + 4 + MEMFAULT_PLATFORM_MAX_TASK_REGIONS + 1 + 1 + 1)
66+ #else // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
67+ // Memory regions for esp-idf < 4.4.0
68+ // Active stack (1) + bss(1) + data(1) + heap(1)
69+ #define MEMFAULT_ESP_PORT_NUM_REGIONS (1 + 1 + 1 + 1)
70+ #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
71+
5672typedef struct {
5773 uint32_t magic ;
5874 esp_partition_t partition ;
5975 uint32_t crc ;
6076} sEspIdfCoredumpPartitionInfo ;
6177
6278static sEspIdfCoredumpPartitionInfo s_esp32_coredump_partition_info ;
79+ static const uintptr_t esp32_dram_start_addr = SOC_DRAM_LOW ;
80+ static const uintptr_t esp32_dram_end_addr = SOC_DRAM_HIGH ;
6381
6482static uint32_t prv_get_partition_info_crc (void ) {
6583 return memfault_crc16_ccitt_compute (MEMFAULT_CRC16_CCITT_INITIAL_VALUE ,
@@ -75,42 +93,121 @@ static const esp_partition_t *prv_get_core_partition(void) {
7593 return & s_esp32_coredump_partition_info .partition ;
7694}
7795
78- //! By default, we attempt to collect all of internal RAM as part of a Coredump
96+ // We use two different default coredump collection methods
97+ // due to differences in esp-idf versions. The following helper
98+ // is only used for esp-idf >= 4.4.0
99+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (4 , 4 , 0 )
100+ //! Helper function to get bss and common sections of task and timer objects
101+ size_t prv_get_freertos_bss_common (sMfltCoredumpRegion * regions , size_t num_regions ) {
102+ if (regions == NULL || num_regions == 0 ) {
103+ return 0 ;
104+ }
105+
106+ size_t region_index = 0 ;
107+ extern uint32_t _memfault_timers_bss_start ;
108+ extern uint32_t _memfault_timers_bss_end ;
109+ extern uint32_t _memfault_timers_common_start ;
110+ extern uint32_t _memfault_timers_common_end ;
111+ extern uint32_t _memfault_tasks_bss_start ;
112+ extern uint32_t _memfault_tasks_bss_end ;
113+ extern uint32_t _memfault_tasks_common_start ;
114+ extern uint32_t _memfault_tasks_common_end ;
115+
116+ // ldgen has a bug that does not exclude rules matching multiple input sections at the
117+ // same time. To work around this, we instead emit a symbol for each section we're attempting
118+ // to collect. This means 8 symbols (tasks/timers + bss/common). If this is ever fixed we
119+ // can remove the need to collect 4 separate regions.
120+ size_t timers_bss_length =
121+ (uintptr_t )& _memfault_timers_bss_end - (uintptr_t )& _memfault_timers_bss_start ;
122+ size_t timers_common_length =
123+ (uintptr_t )& _memfault_timers_common_end - (uintptr_t )& _memfault_timers_common_start ;
124+ size_t tasks_bss_length =
125+ (uintptr_t )& _memfault_tasks_bss_end - (uintptr_t )& _memfault_tasks_bss_start ;
126+ size_t tasks_common_length =
127+ (uintptr_t )& _memfault_tasks_common_end - (uintptr_t )& _memfault_tasks_common_start ;
128+
129+ regions [region_index ++ ] =
130+ MEMFAULT_COREDUMP_MEMORY_REGION_INIT (& _memfault_timers_bss_start , timers_bss_length );
131+ regions [region_index ++ ] =
132+ MEMFAULT_COREDUMP_MEMORY_REGION_INIT (& _memfault_timers_common_start , timers_common_length );
133+ regions [region_index ++ ] =
134+ MEMFAULT_COREDUMP_MEMORY_REGION_INIT (& _memfault_tasks_bss_start , tasks_bss_length );
135+ regions [region_index ++ ] =
136+ MEMFAULT_COREDUMP_MEMORY_REGION_INIT (& _memfault_tasks_common_start , tasks_common_length );
137+
138+ return region_index ;
139+ }
140+ #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
141+
142+ //! Simple implementation to ensure address is in SRAM range.
143+ //!
144+ //! @note The function is intentionally defined as weak so someone can
145+ //! easily override the port defaults by re-defining a non-weak version of
146+ //! the function in another file
147+ MEMFAULT_WEAK size_t memfault_platform_sanitize_address_range (void * start_addr ,
148+ size_t desired_size ) {
149+ const uintptr_t start_addr_int = (uintptr_t )start_addr ;
150+ const uintptr_t end_addr_int = start_addr_int + desired_size ;
151+
152+ if ((start_addr_int < esp32_dram_start_addr ) || (start_addr_int > esp32_dram_end_addr )) {
153+ return 0 ;
154+ }
155+
156+ if (end_addr_int > esp32_dram_end_addr ) {
157+ return esp32_dram_end_addr - start_addr_int ;
158+ }
159+
160+ return desired_size ;
161+ }
162+
163+ //! By default we prioritize collecting active stack, bss, data, and heap.
164+ //!
165+ //! In esp-idf >= 4.4.0, we additionally collect bss and stack regions for
166+ //! FreeRTOS tasks.
79167//!
80168//! @note The function is intentionally defined as weak so someone can
81169//! easily override the port defaults by re-defining a non-weak version of
82170//! the function in another file
83171MEMFAULT_WEAK
84172const sMfltCoredumpRegion * memfault_platform_coredump_get_regions (
85- const sCoredumpCrashInfo * crash_info , size_t * num_regions ) {
86- static sMfltCoredumpRegion s_coredump_regions [1 ];
87-
88- // The ESP32S2 + S3 have a different memory map than the ESP32; IRAM and DRAM
89- // share the same pysical SRAM, but are mapped at different addresses. We need
90- // to account for the placement of IRAM data, which offsets the start of
91- // placed DRAM.
92- //
93- // https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf#subsubsection.3.3.2
94- // https://www.espressif.com/sites/default/files/documentation/esp32-s3_technical_reference_manual_en.pdf#subsubsection.4.3.2
95- #if defined(CONFIG_IDF_TARGET_ESP32S3 ) || defined(CONFIG_IDF_TARGET_ESP32S2 )
96- // use this symbol defined by the linker to find the start of DRAM
173+ const sCoredumpCrashInfo * crash_info , size_t * num_regions ) {
174+ static sMfltCoredumpRegion s_coredump_regions [MEMFAULT_ESP_PORT_NUM_REGIONS ];
175+ int region_idx = 0 ;
176+
177+ const size_t stack_size = memfault_platform_sanitize_address_range (
178+ crash_info -> stack_address , MEMFAULT_PLATFORM_ACTIVE_STACK_SIZE_TO_COLLECT );
179+
180+ // First, capture the active stack
181+ s_coredump_regions [region_idx ++ ] =
182+ MEMFAULT_COREDUMP_MEMORY_REGION_INIT (crash_info -> stack_address , stack_size );
183+
184+ // Second, capture the task regions, if esp-idf >= 4.4.0
185+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (4 , 4 , 0 )
186+ region_idx += memfault_freertos_get_task_regions (
187+ & s_coredump_regions [region_idx ], MEMFAULT_ARRAY_SIZE (s_coredump_regions ) - region_idx );
188+
189+ // Third, capture the FreeRTOS-specific bss regions
190+ region_idx += prv_get_freertos_bss_common (& s_coredump_regions [region_idx ],
191+ MEMFAULT_ARRAY_SIZE (s_coredump_regions ) - region_idx );
192+ #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
193+
194+ // Next, capture all of .bss + .data that we can fit.
97195 extern uint32_t _data_start ;
98- const uint32_t esp32_dram_start_addr = ( uint32_t ) & _data_start ;
99- #else
100- const uint32_t esp32_dram_start_addr = SOC_DMA_LOW ;
101- #endif
196+ extern uint32_t _data_end ;
197+ extern uint32_t _bss_start ;
198+ extern uint32_t _bss_end ;
199+ extern uint32_t _heap_start ;
102200
103- size_t dram_collection_len = SOC_DMA_HIGH - esp32_dram_start_addr ;
104- const esp_partition_t * core_part = prv_get_core_partition ();
105- if (core_part != NULL ) {
106- // NB: Leave some space in storage for other regions collected by the SDK
107- dram_collection_len = MEMFAULT_MIN ((core_part -> size * 7 ) / 8 ,
108- dram_collection_len );
109- }
201+ s_coredump_regions [region_idx ++ ] = MEMFAULT_COREDUMP_MEMORY_REGION_INIT (
202+ & _bss_start , (uint32_t )((uintptr_t )& _bss_end - (uintptr_t )& _bss_start ));
203+ s_coredump_regions [region_idx ++ ] = MEMFAULT_COREDUMP_MEMORY_REGION_INIT (
204+ & _data_start , (uint32_t )((uintptr_t )& _data_end - (uintptr_t )& _data_start ));
205+ // Finally, capture as much of the heap as we can fit
206+ s_coredump_regions [region_idx ++ ] = MEMFAULT_COREDUMP_MEMORY_REGION_INIT (
207+ & _heap_start , (uint32_t )(esp32_dram_end_addr - (uintptr_t )& _heap_start ));
208+
209+ * num_regions = region_idx ;
110210
111- s_coredump_regions [0 ] = MEMFAULT_COREDUMP_MEMORY_REGION_INIT (
112- (void * )esp32_dram_start_addr , dram_collection_len );
113- * num_regions = MEMFAULT_ARRAY_SIZE (s_coredump_regions );
114211 return & s_coredump_regions [0 ];
115212}
116213
0 commit comments