30
30
#include "memfault/esp_port/uart.h"
31
31
#include "memfault/util/crc16_ccitt.h"
32
32
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
+
33
38
// Factor out issues with Espressif's ESP32 to ESP conversion in sdkconfig
34
39
#define COREDUMPS_ENABLED \
35
40
(CONFIG_ESP32_ENABLE_COREDUMP || CONFIG_ESP_COREDUMP_ENABLE)
53
58
esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_COREDUMP, NULL)
54
59
#endif
55
60
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
+
56
72
typedef struct {
57
73
uint32_t magic ;
58
74
esp_partition_t partition ;
59
75
uint32_t crc ;
60
76
} sEspIdfCoredumpPartitionInfo ;
61
77
62
78
static 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 ;
63
81
64
82
static uint32_t prv_get_partition_info_crc (void ) {
65
83
return memfault_crc16_ccitt_compute (MEMFAULT_CRC16_CCITT_INITIAL_VALUE ,
@@ -75,42 +93,121 @@ static const esp_partition_t *prv_get_core_partition(void) {
75
93
return & s_esp32_coredump_partition_info .partition ;
76
94
}
77
95
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.
79
167
//!
80
168
//! @note The function is intentionally defined as weak so someone can
81
169
//! easily override the port defaults by re-defining a non-weak version of
82
170
//! the function in another file
83
171
MEMFAULT_WEAK
84
172
const 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.
97
195
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 ;
102
200
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 ;
110
210
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 );
114
211
return & s_coredump_regions [0 ];
115
212
}
116
213
0 commit comments